public void DisposeAfterExceptionTest()
        {
            // create a default entry and then set both read and edit links to null to provoke an exception during writing
            ODataEntry entry = ObjectModelUtils.CreateDefaultEntry();
            this.Assert.IsNull(entry.EditLink, "entry.EditLink == null");

            this.CombinatorialEngineProvider.RunCombinations(
                new ODataItem[] { entry },
                new bool[] { true, false }, // writeError
                new bool[] { true, false }, // flush
                this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(c => c.IsRequest == false),
                (payload, writeError, flush, testConfiguration) =>
                {
                    testConfiguration = testConfiguration.Clone();
                    testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                    // try writing to a memory stream
                    using (var memoryStream = new TestStream())
                    using (var messageWriter = TestWriterUtils.CreateMessageWriter(memoryStream, testConfiguration, this.Assert))
                    {
                        ODataWriter writer = messageWriter.CreateODataWriter(isFeed: false);
                        ODataWriterCoreInspector inspector = new ODataWriterCoreInspector(writer);
                        try
                        {
                            // write the invalid entry and expect an exception
                            TestExceptionUtils.ExpectedException(
                                this.Assert,
                                () => TestWriterUtils.WritePayload(messageWriter, writer, false, entry),
                                ODataExpectedExceptions.ODataException("WriterValidationUtils_EntriesMustHaveNonEmptyId"),
                                this.ExceptionVerifier); 

                            this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state.");

                            if (writeError)
                            {
                                // now write an error which is the only valid thing to do
                                ODataAnnotatedError error = new ODataAnnotatedError
                                {
                                    Error = new ODataError()
                                    {
                                        Message = "DisposeAfterExceptionTest error message."
                                    }
                                };
                                Exception ex = TestExceptionUtils.RunCatching(() => TestWriterUtils.WritePayload(messageWriter, writer, false, error));
                                this.Assert.IsNull(ex, "Unexpected error '" + (ex == null ? "<none>" : ex.Message) + "' while writing an error.");
                                this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state.");
                            }

                            if (flush)
                            {
                                writer.Flush();
                            }
                        }
                        catch (ODataException oe)
                        {
                            if (writeError && !flush)
                            {
                                this.Assert.AreEqual("A writer or stream has been disposed with data still in the buffer. You must call Flush or FlushAsync before calling Dispose when some data has already been written.", oe.Message, "Did not find expected error message");
                                this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state.");
                            }
                            else
                            {
                                this.Assert.Fail("Caught an unexpected ODataException: " + oe.Message + ".");
                            }
                        }
                    }
                });
        }
