/// <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>
        /// 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="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 BatchResponseChangeset InResponseChangeset <T>(
            this T payload,
            int statuscode,
            IRandomNumberGenerator random,
            IODataRequestManager requestManager,
            int operationsBefore = 0,
            int operationsAfter  = 0,
            ODataVersion version = ODataVersion.V4) where T : PayloadTestDescriptor
        {
            ExceptionUtilities.CheckArgumentNotNull(payload, "payload");
            ExceptionUtilities.CheckArgumentNotNull(statuscode, "statuscode");
            ExceptionUtilities.CheckArgumentNotNull(random, "random");
            ExceptionUtilities.CheckArgumentNotNull(requestManager, "requestManager");

            var extraOperations = BatchUtils.ExtraResponseOperations(random, (EdmModel)payload.PayloadEdmModel, version);

            // Build the list of all properties
            IEnumerable <IMimePart> operations = Enumerable.Range(0, operationsBefore).Select(i => random.ChooseFrom(extraOperations));

            operations.ConcatSingle(InResponseOperation(payload, statuscode, requestManager));
            operations = operations.Concat(Enumerable.Range(0, operationsAfter).Select(i => random.ChooseFrom(extraOperations)));

            var changeset = BatchPayloadBuilder.ResponseChangeset("changeset_" + Guid.NewGuid().ToString(), Encoding.UTF8.WebName, operations.ToArray());

            return(changeset);
        }
Example #3
0
        /// <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());
        }
Example #4
0
        /// <summary>
        /// Gets the response changeset with the specified mime parts and content type.
        /// </summary>
        /// <param name="operations">Operations to go into changeset</param>
        /// <param name="contentTypeName">ContentType associated with changeset</param>
        /// <param name="requestManager">RequestManager to build the response changeset.</param>
        /// <returns>A batch response changeset.</returns>
        public static BatchResponseChangeset GetResponseChangeset(
            IMimePart[] operations,
            IODataRequestManager requestManager
            )
        {
            ExceptionUtilities.CheckArgumentNotNull(operations, "operations");
            ExceptionUtilities.CheckArgumentNotNull(requestManager, "requestManager");

            return(BatchPayloadBuilder.ResponseChangeset("changeset_" + Guid.NewGuid().ToString(), Encoding.UTF8.WebName, operations.ToArray()));
        }
Example #5
0
            /// <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()));
            }
Example #6
0
        /// <summary>
        /// Generates extra response changesets.
        /// </summary>
        /// <param name="random">For generating arbitrary changesets.</param>
        /// <param name="model">For adding any generated types to.</param>
        /// <param name="version">Maximum version of any generated types.</param>
        /// <returns>An array of response changesets.</returns>
        public static BatchResponseChangeset[] ExtraResponseChangesets(
            IRandomNumberGenerator random,
            EdmModel model       = null,
            ODataVersion version = ODataVersion.V4)
        {
            ExceptionUtilities.CheckArgumentNotNull(random, "random");

            string contentType = HttpUtilities.BuildContentType(MimeTypes.ApplicationXml, Encoding.UTF8.WebName, null);

            var responses = ExtraResponseOperations(random, model, version);
            List <BatchResponseChangeset> changesets = new List <BatchResponseChangeset>();

            for (int x = 0; x < 5; ++x)
            {
                IEnumerable <IMimePart> operations = Enumerable.Range(0, random.Next(4)).Select(i => random.ChooseFrom(responses));
                changesets.Add(BatchPayloadBuilder.ResponseChangeset("changeset_" + Guid.NewGuid().ToString(), contentType, operations.ToArray()));
            }

            return(changesets.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()));
        }
Example #8
0
        /// <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)
            });
        }