/// <summary> /// Creates a batch payload with the specified number of changesets and the specified number of operations in each changeset. /// </summary> /// <param name="requestManager">Used for building the requests/responses.</param> /// <param name="changeSetCount">The number of changesets to create in the batch payload.</param> /// <param name="changeSetSizes">The size of each changeset.</param> /// <param name="forRequest">true if creating a batch request payload; otherwise false.</param> /// <param name="batchBoundary">The batch boundary to use; or null to use an auto-generated one.</param> /// <returns>A <see cref="PayloadTestDescriptor"/> for the batch payload.</returns> public static PayloadTestDescriptor CreateDefaultQueryBatch( IODataRequestManager requestManager, int queryCount, bool forRequest, string batchBoundary = null) { Debug.Assert(queryCount >= 0, "batchSize >= 0"); var emptyPayload = new PayloadTestDescriptor() { PayloadEdmModel = CreateEmptyEdmModel() }; var root = ODataUriBuilder.Root(new Uri("http://www.odata.org/service.svc")); IMimePart[] parts = new IMimePart[queryCount]; if (forRequest) { var queryOperation = emptyPayload.InRequestOperation(HttpVerb.Get, new ODataUri(new ODataUriSegment[] { root }), requestManager); for (int i = 0; i < queryCount; ++i) { parts[i] = queryOperation; } ; string requestBoundary = batchBoundary ?? "bb_multiple_request_queries_" + queryCount; return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchRequestPayload(parts) .AddAnnotation(new BatchBoundaryAnnotation(requestBoundary)), }); } // Response operation with no payload and a status code of 200 var emptyPayloadResponse = emptyPayload.InResponseOperation(200, requestManager); for (int i = 0; i < queryCount; ++i) { parts[i] = emptyPayloadResponse; } ; string responseBoundary = batchBoundary ?? "bb_multiple_response_queries_" + queryCount; return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(parts) .AddAnnotation(new BatchBoundaryAnnotation(responseBoundary)), }); }
/// <summary> /// Visits an ODataBatch. /// </summary> /// <param name="batch">The batch to visit.</param> protected override ODataPayloadElement VisitBatch(ODataBatch batch) { List <IMimePart> parts = new List <IMimePart>(); if (batch.Parts != null) { foreach (ODataBatchPart part in batch.Parts) { ODataBatchChangeset changeset = part as ODataBatchChangeset; if (changeset == null) { parts.Add(this.ConvertBatchOperation((ODataBatchOperation)part)); } else { List <IMimePart> changeSetOperations = new List <IMimePart>(); if (changeset.Operations != null) { foreach (ODataBatchOperation batchOperation in changeset.Operations) { changeSetOperations.Add(this.ConvertBatchOperation(batchOperation)); } } // TODO: the ODataBatchReader does not expose boundary strings or encodings; should it? if (this.response) { BatchResponseChangeset responseChangeset = BatchPayloadBuilder.ResponseChangeset(/*boundary*/ null, /*charset*/ null, changeSetOperations.ToArray()); parts.Add(responseChangeset); } else { BatchRequestChangeset requestChangeset = BatchPayloadBuilder.RequestChangeset(/*boundary*/ null, /*charset*/ null, changeSetOperations.ToArray()); parts.Add(requestChangeset); } } } } return(this.response ? (ODataPayloadElement)PayloadBuilder.BatchResponsePayload(parts.ToArray()) : (ODataPayloadElement)PayloadBuilder.BatchRequestPayload(parts.ToArray())); }
/// <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 batch payload with the specified number of changesets and the specified number of operations in each changeset. /// </summary> /// <param name="requestManager">Used for building the requests/responses.</param> /// <param name="changeSetCount">The number of changesets to create in the batch payload.</param> /// <param name="changeSetSizes">The size of each changeset.</param> /// <param name="forRequest">true if creating a batch request payload; otherwise false.</param> /// <param name="changeSetBoundary">The changeset boundary to use; or null to use an auto-generated one.</param> /// <returns>A <see cref="PayloadTestDescriptor"/> for the batch payload.</returns> public static PayloadTestDescriptor CreateDefaultChangeSetBatch( IODataRequestManager requestManager, int changeSetCount, int[] changeSetSizes, bool forRequest, string changeSetBoundary = null) { Debug.Assert(changeSetCount >= 0, "batchSize >= 0"); Debug.Assert(changeSetSizes != null, "changeSetSizes != null"); Debug.Assert(changeSetSizes.Length == changeSetCount, "Size of the batch must match the length of the change set sizes array!"); var emptyPayload = new PayloadTestDescriptor() { PayloadEdmModel = CreateEmptyEdmModel() }; var root = ODataUriBuilder.Root(new Uri("http://www.odata.org/service.svc")); IMimePart[] parts = new IMimePart[changeSetCount]; if (forRequest) { // Delete operation with no payload var deleteOperation = emptyPayload.InRequestOperation(HttpVerb.Delete, new ODataUri(new ODataUriSegment[] { root }), requestManager); for (int i = 0; i < changeSetCount; ++i) { int changeSetSize = changeSetSizes[i]; var deleteOperations = new IMimePart[changeSetSize]; for (int j = 0; j < changeSetSize; ++j) { deleteOperations[j] = deleteOperation; } var changeset = BatchUtils.GetRequestChangeset(deleteOperations, requestManager); parts[i] = changeset; } ; string requestBoundary = changeSetBoundary ?? "bb_multiple_request_changesets_" + changeSetCount; return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchRequestPayload(parts) .AddAnnotation(new BatchBoundaryAnnotation(requestBoundary)), }); } // Response operation with no payload and a status code of 200 var emptyPayloadOperation = emptyPayload.InResponseOperation(200, requestManager); for (int i = 0; i < changeSetCount; ++i) { int changeSetSize = changeSetSizes[i]; var operationResponses = new IMimePart[changeSetSize]; for (int j = 0; j < changeSetSize; ++j) { operationResponses[j] = emptyPayloadOperation; } var changeset = BatchUtils.GetResponseChangeset(operationResponses, requestManager); parts[i] = changeset; } ; string responseBoundary = changeSetBoundary ?? "bb_multiple_response_changesets_" + changeSetCount; return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(parts) .AddAnnotation(new BatchBoundaryAnnotation(responseBoundary)), }); }
/// <summary> /// Helper method to run a single iteration of the URI reading tests in a specified configuration. /// </summary> /// <typeparam name="T">The type of the payload to read.</typeparam> /// <param name="payloadElement">The payload to read.</param> /// <param name="setExpectedUriAction">An action to set the URI in question on the payload.</param> /// <param name="model">The metadata model.</param> /// <param name="payloadUri">The payload URI for the current iteration.</param> /// <param name="baseUriValue">The base URI value for the current iteration.</param> /// <param name="resolver">The resolver to use.</param> /// <param name="testConfiguration">The reader test configuration.</param> private void RunBaseUriReadingTest <T>( T payloadElement, Action <T, Uri, ReaderTestConfiguration> setExpectedUriAction, IEdmModel model, Uri payloadUri, BaseUriValue baseUriValue, KeyValuePair <Func <Uri, Uri, Uri, Uri>, Uri> resolver, ReaderTestConfiguration testConfiguration, bool runInBatch = false) where T : ODataPayloadElement { this.Assert.IsNull(testConfiguration.MessageReaderSettings.BaseUri, "No base URI expected on reader settings."); ExpectedException expectedException = null; Uri settingsBaseUri = baseUriValue.ReaderSettingBaseUri; // Set the base URI on the message reader settings if specified if (settingsBaseUri != null) { testConfiguration = new ReaderTestConfiguration(testConfiguration); testConfiguration.MessageReaderSettings.BaseUri = settingsBaseUri; } // Create the payload element T clonedPayloadElement = payloadElement.DeepCopy(); setExpectedUriAction(clonedPayloadElement, payloadUri, testConfiguration); if (testConfiguration.Format == ODataFormat.Atom) { XElement xmlRepresentation = this.PayloadElementToXmlConverter.ConvertToXml(clonedPayloadElement); // add an xml:base attribute if specified Uri xmlBaseUri = baseUriValue.XmlBaseUri; if (xmlBaseUri != null) { xmlRepresentation.Add(new XAttribute(XNamespace.Xml.GetName("base"), xmlBaseUri.OriginalString)); } clonedPayloadElement.XmlRepresentation(xmlRepresentation); if (resolver.Value != null) { setExpectedUriAction(clonedPayloadElement, resolver.Value, testConfiguration); } else { // compute the expected URI value for ATOM if (!payloadUri.IsAbsoluteUri) { if (xmlBaseUri != null) { setExpectedUriAction(clonedPayloadElement, new Uri(xmlBaseUri, payloadUri), testConfiguration); } else if (settingsBaseUri != null) { setExpectedUriAction(clonedPayloadElement, new Uri(settingsBaseUri, payloadUri), testConfiguration); } else { // fail for relative URIs without base URI expectedException = ODataExpectedExceptions.ODataException("ODataAtomDeserializer_RelativeUriUsedWithoutBaseUriSpecified", payloadUri.OriginalString); } } } } else { throw new NotSupportedException("Unsupported configuration format: " + testConfiguration.Format.ToString()); } PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(resolver.Key == null ? this.Settings : this.NoValidatorSettings) { PayloadElement = clonedPayloadElement, PayloadEdmModel = model, ExpectedException = expectedException, UrlResolver = resolver.Key == null ? null : new TestUrlResolver { ResolutionCallback = (baseUri, realPayloadUri) => resolver.Key(payloadUri, baseUri, realPayloadUri) }, SkipTestConfiguration = tc => ODataPayloadElementConfigurationValidator.GetSkipTestConfiguration(payloadElement, ODataPayloadElementConfigurationValidator.AllValidators)(tc), }; if (runInBatch) { // TODO: Batch reader does not enter Exception state upon cross reference error in payload. // Once fixed allow the batch tests to run even for error cases. if (expectedException != null) { return; } if (testConfiguration.IsRequest) { testDescriptor = new PayloadReaderTestDescriptor(testDescriptor) { PayloadElement = PayloadBuilder.BatchRequestPayload( BatchUtils.GetRequestChangeset( new IMimePart[] { testDescriptor.PayloadDescriptor.InRequestOperation( HttpVerb.Put, new ODataUri(ODataUriBuilder.Root(new Uri("http://odata.org/service"))), this.RequestManager, TestMediaTypeUtils.GetDefaultContentType(testDescriptor.PayloadDescriptor.PayloadKind, testConfiguration.Format)) }, this.RequestManager)) .AddAnnotation(new BatchBoundaryAnnotation("bb_request")) }; } else { testDescriptor = new PayloadReaderTestDescriptor(testDescriptor) { PayloadElement = PayloadBuilder.BatchResponsePayload( testDescriptor.PayloadDescriptor.InResponseOperation( 200, this.RequestManager, TestMediaTypeUtils.GetDefaultContentType(testDescriptor.PayloadDescriptor.PayloadKind, testConfiguration.Format))) .AddAnnotation(new BatchBoundaryAnnotation("bb_response")) }; } testConfiguration = new ReaderTestConfiguration(null, testConfiguration.MessageReaderSettings, testConfiguration.IsRequest, testConfiguration.Synchronous, testConfiguration.Version); } testDescriptor.RunTest(testConfiguration); }