Beispiel #2
0
        public void ODataBatchWriterODataPayloadSmokeTests()
        {
            // Create OData payloads
            ODataEntry sampleEntry = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata();
            ODataFeed sampleFeed = ObjectModelUtils.CreateDefaultFeedWithAtomMetadata();
            ODataAnnotatedError sampleError = ObjectModelUtils.CreateDefaultError(true);

            ODataItem[] entryPayload = new ODataItem[] { sampleEntry };
            ODataItem[] feedPayload = new ODataItem[] { sampleFeed, sampleEntry };
            ODataAnnotatedError[] errorPayload = new ODataAnnotatedError[] { sampleError };

            // the expected entry result (ATOM and JSON)
            Func<ODataVersion, string> entryPayloadExpectedAtomResult =
                version => string.Join(
                "$(NL)",
                @"<entry xmlns=""" + TestAtomConstants.AtomNamespace +
                    @""" xmlns:d=""" + TestAtomConstants.ODataNamespace +
                    @""" xmlns:m=""" + TestAtomConstants.ODataMetadataNamespace +
                    @""" xmlns:georss=""" + TestAtomConstants.GeoRssNamespace +
                    @""" xmlns:gml=""" + TestAtomConstants.GmlNamespace + @""">" +
                @"  <id>" + ObjectModelUtils.DefaultEntryId + "</id>",
                @"  <link rel=""self"" href=""" + ObjectModelUtils.DefaultEntryReadLink + @""" />",
                @"  <title />",
                @"  <updated>" + ObjectModelUtils.DefaultEntryUpdated + "</updated>",
                @"  <author>",
                @"    <name />",
                @"  </author>",
                @"  <content type=""application/xml"" />",
                @"</entry>");
            string[] entryPayloadExpectedJsonResult = new string[]
            {
                "{",
                "$(Indent)\"__metadata\":{",
                "$(Indent)$(Indent)\"id\":\"http://www.odata.org/entryid\",\"uri\":\"http://www.odata.org/entry/readlink\"",
                "$(Indent)}",
                "}"
            };

            // create the expected feed result (ATOM and JSON)
            Func<ODataVersion, string> feedPayloadExpectedAtomResult =
                version => string.Join(
                "$(NL)",
                @"<feed xmlns=""" + TestAtomConstants.AtomNamespace + @""" xmlns:d=""" + TestAtomConstants.ODataNamespace +
                    @""" xmlns:m=""" + TestAtomConstants.ODataMetadataNamespace +
                    @""" xmlns:georss=""" + TestAtomConstants.GeoRssNamespace +
                    @""" xmlns:gml=""" + TestAtomConstants.GmlNamespace + @""">" +
                @"  <id>http://www.odata.org/feedid</id>",
                @"  <title />",
                @"  <updated>2010-10-10T10:10:10Z</updated>",
                @"  <entry>",
                @"    <id>" + ObjectModelUtils.DefaultEntryId + "</id>",
                @"    <link rel=""self"" href=""" + ObjectModelUtils.DefaultEntryReadLink + @""" />",
                @"    <title />",
                @"    <updated>" + ObjectModelUtils.DefaultEntryUpdated + "</updated>",
                @"    <author>",
                @"      <name />",
                @"    </author>",
                @"    <content type=""application/xml"" />",
                @"  </entry>",
                @"</feed>");

            string[] feedPayloadExpectedJsonResult = new string[]
            {
                "[",
                "$(Indent){",
                "$(Indent)$(Indent)\"__metadata\":{",
                "$(Indent)$(Indent)$(Indent)\"id\":\"http://www.odata.org/entryid\",\"uri\":\"http://www.odata.org/entry/readlink\"",
                "$(Indent)$(Indent)}",
                "$(Indent)}",
                "]"
            };

            // create the expected error result (ATOM and JSON)
            string errorPayloadExpectedAtomResult =
                string.Join(
                "$(NL)",
                @"<m:error xmlns:m=""" + TestAtomConstants.ODataMetadataNamespace + @""">",
                @"  <m:code>Default error code</m:code>",
                @"  <m:message xml:lang=""Default error message language."">Default error message.</m:message>",
                @"  <m:innererror>",
                @"    <m:message>Default inner error.</m:message>",
                @"    <m:type></m:type>",
                @"    <m:stacktrace></m:stacktrace>",
                @"  </m:innererror>",
                @"</m:error>");

            string[] errorPayloadExpectedJsonResult = new string[]
            {
                "{",
                "$(Indent)\"error\":{",
                "$(Indent)$(Indent)\"code\":\"Default error code\",\"message\":{",
                "$(Indent)$(Indent)$(Indent)\"lang\":\"Default error message language.\",\"value\":\"Default error message.\"",
                "$(Indent)$(Indent)},\"innererror\":{",
                "$(Indent)$(Indent)$(Indent)\"message\":\"Default inner error.\",\"type\":\"\",\"stacktrace\":\"\"",
                "$(Indent)$(Indent)}",
                "$(Indent)}",
                "}",
            };

            // create the various query and changeset batches
            var testCases = new Func<WriterTestConfiguration, BatchTestWithDirection>[]
            {
                testConfig => 
                    {
                        // entry payload of query operation response with 200  response code
                        string expectedResult = testConfig.Format == ODataFormat.Atom
                            ? entryPayloadExpectedAtomResult(testConfig.Version)
                            : JsonUtils.WrapTopLevelValue(testConfig, entryPayloadExpectedJsonResult);

                        testConfig = SetAcceptableHeaders(testConfig);

                        return new BatchTestWithDirection
                        {
                            Batch = BatchWriterUtils.CreateQueryResponseBatch(
                                200, 
                                new BatchWriterUtils.ODataPayload() { Items = entryPayload, TestConfiguration = testConfig, ExpectedResult = expectedResult }, 
                                GetExpectedHeadersForFormat(testConfig.Format, ODataPayloadKind.Entry)),
                            ForRequests = false
                        };
                    },
                testConfig => 
                    {
                        // feed payload of query operation response with 200  response code
                        string expectedResult = testConfig.Format == ODataFormat.Atom
                            ? feedPayloadExpectedAtomResult(testConfig.Version)
                            : JsonUtils.WrapTopLevelResults(testConfig, feedPayloadExpectedJsonResult);

                        testConfig = SetAcceptableHeaders(testConfig);

                        return new BatchTestWithDirection
                        {
                            Batch = BatchWriterUtils.CreateQueryResponseBatch(
                                200, 
                                new BatchWriterUtils.ODataPayload() { Items = feedPayload, TestConfiguration = testConfig, ExpectedResult = expectedResult }, 
                                GetExpectedHeadersForFormat(testConfig.Format, ODataPayloadKind.Feed)),
                            ForRequests = false
                        };
                    },
                testConfig => 
                    {
                        // error payload of query operation response with 200  response code
                        string expectedResult = testConfig.Format == ODataFormat.Atom
                            ? errorPayloadExpectedAtomResult
                            : string.Join("$(NL)", errorPayloadExpectedJsonResult);

                        testConfig = SetAcceptableHeaders(testConfig);

                        return new BatchTestWithDirection
                        {
                            Batch = BatchWriterUtils.CreateQueryResponseBatch(
                                200, 
                                new BatchWriterUtils.ODataPayload() { Items = errorPayload, TestConfiguration = testConfig, ExpectedResult = expectedResult }, 
                                GetExpectedHeadersForFormat(testConfig.Format, ODataPayloadKind.Error)),
                            ForRequests = false
                        };
                    },
                testConfig => 
                    {
                        // changeset request with entry payload
                        string expectedResult = testConfig.Format == ODataFormat.Atom
                            ? entryPayloadExpectedAtomResult(testConfig.Version)
                            : JsonUtils.WrapTopLevelValue(testConfig, entryPayloadExpectedJsonResult);

                        testConfig = SetAcceptableHeaders(testConfig);

                        return new BatchTestWithDirection
                        {
                            Batch = BatchWriterUtils.CreateChangeSetRequestBatch(
                                "POST",
                                new Uri("http://services.odata.org/OData/OData.svc/Products"),
                                new BatchWriterUtils.ODataPayload() { Items = entryPayload, TestConfiguration = testConfig, ExpectedResult = expectedResult }, 
                                GetExpectedHeadersForFormat(testConfig.Format, ODataPayloadKind.Entry)
                                ),
                            ForRequests = true
                        };
                    },
                testConfig => 
                    {
                        // changeset response with entry payload
                        string expectedResult = testConfig.Format == ODataFormat.Atom
                            ? entryPayloadExpectedAtomResult(testConfig.Version)
                            : JsonUtils.WrapTopLevelValue(testConfig, entryPayloadExpectedJsonResult);

                        testConfig = SetAcceptableHeaders(testConfig);

                        return new BatchTestWithDirection
                        {
                            Batch = BatchWriterUtils.CreateChangeSetResponseBatch(
                                200,
                                new BatchWriterUtils.ODataPayload() { Items = entryPayload, TestConfiguration = testConfig, ExpectedResult = expectedResult }, 
                                GetExpectedHeadersForFormat(testConfig.Format, ODataPayloadKind.Entry)
                                ),
                            ForRequests = false
                        };
                    },
                testConfig => 
                    {
                        // changeset response with error payload
                        string expectedResult = testConfig.Format == ODataFormat.Atom
                            ? errorPayloadExpectedAtomResult
                            : string.Join("$(NL)", errorPayloadExpectedJsonResult);

                        testConfig = SetAcceptableHeaders(testConfig);

                        return new BatchTestWithDirection
                        {
                            Batch = BatchWriterUtils.CreateChangeSetResponseBatch(
                                200,
                                new BatchWriterUtils.ODataPayload() { Items = errorPayload, TestConfiguration = testConfig, ExpectedResult = expectedResult }, 
                                GetExpectedHeadersForFormat(testConfig.Format, ODataPayloadKind.Error)),
                            ForRequests = false
                        };
                    },
            };

            // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight
            // Write everything to the batch (ATOM + JSON)
            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                this.WriterTestConfigurationProvider.DefaultFormatConfigurationsWithIndent,
                this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent.Where(tc => !tc.MessageWriterSettings.DisableMessageStreamDisposal && tc.Format == ODataFormat.Atom),
                (testCase, batchTestConfig, payloadTestConfig) =>
                {
                    if (batchTestConfig.IsRequest != payloadTestConfig.IsRequest)
                    {
                        return;
                    }

                    BatchTestWithDirection testWithDirection = testCase(payloadTestConfig);

                    if (batchTestConfig.IsRequest != testWithDirection.ForRequests)
                    {
                        return;
                    }

                    var testDescriptor = new BatchWriterTestDescriptor(this.Settings, testWithDirection.Batch, (Dictionary<string, string>)null);
                    BatchWriterUtils.WriteAndVerifyBatchPayload(testDescriptor, batchTestConfig, payloadTestConfig, this.Assert);
                });
        }