/// <summary> /// Visits a payload element whose root is an ServiceOperationDescriptor. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(ServiceOperationDescriptor payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); var serviceOperationPayloadDescriptor = payloadElement as ServiceOperationDescriptor; ExceptionUtilities.CheckArgumentNotNull(serviceOperationPayloadDescriptor, "serviceOperationPayloadDescriptor"); ExceptionUtilities.CheckObjectNotNull(serviceOperationPayloadDescriptor.Metadata, "serviceOperationPayloadDescriptor.Metadata cannot be null"); this.writer.StartObjectScope(); if (serviceOperationPayloadDescriptor.Title != null) { this.writer.WriteName("title"); this.writer.WriteString(serviceOperationPayloadDescriptor.Title); } if (serviceOperationPayloadDescriptor.Target != null) { this.writer.WriteName("target"); this.writer.WriteString(serviceOperationPayloadDescriptor.Target); } this.writer.EndScope(); }
/// <summary> /// Visits a payload element whose root is a ActionDescriptor. /// </summary> /// <param name="expected">The root node of payload element being visited.</param> public void Visit(ServiceOperationDescriptor expected) { ExceptionUtilities.CheckArgumentNotNull(expected, "expected"); var observed = this.GetNextObservedElement <ServiceOperationDescriptor>(); this.Assert.AreEqual(expected.Metadata, observed.Metadata, "Metadata did not match expectation"); this.Assert.AreEqual(expected.Target, observed.Target, "Target did not match expectation"); this.Assert.AreEqual(expected.Title, observed.Title, "Title did not match expectation"); }
/// <summary> /// Visits a odata operation value. /// </summary> /// <param name="primitiveValue">The primitive value to visit.</param> protected override ODataPayloadElement VisitODataOperation(ODataOperation operation) { ServiceOperationDescriptor descriptor = new ServiceOperationDescriptor(); descriptor.IsAction = true; if (operation is ODataFunction) { descriptor.IsFunction = true; } descriptor.Metadata = operation.Metadata == null ? null : operation.Metadata.OriginalString; descriptor.Target = operation.Target == null ? null : operation.Target.OriginalString; descriptor.Title = operation.Title; return(descriptor); }
/// <summary> /// Visits the children of the given payload element and replaces it with a copy if any child changes /// </summary> /// <param name="serviceOperationDescriptor">The payload element to potentially replace</param> /// <returns>The original element or a copy to replace it with</returns> public virtual ODataPayloadElement Visit(ServiceOperationDescriptor serviceOperationDescriptor) { ExceptionUtilities.CheckArgumentNotNull(serviceOperationDescriptor, "serviceOperationDescriptor"); if (this.alwaysReplace) { return(serviceOperationDescriptor.ReplaceWith <ServiceOperationDescriptor>( new ServiceOperationDescriptor() { IsAction = serviceOperationDescriptor.IsAction, Metadata = serviceOperationDescriptor.Metadata, Target = serviceOperationDescriptor.Target, Title = serviceOperationDescriptor.Title })); } return(serviceOperationDescriptor); }
private IEnumerable <ServiceOperationDescriptor> DeserializeServiceOperatonDescriptors(IEnumerable <XElement> serviceOperationPayloadElements) { List <ServiceOperationDescriptor> serviceOperationDescriptors = new List <ServiceOperationDescriptor>(); foreach (var xelement in serviceOperationPayloadElements) { var serviceOperationDescriptor = new ServiceOperationDescriptor(); if (xelement.Name == MetadataAction) { serviceOperationDescriptor.IsAction = true; } serviceOperationDescriptor.Metadata = this.GetXAttributeValueIfExists(xelement.Attribute(XNameMetadata)); serviceOperationDescriptor.Title = this.GetXAttributeValueIfExists(xelement.Attribute(XNameTitle)); serviceOperationDescriptor.Target = this.GetXAttributeValueIfExists(xelement.Attribute(XNameTarget)); serviceOperationDescriptors.Add(serviceOperationDescriptor); } return(serviceOperationDescriptors.AsEnumerable()); }
private void CreateServiceOperationDescriptor(XElement entryElement, ServiceOperationDescriptor serviceOperationPayloadAnnotation) { string elementName = "action"; if (serviceOperationPayloadAnnotation.IsFunction) { elementName = "function"; } XElement actionNode = CreateMetadataElement(entryElement, elementName); actionNode.Add(new XAttribute("metadata", serviceOperationPayloadAnnotation.Metadata)); if (serviceOperationPayloadAnnotation.Title != null) { actionNode.Add(new XAttribute("title", serviceOperationPayloadAnnotation.Title)); } if (serviceOperationPayloadAnnotation.Target != null) { actionNode.Add(new XAttribute("target", serviceOperationPayloadAnnotation.Target)); } }
/// <summary> /// Visits a payload element whose root is an ServiceOperationDescriptor. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(ServiceOperationDescriptor payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); var serviceOperationPayloadDescriptor = payloadElement as ServiceOperationDescriptor; ExceptionUtilities.CheckArgumentNotNull(serviceOperationPayloadDescriptor, "serviceOperationPayloadDescriptor"); ExceptionUtilities.CheckObjectNotNull(serviceOperationPayloadDescriptor.Metadata, "serviceOperationPayloadDescriptor.Metadata cannot be null"); this.writer.StartObjectScope(); if (serviceOperationPayloadDescriptor.Title != null) { this.writer.WriteName("title"); this.writer.WriteString(serviceOperationPayloadDescriptor.Title); } if (serviceOperationPayloadDescriptor.Target != null) { this.writer.WriteName("target"); this.writer.WriteString(serviceOperationPayloadDescriptor.Target); } this.writer.EndScope(); }
private void VerifyEntityOperations(ODataRequest request, ODataResponse response, List <EntityInstance> entities, bool isTopLevelElement) { foreach (var entity in entities.Where(et => !et.IsNull)) { var instanceEntityType = this.model.EntityTypes.Single(et => et.FullName == entity.FullTypeName); // look at each action/function bound to the same type as entity, ensure it is advertised correctly int numberOfDescriptorsVerified = 0; var functionsWithBindings = this.model.Functions.Where(f => f.Annotations.OfType <ServiceOperationAnnotation>().Any(s => s.BindingKind.IsBound())).ToArray(); foreach (Function function in functionsWithBindings) { ServiceOperationAnnotation serviceOperationAnnotation = function.Annotations.OfType <ServiceOperationAnnotation>().SingleOrDefault(); if (serviceOperationAnnotation != null) { DataType bindingParameterDataType = function.Parameters[0].DataType; EntityDataType bindingEntityDataType = bindingParameterDataType as EntityDataType; if (bindingEntityDataType == null) { ExceptionUtilities.Assert(bindingParameterDataType is CollectionDataType, "Unsupported binding parameter data type."); ExceptionUtilities.Assert(entity.ServiceOperationDescriptors.SingleOrDefault(d => d.Title == function.Name) == null, "Unexpected feed-bound action advertised in entry."); continue; } // Check the base type as well as derived types bool beginServiceOpMatchMatching = bindingEntityDataType.Definition.Model.EntityTypes.Where(t => t.IsKindOf(bindingEntityDataType.Definition)).Where(a => a.FullName.Equals(entity.FullTypeName)).Any(); if (beginServiceOpMatchMatching) { // find ServiceOperationDescriptor that matches the function ServiceOperationDescriptor descriptor = entity.ServiceOperationDescriptors.SingleOrDefault(d => ExtractSimpleActionName(d.Title) == function.Name); bool expectActionDescriptor = true; if (request.Uri.SelectSegments.Count > 0) { expectActionDescriptor = this.ExpectActionWithProjection(request.Uri, function, isTopLevelElement); } if (descriptor == null) { ExceptionUtilities.Assert(!expectActionDescriptor, "Missing service operation descriptor for " + function.Name); } else { expectActionDescriptor = this.VerifyIfOpenType(function, bindingEntityDataType, expectActionDescriptor); ExceptionUtilities.Assert(expectActionDescriptor, "Unexpected service operation descriptor for " + function.Name); // JSONLight will always add the type segment if its a derived type now string derivedTypeFullName = string.Empty; var acceptHeaderValue = response.Headers[HttpHeaders.ContentType]; if (bindingEntityDataType.Definition.BaseType != null) { derivedTypeFullName = string.Concat(bindingEntityDataType.Definition.FullName, "/"); } if (bindingEntityDataType.Definition.FullName != instanceEntityType.FullName) { derivedTypeFullName = string.Concat(instanceEntityType.FullName, "/"); } // check if there is a possible name collision between a property and an action, if so add the Entity Container name to the expected result string containerName = this.BuildExpectedContainerName(function, bindingEntityDataType, instanceEntityType); string expectedMetadataContainerName = string.Concat(function.Model.GetDefaultEntityContainer().Name, "."); // When running in JSONLight descriptor returns full name, not partial if (IsJsonLightResponse(acceptHeaderValue)) { containerName = string.Concat(function.Model.GetDefaultEntityContainer().Name, "."); expectedMetadataContainerName = containerName; } string expectedTarget = string.Concat(entity.Id.TrimEnd('/'), "/", derivedTypeFullName, containerName, function.Name); string expectedMetadata = string.Concat(((ServiceRootSegment)request.Uri.RootSegment).Uri.AbsoluteUri.TrimEnd('/'), "/", Endpoints.Metadata, "#", expectedMetadataContainerName, function.Name); this.Assert(descriptor.Target == expectedTarget, "Expected target " + expectedTarget + " Actual " + descriptor.Target, request, response); this.Assert(descriptor.Metadata == expectedMetadata, "Expected Metadata " + expectedMetadata + " Actual " + descriptor.Metadata, request, response); // verify IsAction flag this.Assert(serviceOperationAnnotation.IsAction == descriptor.IsAction, "Expected action " + serviceOperationAnnotation.IsAction + " Actual " + descriptor.IsAction, request, response); numberOfDescriptorsVerified++; } } } } this.Assert(numberOfDescriptorsVerified == entity.ServiceOperationDescriptors.Count, "Wrong number of action/function.", request, response); this.VerifyExpandedEntityOperations(entity, request, response); } }
public void ReadActionsAndFunctionsTest() { IEdmModel model = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); IEnumerable <ServiceOperationDescriptor> operations = new ServiceOperationDescriptor[] { new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#operation", Target = "http://odata.org/Target" }, new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#operation", Title = "Title", Target = "http://odata.org/Target2" }, }; operations = operations.Concat(operations.Select(o => (ServiceOperationDescriptor) new ServiceOperationDescriptor { IsFunction = true, Metadata = o.Metadata, Title = o.Title, Target = o.Target })); IEnumerable <PayloadReaderTestDescriptor> testDescriptors = operations.Select(o => { EntityInstance entityInstance = PayloadBuilder.Entity("TestModel.CityType"); entityInstance.Add(o); return(new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = entityInstance, PayloadEdmModel = model }); }); // Add couple more handcrafted cases testDescriptors.Concat(new PayloadReaderTestDescriptor[] { // Duplicate action - different targets new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action" }) .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action2" }), PayloadEdmModel = model }, // Duplicate action - same targets // same targets in a metadata - allowed new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action" }) .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action" }), PayloadEdmModel = model }, // Duplicate function - different targets and titles new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function", Title = "Function 1" }) .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function2", Title = "Function 2" }), PayloadEdmModel = model }, // Duplicate function - same targets and titles // same targets in a metadata - allowed new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function", Title = "Function 1" }) .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function", Title = "Function 1" }), PayloadEdmModel = model }, // Function and Action with the same name (ODL doesn't validate this case) new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#operation", Target = "http://odata.org/service/action", Title = "Action" }) .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#operation", Target = "http://odata.org/service/function", Title = "Function" }), PayloadEdmModel = model }, }); // Generate interesting payloads for the EntityInstance with actions/functions // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight testDescriptors = testDescriptors.SelectMany(td => this.PayloadGenerator.GenerateReaderPayloads(td)); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, ODataVersionUtils.AllSupportedVersions, this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => tc.Format == ODataFormat.Atom), (testDescriptor, maxProtocolVersion, testConfiguration) => { if (maxProtocolVersion < testConfiguration.Version) { // This would fail since the DSV > MPV. return; } // In requests or if MPV < V3 we don't expect the operations to be read. if (testConfiguration.IsRequest) { testDescriptor = new PayloadReaderTestDescriptor(testDescriptor); testDescriptor.ExpectedResultNormalizers.Add(tc => RemoveOperationsNormalizer.Normalize); } testDescriptor.RunTest(testConfiguration.CloneAndApplyMaxProtocolVersion(maxProtocolVersion)); }); }
private IEnumerable<ServiceOperationDescriptor> DeserializeServiceOperatonDescriptors(IEnumerable<XElement> serviceOperationPayloadElements) { List<ServiceOperationDescriptor> serviceOperationDescriptors = new List<ServiceOperationDescriptor>(); foreach (var xelement in serviceOperationPayloadElements) { var serviceOperationDescriptor = new ServiceOperationDescriptor(); if (xelement.Name == MetadataAction) { serviceOperationDescriptor.IsAction = true; } serviceOperationDescriptor.Metadata = this.GetXAttributeValueIfExists(xelement.Attribute(XNameMetadata)); serviceOperationDescriptor.Title = this.GetXAttributeValueIfExists(xelement.Attribute(XNameTitle)); serviceOperationDescriptor.Target = this.GetXAttributeValueIfExists(xelement.Attribute(XNameTarget)); serviceOperationDescriptors.Add(serviceOperationDescriptor); } return serviceOperationDescriptors.AsEnumerable(); }
/// <summary> /// Visits the Service Operation Descriptor payload element /// </summary> /// <param name="payloadElement">The payload element to visit</param> public virtual void Visit(ServiceOperationDescriptor payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); }
/// <summary> /// Visits a payload element whose root is a ServiceOperationDescriptor. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(ServiceOperationDescriptor payloadElement) { // TODO: queryvalues don't hold descriptor info, need to update ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); }
public void ReadActionsAndFunctionsTest() { IEdmModel model = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); IEnumerable<ServiceOperationDescriptor> operations = new ServiceOperationDescriptor[] { new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#operation", Target = "http://odata.org/Target" }, new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#operation", Title = "Title", Target = "http://odata.org/Target2" }, }; operations = operations.Concat(operations.Select(o => (ServiceOperationDescriptor)new ServiceOperationDescriptor { IsFunction = true, Metadata = o.Metadata, Title = o.Title, Target = o.Target })); IEnumerable<PayloadReaderTestDescriptor> testDescriptors = operations.Select( o => { EntityInstance entityInstance = PayloadBuilder.Entity("TestModel.CityType"); entityInstance.Add(o); return new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = entityInstance, PayloadEdmModel = model }; }); // Add couple more handcrafted cases testDescriptors.Concat(new PayloadReaderTestDescriptor[] { // Duplicate action - different targets new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action" }) .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action2" }), PayloadEdmModel = model }, // Duplicate action - same targets // same targets in a metadata - allowed new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action" }) .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#action", Target = "http://odata.org/service/action" }), PayloadEdmModel = model }, // Duplicate function - different targets and titles new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function", Title = "Function 1" }) .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function2", Title = "Function 2" }), PayloadEdmModel = model }, // Duplicate function - same targets and titles // same targets in a metadata - allowed new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function", Title = "Function 1" }) .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#function", Target = "http://odata.org/service/function", Title = "Function 1" }), PayloadEdmModel = model }, // Function and Action with the same name (ODL doesn't validate this case) new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("TestModel.CityType") .OperationDescriptor(new ServiceOperationDescriptor { IsAction = true, Metadata = "http://odata.org/service/$metadata#operation", Target = "http://odata.org/service/action", Title = "Action" }) .OperationDescriptor(new ServiceOperationDescriptor { IsFunction = true, Metadata = "http://odata.org/service/$metadata#operation", Target = "http://odata.org/service/function", Title = "Function" }), PayloadEdmModel = model }, }); // Generate interesting payloads for the EntityInstance with actions/functions // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight testDescriptors = testDescriptors.SelectMany(td => this.PayloadGenerator.GenerateReaderPayloads(td)); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, ODataVersionUtils.AllSupportedVersions, this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => tc.Format == ODataFormat.Atom), (testDescriptor, maxProtocolVersion, testConfiguration) => { if (maxProtocolVersion < testConfiguration.Version) { // This would fail since the DSV > MPV. return; } // In requests or if MPV < V3 we don't expect the operations to be read. if (testConfiguration.IsRequest) { testDescriptor = new PayloadReaderTestDescriptor(testDescriptor); testDescriptor.ExpectedResultNormalizers.Add(tc => RemoveOperationsNormalizer.Normalize); } testDescriptor.RunTest(testConfiguration.CloneAndApplyMaxProtocolVersion(maxProtocolVersion)); }); }