/// <summary> /// Converts the ATOM metadata annotation of stream properties and assocation links /// into XmlTree annotations and removes the stream properties/association links from the payload. /// </summary> /// <param name="payloadElement">The entity instance to visit.</param> public override void Visit(EntityInstance payloadElement) { IEnumerable <PropertyInstance> properties = payloadElement.Properties; if (properties != null) { // First remove all the stream properties in request payloads if (this.readerTestConfiguration.IsRequest) { List <NamedStreamInstance> streamProperties = properties.OfType <NamedStreamInstance>().ToList(); foreach (var streamProperty in streamProperties) { // Edit link string editRelationValue = TestAtomConstants.ODataStreamPropertyEditMediaRelatedLinkRelationPrefix + streamProperty.Name; XmlTreeAnnotation annotation = GetStreamPropertyLinkXmlTreeAnnotation(streamProperty, editRelationValue); if (annotation != null) { payloadElement.AddAnnotation(annotation); } // Self link string sourceRelationValue = TestAtomConstants.ODataStreamPropertyMediaResourceRelatedLinkRelationPrefix + streamProperty.Name; annotation = GetStreamPropertyLinkXmlTreeAnnotation(streamProperty, sourceRelationValue); if (annotation != null) { payloadElement.AddAnnotation(annotation); } payloadElement.Remove(streamProperty); } } // Then also convert the association links of navigation properties and // remove all navigation properties that do not have a URI - for request if (this.readerTestConfiguration.IsRequest) { List <NavigationPropertyInstance> navigationProperties = properties.OfType <NavigationPropertyInstance>().ToList(); foreach (var navProperty in navigationProperties) { XmlTreeAnnotation annotation = GetAssociationLinkXmlTreeAnnotation(navProperty.AssociationLink); navProperty.AssociationLink = null; if (navProperty.Value == null) { payloadElement.Remove(navProperty); } if (annotation != null) { payloadElement.AddAnnotation(annotation); } } } } base.Visit(payloadElement); }
/// <summary> /// Converts the ATOM metadata annotation of stream properties and assocation links /// into XmlTree annotations and removes the stream properties/association links from the payload. /// </summary> /// <param name="payloadElement">The entity instance to visit.</param> public override void Visit(EntityInstance payloadElement) { IEnumerable<PropertyInstance> properties = payloadElement.Properties; if (properties != null) { // First remove all the stream properties in request payloads if (this.readerTestConfiguration.IsRequest) { List<NamedStreamInstance> streamProperties = properties.OfType<NamedStreamInstance>().ToList(); foreach (var streamProperty in streamProperties) { // Edit link string editRelationValue = TestAtomConstants.ODataStreamPropertyEditMediaRelatedLinkRelationPrefix + streamProperty.Name; XmlTreeAnnotation annotation = GetStreamPropertyLinkXmlTreeAnnotation(streamProperty, editRelationValue); if (annotation != null) { payloadElement.AddAnnotation(annotation); } // Self link string sourceRelationValue = TestAtomConstants.ODataStreamPropertyMediaResourceRelatedLinkRelationPrefix + streamProperty.Name; annotation = GetStreamPropertyLinkXmlTreeAnnotation(streamProperty, sourceRelationValue); if (annotation != null) { payloadElement.AddAnnotation(annotation); } payloadElement.Remove(streamProperty); } } // Then also convert the association links of navigation properties and // remove all navigation properties that do not have a URI - for request if (this.readerTestConfiguration.IsRequest) { List<NavigationPropertyInstance> navigationProperties = properties.OfType<NavigationPropertyInstance>().ToList(); foreach (var navProperty in navigationProperties) { XmlTreeAnnotation annotation = GetAssociationLinkXmlTreeAnnotation(navProperty.AssociationLink); navProperty.AssociationLink = null; if (navProperty.Value == null) { payloadElement.Remove(navProperty); } if (annotation != null) { payloadElement.AddAnnotation(annotation); } } } } base.Visit(payloadElement); }
/// <summary> /// Annotates the entry with app:edited values. /// </summary> /// <param name="entry">The entry to annotate.</param> /// <param name="editedDate">The value of the app:edited element.</param> /// <returns>The entry with the annotation applied.</returns> public static EntityInstance AppEdited(this EntityInstance entry, string editedDate) { ExceptionUtilities.CheckArgumentNotNull(entry, "entry"); entry.AddAnnotation(CreateAppElement(TestAtomConstants.AtomPublishingEditedElementName, editedDate)); return(entry); }
/// <summary> /// Annotates the entry with atom:published values. /// </summary> /// <param name="entry">The entry to annotate.</param> /// <param name="publishedDate">The value of the atom:published element.</param> /// <returns>The feed with the annotation applied.</returns> public static EntityInstance AtomPublished(this EntityInstance entry, string publishedDate) { ExceptionUtilities.CheckArgumentNotNull(entry, "entry"); entry.AddAnnotation(XmlTreeAnnotation.Atom(TestAtomConstants.AtomPublishedElementName, publishedDate)); return(entry); }
/// <summary> /// Annotates the entry with atom:source values. /// </summary> /// <param name="entry">The entry to annotate.</param> /// <param name="sourceFeed">The feed containing metadata to copy.</param> /// <returns>The entry with the annotation applied.</returns> public static EntityInstance AtomSource(this EntityInstance entry, EntitySetInstance sourceFeed) { ExceptionUtilities.CheckArgumentNotNull(entry, "entry"); ExceptionUtilities.CheckArgumentNotNull(sourceFeed, "sourceFeed"); var sourceAnnotations = sourceFeed.Annotations.OfType <XmlTreeAnnotation>(); entry.AddAnnotation( XmlTreeAnnotation.Atom( TestAtomConstants.AtomSourceElementName, null, sourceAnnotations.Select(a => (XmlTreeAnnotation)a.Clone()).ToArray())); return(entry); }
/// <summary> /// Visits an entry item. /// </summary> /// <param name="entry">The entry to visit.</param> protected override ODataPayloadElement VisitEntry(ODataResource entry) { ExceptionUtilities.CheckArgumentNotNull(entry, "entry"); EntityInstance entity = new EntityInstance(entry.TypeName, false); if (this.payloadContainsIdentityMetadata) { entity.Id = entry.Id == null ? null : entry.Id.OriginalString; if (entry.ReadLink != null) { entity.WithSelfLink(entry.ReadLink.OriginalString); } if (entry.EditLink != null) { entity.WithEditLink(entry.EditLink.OriginalString); } } if (this.payloadContainsEtagPropertiesForType(entry.TypeName)) { entity.ETag = entry.ETag; } ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource != null) { entity = entity.AsMediaLinkEntry(); NamedStreamInstance namedStreamInstance = (NamedStreamInstance)this.Visit(mediaResource); entity.StreamETag = namedStreamInstance.ETag; entity.StreamSourceLink = namedStreamInstance.SourceLink; entity.StreamEditLink = namedStreamInstance.EditLink; entity.StreamContentType = namedStreamInstance.SourceLinkContentType ?? namedStreamInstance.EditLinkContentType; foreach (var namedStreamAtomLinkMetadataAnnotation in namedStreamInstance.Annotations.OfType <NamedStreamAtomLinkMetadataAnnotation>()) { entity.AddAnnotation(namedStreamAtomLinkMetadataAnnotation); } } // convert properties and navigation links entry.ProcessPropertiesPreservingPayloadOrder( property => entity.Add((PropertyInstance)this.Visit(property)), navigationLink => entity.Add((PropertyInstance)this.Visit(navigationLink))); var actions = entry.Actions; if (actions != null) { foreach (var operation in actions) { var serviceOperationDescriptor = this.Visit(operation) as ServiceOperationDescriptor; entity.Add(serviceOperationDescriptor); } } var functions = entry.Functions; if (functions != null) { foreach (var operation in functions) { var serviceOperationDescriptor = this.Visit(operation) as ServiceOperationDescriptor; entity.Add(serviceOperationDescriptor); } } this.ConvertSerializationTypeNameAnnotation(entry, entity); return(entity); }
/// <summary> /// Creates several PayloadTestDescriptors containing Batch Responses /// </summary> /// <param name="requestManager">Used for building the requests/responses.</param> /// <param name="model">The model to use for adding additional types.</param> /// <param name="withTypeNames">Whether or not to use full type names.</param> /// <returns>PayloadTestDescriptors</returns> public static IEnumerable <PayloadTestDescriptor> CreateBatchResponseTestDescriptors( IODataRequestManager requestManager, EdmModel model, bool withTypeNames = false) { EdmEntityType personType = null; EdmComplexType carType = null; if (model != null) { //TODO: CLONE for EdmModel //model = model.Clone(); personType = model.FindDeclaredType("TestModel.TFPerson") as EdmEntityType; carType = model.FindDeclaredType("TestModel.TFCar") as EdmComplexType; // Create the metadata types for the entity instance used in the entity set if (carType == null) { carType = new EdmComplexType("TestModel", "TFCar"); model.AddElement(carType); carType.AddStructuralProperty("Make", EdmPrimitiveTypeKind.String, true); carType.AddStructuralProperty("Color", EdmPrimitiveTypeKind.String, true); } if (personType == null) { personType = new EdmEntityType("TestModel", "TFPerson"); model.AddElement(personType); personType.AddKeys(personType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); personType.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String, true); personType.AddStructuralProperty("Car", carType.ToTypeReference()); EdmEntityContainer container = (EdmEntityContainer)model.EntityContainer; if (container == null) { container = new EdmEntityContainer("TestModel", "DefaultContainer"); model.AddElement(container); container.AddEntitySet("Customers", personType); container.AddEntitySet("TFPerson", personType); } } } ComplexInstance carInstance = PayloadBuilder.ComplexValue(withTypeNames ? "TestModel.TFCar" : null) .Property("Make", PayloadBuilder.PrimitiveValue("Ford")) .Property("Color", PayloadBuilder.PrimitiveValue("Blue")); ComplexProperty carProperty = (ComplexProperty)PayloadBuilder.Property("Car", carInstance) .WithTypeAnnotation(carType); EntityInstance personInstance = PayloadBuilder.Entity(withTypeNames ? "TestModel.TFPerson" : null) .Property("Id", PayloadBuilder.PrimitiveValue(1)) .Property("Name", PayloadBuilder.PrimitiveValue("John Doe")) .Property("Car", carInstance) .WithTypeAnnotation(personType); ODataErrorPayload errorInstance = PayloadBuilder.Error("ErrorCode") .Message("ErrorValue") .InnerError( PayloadBuilder.InnerError().Message("InnerErrorMessage").StackTrace("InnerErrorStackTrace").TypeName("InnerErrorTypeName")); var carPropertyPayload = new PayloadTestDescriptor() { PayloadElement = carProperty, PayloadEdmModel = model }; var emptyPayload = new PayloadTestDescriptor() { PayloadEdmModel = CreateEmptyEdmModel() }; var personPayload = new PayloadTestDescriptor() { // This payload will be serialised to JSON so we need the annotation to mark it as a response. PayloadElement = personInstance.AddAnnotation(new PayloadFormatVersionAnnotation() { Response = true, ResponseWrapper = true }), PayloadEdmModel = model }; var errorPayload = new PayloadTestDescriptor() { PayloadElement = errorInstance, PayloadEdmModel = model, }; // response operation with a status code of 5 containing a complex instance var carPropertyPayloadOperation = carPropertyPayload.InResponseOperation(5, requestManager); // response operation with no payload and a status code of 200 var emptyPayloadOperation = emptyPayload.InResponseOperation(200, requestManager); // response operation with a status code of 418 containing an entity instance var personPayloadOperation = personPayload.InResponseOperation(418, requestManager, MimeTypes.ApplicationJsonLight); // response operation with a status code of 404 containing an error instance var errorPayloadOperation = errorPayload.InResponseOperation(404, requestManager); // changeset with multiple operations var twoOperationsChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { carPropertyPayloadOperation, emptyPayloadOperation }, requestManager); // changesets with a single operation var oneOperationChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { personPayloadOperation }, requestManager); var oneErrorChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { errorPayloadOperation }, requestManager); // empty changeset var emptyChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { }, requestManager); // Empty Batch yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { }) .AddAnnotation(new BatchBoundaryAnnotation("bb_emptybatch")), PayloadEdmModel = emptyPayload.PayloadEdmModel, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Single Operation yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { carPropertyPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_singleoperation")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Multiple Operations yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { carPropertyPayloadOperation, emptyPayloadOperation, errorPayloadOperation, personPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_multipleoperations")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Single Changeset yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { twoOperationsChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_singlechangeset")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Multiple Changesets yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { twoOperationsChangeset, oneOperationChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_multiplechangesets")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Operations and changesets yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { twoOperationsChangeset, carPropertyPayloadOperation, oneOperationChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_1")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { carPropertyPayloadOperation, oneOperationChangeset, emptyPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_2")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { errorPayloadOperation, carPropertyPayloadOperation, emptyPayloadOperation, twoOperationsChangeset, oneOperationChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_3")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload( new IMimePart[] { oneErrorChangeset, carPropertyPayloadOperation, emptyChangeset, emptyPayloadOperation, twoOperationsChangeset, personPayloadOperation, oneOperationChangeset, errorPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_4")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); }
/// <summary> /// Creates a set of interesting entity instances along with metadata. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <param name="model">If non-null, the method creates complex types for the complex values and adds them to the model.</param> /// <param name="withTypeNames">true if the payloads should specify type names.</param> /// <returns>List of test descriptors with interesting entity instances as payload.</returns> public static IEnumerable <PayloadTestDescriptor> CreateEntityInstanceTestDescriptors( EdmModel model, bool withTypeNames) { IEnumerable <PrimitiveValue> primitiveValues = TestValues.CreatePrimitiveValuesWithMetadata(fullSet: false); IEnumerable <ComplexInstance> complexValues = TestValues.CreateComplexValues(model, withTypeNames, fullSet: false); IEnumerable <NamedStreamInstance> streamReferenceValues = TestValues.CreateStreamReferenceValues(fullSet: false); IEnumerable <PrimitiveMultiValue> primitiveMultiValues = TestValues.CreatePrimitiveCollections(withTypeNames, fullSet: false); IEnumerable <ComplexMultiValue> complexMultiValues = TestValues.CreateComplexCollections(model, withTypeNames, fullSet: false); IEnumerable <NavigationPropertyInstance> navigationProperties = TestValues.CreateDeferredNavigationLinks(); // NOTE we have to copy the EntityModelTypeAnnotation on the primitive value to the NullPropertyInstance for null values since the // NullPropertyInstance does not expose a value. We will later copy it back to the value we generate for the null property. IEnumerable <PropertyInstance> primitiveProperties = primitiveValues.Select((pv, ix) => PayloadBuilder.Property("PrimitiveProperty" + ix, pv).CopyAnnotation <PropertyInstance, EntityModelTypeAnnotation>(pv)); IEnumerable <PropertyInstance> complexProperties = complexValues.Select((cv, ix) => PayloadBuilder.Property("ComplexProperty" + ix, cv)); IEnumerable <PropertyInstance> primitiveMultiValueProperties = primitiveMultiValues.Select((pmv, ix) => PayloadBuilder.Property("PrimitiveMultiValueProperty" + ix, pmv)); IEnumerable <PropertyInstance> complexMultiValueProperties = complexMultiValues.Select((cmv, ix) => PayloadBuilder.Property("ComplexMultiValueProperty" + ix, cmv)); PropertyInstance[][] propertyMatrix = new PropertyInstance[6][]; propertyMatrix[0] = primitiveProperties.ToArray(); propertyMatrix[1] = complexProperties.ToArray(); propertyMatrix[2] = streamReferenceValues.ToArray(); propertyMatrix[3] = primitiveMultiValueProperties.ToArray(); propertyMatrix[4] = complexMultiValueProperties.ToArray(); propertyMatrix[5] = navigationProperties.ToArray(); IEnumerable <PropertyInstance[]> propertyCombinations = propertyMatrix.ColumnCombinations(0, 1, 6); int count = 0; foreach (PropertyInstance[] propertyCombination in propertyCombinations) { // build the entity type, add it to the model EdmEntityType generatedEntityType = null; string typeName = "PGEntityType" + count; EdmEntityContainer container = null; EdmEntitySet entitySet = null; if (model != null) { // generate a new type with the auto-generated name, check that no type with this name exists and add the default key property to it. Debug.Assert(model.FindDeclaredType(typeName) == null, "Entity type '" + typeName + "' already exists."); generatedEntityType = new EdmEntityType("TestModel", typeName); generatedEntityType.AddKeys(generatedEntityType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); model.AddElement(generatedEntityType); container = model.EntityContainer as EdmEntityContainer; if (container == null) { container = new EdmEntityContainer("TestModel", "DefaultNamespace"); model.AddElement(container); } entitySet = container.AddEntitySet(typeName, generatedEntityType); } EntityInstance entityInstance = PayloadBuilder.Entity("TestModel." + typeName) .Property("Id", PayloadBuilder.PrimitiveValue(count).WithTypeAnnotation(EdmCoreModel.Instance.GetInt32(false))); for (int i = 0; i < propertyCombination.Length; ++i) { PropertyInstance currentProperty = propertyCombination[i]; entityInstance.Add(currentProperty); if (model != null) { if (entitySet == null) { entitySet = container.FindEntitySet(typeName) as EdmEntitySet; } switch (currentProperty.ElementType) { case ODataPayloadElementType.ComplexProperty: ComplexProperty complexProperty = (ComplexProperty)currentProperty; generatedEntityType.AddStructuralProperty(complexProperty.Name, complexProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); break; case ODataPayloadElementType.PrimitiveProperty: PrimitiveProperty primitiveProperty = (PrimitiveProperty)currentProperty; if (primitiveProperty.Value == null) { generatedEntityType.AddStructuralProperty( primitiveProperty.Name, PayloadBuilder.PrimitiveValueType(null)); } else { generatedEntityType.AddStructuralProperty(primitiveProperty.Name, primitiveProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); } break; case ODataPayloadElementType.NamedStreamInstance: NamedStreamInstance streamProperty = (NamedStreamInstance)currentProperty; generatedEntityType.AddStructuralProperty(streamProperty.Name, EdmPrimitiveTypeKind.Stream); break; case ODataPayloadElementType.EmptyCollectionProperty: throw new NotImplementedException(); case ODataPayloadElementType.NavigationPropertyInstance: NavigationPropertyInstance navigationProperty = (NavigationPropertyInstance)currentProperty; var navProperty = generatedEntityType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo() { ContainsTarget = false, Name = navigationProperty.Name, Target = generatedEntityType, TargetMultiplicity = EdmMultiplicity.One }); entitySet.AddNavigationTarget(navProperty, entitySet); break; case ODataPayloadElementType.ComplexMultiValueProperty: ComplexMultiValueProperty complexMultiValueProperty = (ComplexMultiValueProperty)currentProperty; generatedEntityType.AddStructuralProperty(complexMultiValueProperty.Name, complexMultiValueProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); break; case ODataPayloadElementType.PrimitiveMultiValueProperty: PrimitiveMultiValueProperty primitiveMultiValueProperty = (PrimitiveMultiValueProperty)currentProperty; generatedEntityType.AddStructuralProperty(primitiveMultiValueProperty.Name, primitiveMultiValueProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); break; default: throw new NotSupportedException("Unsupported element type found : " + propertyCombination[i].ElementType); } } } if (generatedEntityType != null) { entityInstance.AddAnnotation(new EntityModelTypeAnnotation(generatedEntityType.ToTypeReference(true))); } yield return(new PayloadTestDescriptor() { PayloadElement = entityInstance, PayloadEdmModel = model }); count++; } }