/// <summary> /// Puts the specified <paramref name="payload"/> into a changeset. /// </summary> /// <param name="payload">The payload to be used as content for the expanded link.</param> /// <param name="verb">The verb associated with the payload.</param> /// <param name="random">Use of random makes this method non deterministic.</param> /// <param name="requestManager">Used to construct requests</param> /// <param name="operationsBefore">Number of extra operations before payload.</param> /// <param name="operationsAfter">Number of extra operations after payload.</param> /// <param name="version">Highest version of allowed features</param> /// <returns>An entry payload with an expanded link that contains the specified <paramref name="payload"/>.</returns> public static BatchRequestChangeset InRequestChangeset <T>( this T payload, HttpVerb verb, IRandomNumberGenerator random, IODataRequestManager requestManager, int operationsBefore = 0, int operationsAfter = 0, ODataVersion version = ODataVersion.V4 ) where T : PayloadTestDescriptor { ExceptionUtilities.CheckArgumentNotNull(payload, "payload"); ExceptionUtilities.CheckArgumentNotNull(verb, "verb"); ExceptionUtilities.CheckArgumentNotNull(random, "random"); ExceptionUtilities.CheckArgumentNotNull(requestManager, "requestManager"); var baseUri = new ODataUri(ODataUriBuilder.Root(new Uri("http://www.odata.org/service.svc"))); var extraOperations = BatchUtils.ExtraRequestChangesetOperations(random, requestManager, (EdmModel)payload.PayloadEdmModel, baseUri, version); // Build the list of all properties IEnumerable <IHttpRequest> operations = Enumerable.Range(0, operationsBefore).Select(i => random.ChooseFrom(extraOperations)); operations.ConcatSingle(payload.InRequestOperation(verb, baseUri, requestManager)); operations = operations.Concat(Enumerable.Range(0, operationsAfter).Select(i => extraOperations[extraOperations.Length - 1 - (i % extraOperations.Length)])); var changeset = BatchPayloadBuilder.RequestChangeset("changeset_" + Guid.NewGuid().ToString(), Encoding.UTF8.WebName, operations.ToArray()); return(changeset); }
/// <summary> /// Generates extra request changesets. /// </summary> /// <param name="random">For generating arbitrary changesets.</param> /// <param name="requestManager">For building changesets.</param> /// <param name="model">For adding any generated types to.</param> /// <param name="baseUri">Base uri for the changesets.</param> /// <param name="version">Maximum version of any generated types.</param> /// <returns>An array of request changesets.</returns> public static BatchRequestChangeset[] ExtraRequestChangesets( IRandomNumberGenerator random, IODataRequestManager requestManager, EdmModel model, ODataUri baseUri, ODataVersion version = ODataVersion.V4 ) { ExceptionUtilities.CheckArgumentNotNull(random, "random"); ExceptionUtilities.CheckArgumentNotNull(requestManager, "requestManager"); ExceptionUtilities.CheckArgumentNotNull(baseUri, "baseUri"); var headers = new Dictionary <string, string> { { "RequestHeader", "RequestHeaderValue" } }; string mergeContentType = HttpUtilities.BuildContentType(MimeTypes.ApplicationXml, Encoding.UTF8.WebName, null); var requests = ExtraRequestChangesetOperations(random, requestManager, model, baseUri, version); List <BatchRequestChangeset> changesets = new List <BatchRequestChangeset>(); for (int x = 0; x < 5; ++x) { IEnumerable <IHttpRequest> operations = Enumerable.Range(0, random.Next(10)).Select(i => random.ChooseFrom(requests)); changesets.Add(BatchPayloadBuilder.RequestChangeset("changeset_" + Guid.NewGuid().ToString(), "", operations.ToArray())); } return(changesets.ToArray()); }
/// <summary> /// Gets the request changeset with the specified mime parts and content type. /// </summary> /// <param name="operations">Operations to go into changeset</param> /// <param name="requestManager">RequestManager to build the request.</param> /// <returns>A batch request changeset.</returns> public static BatchRequestChangeset GetRequestChangeset( IMimePart[] operations, IODataRequestManager requestManager ) { ExceptionUtilities.CheckArgumentNotNull(operations, "operations"); ExceptionUtilities.CheckArgumentNotNull(requestManager, "requestManager"); return(BatchPayloadBuilder.RequestChangeset("changeset_" + Guid.NewGuid().ToString(), Encoding.UTF8.WebName, operations.ToArray())); }
/// <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())); }
private BatchRequestChangeset GenerateRequestChangeset(BatchResponseChangeset batchResponseChangeset, EntityModelSchema model) { ExceptionUtilities.CheckArgumentNotNull(batchResponseChangeset, "batchResponseChangeset"); ExceptionUtilities.CheckArgumentNotNull(model, "model"); var contentTypeValue = batchResponseChangeset.GetHeaderValueIfExists(HttpHeaders.ContentType); ExceptionUtilities.CheckObjectNotNull(contentTypeValue, "Can't generate request for a response with no content type"); var parts = contentTypeValue.Split(';'); string boundary = parts.Where(s => s.Contains("boundary")).Single(); string contentType = String.Concat(parts.Where(s => s.Contains("charset")).ToArray()); IList <MimePartData <IHttpRequest> > operations = new List <MimePartData <IHttpRequest> >(); foreach (var operation in batchResponseChangeset.Operations) { operations.Add(this.GenerateRequestOperation((ODataResponse)operation, model).AsBatchFragment()); } return(BatchPayloadBuilder.RequestChangeset(boundary, contentType, operations.ToArray())); }
/// <summary> /// Generates the raw test message with mixed encodings defined by the test case, as well as the expected ODataPayloadElement. /// </summary> /// <param name="testCase">The test case defining the structure and encodings of the batch payload.</param> /// <param name="payload">The payload to use for all generated batch operations.</param> /// <param name="payloadUri">The URI to use for all generated batch operations.</param> /// <param name="isRequest">If true, generates a batch request, otherwise a batch response.</param> /// <returns>The test descriptor for this test case/configuration.</returns> private BatchReaderMixedEncodingTestDescriptor CreateTestDescriptor(BatchReaderMixedEncodingTestCase testCase, ODataPayloadElement payload, ODataUri payloadUri, bool isRequest) { ExceptionUtilities.Assert(testCase.BatchEncoding != null, "Batch encoding has not been specified."); string batchBoundary = "batch_" + Guid.NewGuid().ToString(); string payloadUriString = this.UriConverter.ConvertToString(payloadUri); var batchPayload = isRequest ? (ODataPayloadElement) new BatchRequestPayload() : (ODataPayloadElement) new BatchResponsePayload(); batchPayload.AddAnnotation(new BatchBoundaryAnnotation(batchBoundary)); var rawMessage = new List <byte>(); // TODO: Batch reader does not support multi codepoint encodings Encoding unsupportedEncoding = AsUnsupportedEncoding(testCase.BatchEncoding); foreach (var changeset in testCase.Changesets) { string changesetBoundary = "change_" + Guid.NewGuid().ToString(); Encoding changesetEncoding = changeset.ChangesetEncoding ?? testCase.BatchEncoding; // TODO: Batch reader does not support multi codepoint encodings unsupportedEncoding = unsupportedEncoding ?? AsUnsupportedEncoding(changesetEncoding); string changesetContentType = HttpUtilities.BuildContentType( MimeTypes.MultipartMixed, changeset.ChangesetEncoding == null ? string.Empty : changeset.ChangesetEncoding.WebName, changesetBoundary); rawMessage.AddRange( WriteMessagePart( testCase.BatchEncoding, (writer) => { writer.Write("--"); writer.WriteLine(batchBoundary); writer.WriteLine(HttpHeaders.ContentType + ": " + changesetContentType); writer.WriteLine(); })); var mimeParts = new List <IMimePart>(); int contentId = 0; foreach (var operation in changeset.Operations) { ExceptionUtilities.Assert(operation.PayloadFormat == ODataFormat.Atom || operation.PayloadFormat == ODataFormat.Json, "Payload format must be ATOM or JSON."); string formatType = MimeTypes.ApplicationAtomXml + ";type=entry"; Encoding payloadEncoding = operation.OperationEncoding ?? changesetEncoding; string payloadContentType = HttpUtilities.BuildContentType( formatType, operation.OperationEncoding == null ? string.Empty : operation.OperationEncoding.WebName, string.Empty); string httpStatus = isRequest ? "POST " + payloadUriString + " HTTP/1.1" : "HTTP/1.1 201 Created"; rawMessage.AddRange( WriteMessagePart( changesetEncoding, (writer) => { writer.WriteLine(); writer.Write("--"); writer.WriteLine(changesetBoundary); writer.WriteLine(HttpHeaders.ContentType + ": application/http"); writer.WriteLine(HttpHeaders.ContentTransferEncoding + ": binary"); writer.WriteLine(HttpHeaders.ContentId + ": " + (++contentId).ToString()); writer.WriteLine(); writer.WriteLine(httpStatus); writer.WriteLine(HttpHeaders.ContentType + ": " + payloadContentType); writer.WriteLine(); })); IPayloadSerializer payloadSerializer = operation.PayloadFormat == ODataFormat.Atom ? (IPayloadSerializer) new XmlPayloadSerializer(this.PayloadElementToXmlConverter) : (IPayloadSerializer) new JsonPayloadSerializer(this.PayloadElementToJsonConverter.ConvertToJson); byte[] payloadBytes = payloadSerializer.SerializeToBinary(payload, payloadEncoding.WebName); rawMessage.AddRange(payloadBytes.Skip(payloadEncoding.GetPreamble().Length)); if (isRequest) { var request = this.RequestManager.BuildRequest(payloadUri, HttpVerb.Post, new Dictionary <string, string> { { HttpHeaders.ContentType, payloadContentType } }); request.Body = new ODataPayloadBody(payloadBytes, payload); mimeParts.Add(request); } else { var httpResponseData = new HttpResponseData { StatusCode = HttpStatusCode.Created, }; httpResponseData.Headers.Add(HttpHeaders.ContentType, payloadContentType); var response = new ODataResponse(httpResponseData) { Body = payloadBytes, RootElement = payload }; mimeParts.Add(response); } } rawMessage.AddRange( WriteMessagePart( changesetEncoding, (writer) => { writer.WriteLine(); writer.Write("--"); writer.Write(changesetBoundary); writer.WriteLine("--"); })); if (isRequest) { ((BatchRequestPayload)batchPayload).Add(BatchPayloadBuilder.RequestChangeset(changesetBoundary, changesetEncoding.WebName, mimeParts.ToArray())); } else { ((BatchResponsePayload)batchPayload).Add(BatchPayloadBuilder.ResponseChangeset(changesetBoundary, changesetEncoding.WebName, mimeParts.ToArray())); } } rawMessage.AddRange( WriteMessagePart( testCase.BatchEncoding, (writer) => { writer.WriteLine(); writer.Write("--"); writer.Write(batchBoundary); writer.WriteLine("--"); })); return(new BatchReaderMixedEncodingTestDescriptor(this.PayloadReaderSettings) { BatchContentTypeHeader = HttpUtilities.BuildContentType(MimeTypes.MultipartMixed, testCase.BatchEncoding.WebName, batchBoundary), RawMessage = rawMessage.ToArray(), PayloadElement = batchPayload, ExpectedException = unsupportedEncoding == null ? null : ODataExpectedExceptions.ODataException("ODataBatchReaderStream_MultiByteEncodingsNotSupported", unsupportedEncoding.WebName) }); }