예제 #1
0
        public void CallbackSuccessQueryKeywordTest()
        {
            using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
            {
                request.DataServiceType = typeof(CallbackQueryOptionTestService);
                request.StartService();

                request.RequestUriString = "/ReturnNullServiceOperation?$callback=foo";
                request.SendRequest();
                Assert.AreEqual(204, request.ResponseStatusCode);

                request.RequestUriString = "/Customers(1)/ID/$value?$callback=foo";
                request.SendRequest();
                Assert.AreEqual(200, request.ResponseStatusCode);
                Assert.AreEqual("foo(1)", request.GetResponseStreamAsText());
                Assert.AreEqual("text/javascript;charset=utf-8", request.ResponseHeaders["content-type"]);

                request.RequestUriString = "/Customers/$count?$callback=foo";
                request.SendRequest();
                Assert.AreEqual(200, request.ResponseStatusCode);
                var actualText = request.GetResponseStreamAsText();
                Assert.IsTrue(actualText.StartsWith("foo("));
                Assert.IsTrue(actualText.EndsWith(")"));
                Assert.AreEqual("text/javascript;charset=utf-8", request.ResponseHeaders["content-type"]);
            }
        }
예제 #2
0
            public void CheckRelationshipLinkForDeleteOperationForEntityCollection()
            {
                // CreateChangeScope will make sure that changes are preserved after every SendRequest.
                // By default the data source is created for every request
                using (UnitTestsUtil.CreateChangeScope(typeof(CustomDataContext)))
                {
                    using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
                    {
                        request.ServiceType = typeof(RelationshipLinksService);

                        request.RequestUriString = "/Customers(1)/Orders/$ref";
                        request.HttpMethod       = "GET";
                        request.SendRequest();
                        var response1 = request.GetResponseStreamAsText();

                        request.RequestUriString = "/Customers(1)/Orders/$ref?$id=Orders(1)";
                        request.HttpMethod       = "DELETE";
                        request.SendRequest();

                        var response = request.GetResponseStreamAsText();
                        Assert.IsTrue(response != null);
                        Assert.IsTrue(request.ResponseStatusCode == 204);

                        request.RequestUriString = "/Customers(1)/Orders/$ref";
                        request.HttpMethod       = "GET";
                        request.SendRequest();
                        var response2 = request.GetResponseStreamAsText();

                        Assert.IsTrue(response1 != response2);
                    }
                }
            }
예제 #3
0
        public void CallBackInBatchRequestTest()
        {
            StringBuilder batchQueryOperation = new StringBuilder();

            batchQueryOperation.AppendLine("GET Customers(1)/Address?$callback=foo HTTP/1.1");
            batchQueryOperation.AppendLine("Host: host");
            batchQueryOperation.AppendLine("Accept: " + UnitTestsUtil.JsonMimeType);
            batchQueryOperation.AppendLine("Override-Accept: " + UnitTestsUtil.JsonLightMimeType);

            var testCase = new SimpleBatchTestCase
            {
                RequestPayload = new BatchInfo(new BatchQuery(new Operation(batchQueryOperation.ToString()))),
                ExpectedResponsePayloadContains = new[]
                {
                    "Content-Type: text/javascript;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8",
                    "foo({\"@odata.context\":",
                    "\"StreetAddress\":\"Line1\",\"City\":\"Redmond\",\"State\":\"WA\",\"PostalCode\":\"98052\"})",
                },
                ResponseStatusCode = 202,
                ResponseETag       = default(string),
            };

            using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
            {
                request.HttpMethod         = "POST";
                request.RequestUriString   = "/$batch";
                request.DataServiceType    = typeof(CustomDataContext);
                request.Accept             = UnitTestsUtil.MimeMultipartMixed;
                request.ForceVerboseErrors = true;

                const string boundary = "batch-set";
                request.RequestContentType = String.Format("{0}; boundary={1}", UnitTestsUtil.MimeMultipartMixed, boundary);
                request.SetRequestStreamAsText(BatchRequestWritingUtils.GetBatchText(testCase.RequestPayload, boundary));

                // callback in inner GET request should succeed
                request.SendRequest();
                string response = request.GetResponseStreamAsText();
                Assert.AreEqual(testCase.ResponseStatusCode, request.ResponseStatusCode);
                Assert.IsTrue(request.ResponseContentType.StartsWith("multipart/mixed; boundary=batchresponse_"));
                foreach (string str in testCase.ExpectedResponsePayloadContains)
                {
                    Assert.IsTrue(response.Contains(str), String.Format("The response:\r\n{0}\r\nDoes not contain the string:\r\n{1}.", response, str));
                }

                // callback with $batch should fail
                try
                {
                    request.RequestUriString = "/$batch?$callback=bar";
                    request.SendRequest();
                    Assert.Fail("Request should have failed because it was not a GET request.");
                }
                catch (WebException)
                {
                    Assert.IsTrue(request.GetResponseStreamAsText().Contains("$callback can only be specified on GET requests."));
                    Assert.IsTrue(request.ResponseHeaders["content-type"].StartsWith("application/xml"));
                    Assert.AreEqual(400, request.ResponseStatusCode);
                }
            }
        }
예제 #4
0
        public void CallbackSuccessQueryTest()
        {
            using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
            {
                request.DataServiceType = typeof(CustomDataContext);
                List <string> requestUris = new List <string>()
                {
                    "/Customers(1)/ID?$format=json&$callback=foo",
                    "/Customers(1)/Orders/$ref?$format=json&$callback=foo",
                    "/Customers/?$expand=Orders&$select=ID,Name,Orders&$top=3&$skip=1&$orderby=ID&$filter=Orders/any(p:p/ID%20ne%200)&$format=json&$callback=foo",
                    "/Customers/?$format=json&$callback=foo&$filter=Orders/all(p:p/ID%20ge%200)&inlinecount=allpages",
                };

                foreach (var requestUri in requestUris)
                {
                    request.RequestUriString = requestUri;

                    request.SendRequest();
                    var actualText = request.GetResponseStreamAsText();
                    Assert.IsTrue(actualText.StartsWith("foo("));
                    Assert.IsTrue(actualText.EndsWith(")"));
                    Assert.IsTrue(request.ResponseHeaders["content-type"].StartsWith("text/javascript;odata.metadata=minimal;"));
                    Assert.AreEqual(200, request.ResponseStatusCode);
                }
            }
        }
예제 #5
0
        private static void ResponsesShouldBeTheSame(string baselineUri, string testUri, int statusCode, Func <string, string> prepareExpected, Type serviceType)
        {
            using (TestServiceHost.AllowServerToSerializeException.Restore())
                using (TestWebRequest baselineRequest = TestWebRequest.CreateForInProcess())
                    using (TestWebRequest testRequest = TestWebRequest.CreateForInProcess())
                    {
                        TestServiceHost.AllowServerToSerializeException.Value = true;

                        baselineRequest.DataServiceType = serviceType;
                        testRequest.DataServiceType     = serviceType;

                        baselineRequest.RequestUriString = baselineUri;
                        testRequest.RequestUriString     = testUri;

                        TestUtil.RunCatching(baselineRequest.SendRequest);
                        TestUtil.RunCatching(testRequest.SendRequest);

                        Assert.AreEqual(statusCode, testRequest.ResponseStatusCode);
                        Assert.AreEqual(testRequest.ResponseStatusCode, baselineRequest.ResponseStatusCode);

                        var    baselinePayload = prepareExpected(testRequest.GetResponseStreamAsText());
                        string actualPayload   = baselineRequest.GetResponseStreamAsText();
                        Assert.AreEqual(baselinePayload, actualPayload);
                    }
        }
예제 #6
0
        [Ignore] // Remove Atom
        // [TestMethod, TestCategory("Partition1")]
        public void CanOverrideAcceptHeaderToBatchRequestWithQueryItem()
        {
            StringBuilder batchQueryOperation = new StringBuilder();

            batchQueryOperation.AppendLine("GET Customers(1)/Address?Override-Accept=" + UnitTestsUtil.JsonLightMimeType + " HTTP/1.1");
            batchQueryOperation.AppendLine("Host: host");
            batchQueryOperation.AppendLine("Accept: " + UnitTestsUtil.MimeApplicationXml);

            var test = new SimpleBatchTestCase
            {
                RequestPayload               = new BatchInfo(new BatchQuery(new Operation(batchQueryOperation.ToString()))),
                ResponseStatusCode           = 202,
                ResponseETag                 = default(string),
                ResponseVersion              = V4,
                RequestDataServiceVersion    = V4,
                RequestMaxDataServiceVersion = V4,
            };

            foreach (var serviceType in Services)
            {
                using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
                {
                    request.HttpMethod         = "POST";
                    request.RequestUriString   = "/$batch?Override-Batch-Accept=" + UnitTestsUtil.JsonLightMimeType;
                    request.DataServiceType    = serviceType;
                    request.Accept             = UnitTestsUtil.MimeMultipartMixed;
                    request.RequestVersion     = test.RequestDataServiceVersion.ToString();
                    request.RequestMaxVersion  = test.RequestMaxDataServiceVersion.ToString();
                    request.ForceVerboseErrors = true;
                    if (test.RequestPayload == null)
                    {
                        request.RequestContentLength = 0;
                    }
                    else
                    {
                        const string boundary = "batch-set";
                        request.RequestContentType = String.Format("{0}; boundary={1}", UnitTestsUtil.MimeMultipartMixed, boundary);
                        request.SetRequestStreamAsText(BatchRequestWritingUtils.GetBatchText(test.RequestPayload, boundary));
                    }

                    TestUtil.RunCatching(request.SendRequest);

                    // expect 202 as $batch request does not honor query string Accept header
                    Assert.AreEqual(test.ResponseStatusCode, request.ResponseStatusCode);
                    // The following response header is written in ProcessingRequest/OnStartProcessingRequest
                    Assert.AreEqual(UnitTestsUtil.JsonLightMimeType, request.ResponseHeaders["Override-Batch-Accept"]);

                    string response = request.GetResponseStreamAsText();
                    if (serviceType == typeof(ModifyHeaderOnStartProcessingRequestTestService))
                    {
                        Assert.IsTrue(response.Contains("Content-Type: application/json;odata.metadata=minimal;"));
                    }
                    else
                    {
                        // ProcessingRequest which sets the Aceept header is not called for inner requests
                        Assert.IsTrue(response.Contains("Content-Type: application/xml;charset=utf-8"));
                    }
                }
            }
        }
예제 #7
0
        public void CallbackFailOnCUDRequest()
        {
            using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
            {
                request.DataServiceType  = typeof(CustomDataContext);
                request.RequestUriString = "/Customers(1)?$format=json&$callback=foo";

                List <string> methods = new List <string>()
                {
                    "POST", "PUT", "DELETE"
                };
                request.RequestStream = new MemoryStream(new byte[] { 1, 2, 3, });

                foreach (string method in methods)
                {
                    try
                    {
                        request.HttpMethod = method;
                        request.SendRequest();
                        Assert.Fail("Request should have failed because it was not a GET request.");
                    }
                    catch (WebException)
                    {
                        var actualText = request.GetResponseStreamAsText();
                        Assert.IsFalse(actualText.StartsWith("foo("));
                        Assert.IsTrue(actualText.Contains("$callback can only be specified on GET requests."));

                        Assert.IsTrue(request.ResponseHeaders["content-type"].StartsWith("application/json"));
                        Assert.AreEqual(400, request.ResponseStatusCode);
                    }
                }
            }
        }
        public void PrimitiveCustomAnnotationOnInStreamError()
        {
            using (TestWebRequest webRequest = this.SetupRequest())
            {
                webRequest.RequestUriString = "/InStreamErrorGetCustomers";
                webRequest.Accept           = "application/json;odata.metadata=minimal";
                AnnotationValue             = new ODataPrimitiveValue(88);

                TestUtil.RunCatching(webRequest.SendRequest);

                webRequest.ErrorResponseContent.Should().BeEmpty();
                string responseBody = webRequest.GetResponseStreamAsText();
                responseBody.Should().StartWith("{\"@odata.context\":\"http://");
                responseBody.Should().Contain(string.Concat(
                                                  "\"ID\":1,",
                                                  "\"Name\":\"Customer 1\",",
                                                  "\"NameAsHtml\":\"<html><body>Customer 1</body></html>\",",
                                                  "\"Birthday\":\""
                                                  ));
                responseBody.Should().EndWith(string.Concat(
                                                  "},",
                                                  "{",
                                                  "\"error\":",
                                                  "{",
                                                  "\"code\":\"\",",
                                                  "\"message\":\"InStreamErrorGetCustomers ThrowForCustomer2 error\",",
                                                  "\"@location.error\":88",
                                                  "}",
                                                  "}"
                                                  ));

                HandleExceptionCalls.Should().Be(1);
            }
        }
예제 #9
0
        public void RequestUriCaseInsensitive()
        {
            // Repro: Path to the .svc file shoud not be case sensitive.
            WebServerLocation[] locations = new WebServerLocation[]
            {
                WebServerLocation.InProcessWcf,
                WebServerLocation.Local
            };
            CombinatorialEngine engine = CombinatorialEngine.FromDimensions(
                new Dimension("location", locations));

            TestUtil.RunCombinatorialEngineFail(engine, delegate(Hashtable values)
            {
                WebServerLocation location = (WebServerLocation)values["location"];
                using (TestWebRequest request = TestWebRequest.CreateForLocation(location))
                {
                    request.DataServiceType      = typeof(CustomDataContext);
                    request.RequestUriString     = "/Customers";
                    request.FullRequestUriString = request.FullRequestUriString
                                                   .Replace(".svc", ".SvC")
                                                   .Replace("Test", "test");
                    request.SendRequest();
                    string response = request.GetResponseStreamAsText();
                    Trace.WriteLine(response);
                }
            });
        }
예제 #10
0
        public void HttpProcessUtilityJsonEncodingTest()
        {
            CombinatorialEngine engine = CombinatorialEngine.FromDimensions(
                new Dimension("Test", TestUtil.CreateDictionary <string, Encoding>(
                                  new string[] { UnitTestsUtil.JsonLightMimeType, UnitTestsUtil.JsonLightMimeType + ";charset=utf-16", UnitTestsUtil.JsonLightMimeType + ";charset=GB18030" },
                                  new Encoding[] { Encoding.UTF8, Encoding.Unicode, Encoding.GetEncoding("GB18030") })));

            using (CustomDataContext.CreateChangeScope())
                using (TestWebRequest request = TestWebRequest.CreateForInProcess())
                {
                    request.DataServiceType = typeof(CustomDataContext);
                    request.Accept          = UnitTestsUtil.JsonLightMimeType;
                    request.HttpMethod      = "POST";

                    int index = 100;
                    TestUtil.RunCombinatorialEngineFail(engine, delegate(Hashtable values)
                    {
                        KeyValuePair <string, Encoding> test = (KeyValuePair <string, Encoding>)values["Test"];
                        Encoding encoding = test.Value;

                        request.RequestContentType = test.Key;
                        request.RequestStream      = new MemoryStream();

                        byte[] bytes = encoding.GetBytes("{ @odata.type: 'AstoriaUnitTests.Stubs.Customer', ID : " + index++.ToString() + ", Name : \"P\\\\B \\/K\\\"n\\u00e4c\\f\\tke\\r\\n\\br\\u00f6d AB\" }");
                        request.RequestStream.Write(bytes, 0, bytes.Length);
                        request.RequestStream.Position = 0;

                        request.RequestUriString = "/Customers";
                        request.SendRequest();
                        string responseText = request.GetResponseStreamAsText();
                        Assert.IsTrue(responseText.Contains(@"P\\B /K\" + "\"" + @"n\u00e4c\f\tke\r\n\br\u00f6d AB"), "Response [" + responseText + "] contains the expected escape sequences.");
                    });
                }
        }
예제 #11
0
        public void CallbackFailOnAtomXml()
        {
            using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
            {
                request.DataServiceType = typeof(CustomDataContext);
                List <string> requestUriStrings = new List <string>()
                {
                    "/Customers(1)?$callback=foo",
                    "/Customers(1)/Address?$callback=foo",
                };

                foreach (string requestUriString in requestUriStrings)
                {
                    try
                    {
                        request.RequestUriString = requestUriString;
                        request.Accept           = "application/atom+xml,application/xml";
                        request.SendRequest();
                        Assert.Fail("Request should have failed because our server defaults to ATOM/XML, which does not support $callback.");
                    }
                    catch (WebException)
                    {
                        var actualText = request.GetResponseStreamAsText();
                        Assert.IsFalse(actualText.StartsWith("foo("));
                        Assert.IsTrue(actualText.Contains("is not compatible with the $callback query option."));

                        Assert.IsTrue(request.ResponseHeaders["content-type"].StartsWith("application/xml"));
                        Assert.AreEqual(400, request.ResponseStatusCode);
                    }
                }
            }
        }
        public void BadCustomAnnotationOnErrorWithBatchRequestCausesInStreamErrorInErrorPayload()
        {
            StringBuilder batchQueryOperation = new StringBuilder();

            batchQueryOperation.AppendLine("GET Customers(1)/Addresssss?Override-Accept=" + UnitTestsUtil.JsonLightMimeType + " HTTP/1.1");
            batchQueryOperation.AppendLine("Host: host");
            batchQueryOperation.AppendLine("Accept: " + "application/json;odata.metadata=minimal");

            var test = new SimpleBatchTestCase
            {
                RequestPayload               = new BatchInfo(new BatchQuery(new Operation(batchQueryOperation.ToString()))),
                ResponseStatusCode           = 202,
                ResponseETag                 = default(string),
                ResponseVersion              = V4,
                RequestDataServiceVersion    = V4,
                RequestMaxDataServiceVersion = V4,
            };

            using (TestWebRequest webRequest = this.SetupRequest())
            {
                webRequest.HttpMethod       = "POST";
                webRequest.RequestUriString = "/$batch";

                webRequest.Accept             = UnitTestsUtil.MimeMultipartMixed;
                webRequest.RequestVersion     = "4.0;";
                webRequest.RequestMaxVersion  = "4.0;";
                webRequest.ForceVerboseErrors = true;

                const string boundary = "batch-set";
                webRequest.RequestContentType = String.Format("{0}; boundary={1}", UnitTestsUtil.MimeMultipartMixed, boundary);
                webRequest.SetRequestStreamAsText(BatchRequestWritingUtils.GetBatchText(test.RequestPayload, boundary));

                AnnotationValue = new ODataComplexValue
                {
                    TypeName   = "AstoriaUnitTests.Stubs.Address",
                    Properties = new[]
                    {
                        new ODataProperty {
                            Name = "CityCity", Value = "404"
                        },
                        new ODataProperty {
                            Name = "State", Value = (new DateTimeOffset(2012, 10, 10, 1, 2, 3, new TimeSpan())).ToString()
                        },
                        new ODataProperty {
                            Name = "Foo", Value = new ODataCollectionValue {
                                Items = new Object[] { 123, new Object() }
                            }
                        }                                                                                                          // collection value is wrong so error payload fails to write
                    }
                };

                TestUtil.RunCatching(webRequest.SendRequest);

                // For batch request if ODL fails when writing error, HandleException is called twice and ODataError annotation cannot be be written correctly
                webRequest.ResponseStatusCode.Should().Be(202);
                webRequest.GetResponseStreamAsText().Should().Contain("{\"error\":{\"code\":\"\",\"message\":\"Resource not found for the segment 'Addresssss'.\",\"@location.error\":{\"@odata.type\":\"#AstoriaUnitTests.Stubs.Address\",\"CityCity\":\"404\",\"State\":\"10/10/2012 1:02:03 AM +00:00\",\"Foo\":[123<?xml");
                HandleExceptionCalls.Should().Be(2);
            }
        }
예제 #13
0
        public void RequestUriProcessorKeySpecialRealTest()
        {
            double[] doubleValues = new double[] { double.PositiveInfinity, double.NegativeInfinity, double.NaN };
            string[] findText     = new string[] { "INF", "-INF", "NaN" };
            int      textIndex    = 0; // Index corresponds to the findText array

            CombinatorialEngine engine = CombinatorialEngine.FromDimensions(
                new Dimension("doubleValue", doubleValues));

            using (TestWebRequest request = TestWebRequest.CreateForInProcess())
            {
                request.DataServiceType = typeof(TypedCustomDataContext <TypedEntity <double, string> >);
                TypedCustomDataContext <TypedEntity <double, string> > .ClearHandlers();

                TypedCustomDataContext <TypedEntity <double, string> > .ClearValues();

                TestUtil.RunCombinatorialEngineFail(engine, delegate(Hashtable values)
                {
                    double doubleValue = (double)values["doubleValue"];
                    TypedCustomDataContext <TypedEntity <double, string> > .ValuesRequested += (sender, args) =>
                    {
                        TypedCustomDataContext <TypedEntity <double, string> > s = (TypedCustomDataContext <TypedEntity <double, string> >)sender;
                        TypedEntity <double, string> entity = new TypedEntity <double, string>();
                        entity.ID = doubleValue;
                        s.SetValues(new object[] { entity });
                    };
                    try
                    {
                        Assert.IsTrue(textIndex < 3, "Out of bounds for test data array. Please check the doubleValues variable.");
                        string searchValue = findText[textIndex];

                        // Increment textIndex for next test case
                        ++textIndex;

                        request.RequestUriString = "/Values";
                        request.Accept           = "application/json";
                        request.SendRequest();

                        string responseText = request.GetResponseStreamAsText();
                        Assert.IsTrue(responseText.IndexOf(searchValue) > 0, String.Format("ID \"{0}\" expected in response.", searchValue));

                        Trace.WriteLine(String.Format("Found ID: {0}", searchValue));

                        // Finish the test suite after we've ran through all the strings. If we continue, the test suite continues and fails.
                        // Researching into that is a expensive at this time.
                        if (textIndex == 3)
                        {
                            return;
                        }
                    }
                    finally
                    {
                        TypedCustomDataContext <TypedEntity <double, string> > .ClearHandlers();
                        TypedCustomDataContext <TypedEntity <double, string> > .ClearValues();
                    }
                });
            }
        }
예제 #14
0
        public void RequestUriResourceKeyTest()
        {
            CombinatorialEngine engine = CombinatorialEngine.FromDimensions(
                new Dimension("TypeData", TypeData.Values),
                new Dimension("UseSmallCasing", new bool[] { true, false }),
                new Dimension("UseDoublePostfix", new bool[] { true, false }));

            TestUtil.RunCombinatorialEngineFail(engine, delegate(Hashtable values)
            {
                TypeData typeData = (TypeData)values["TypeData"];
                if (!typeData.IsTypeSupportedAsKey)
                {
                    return;
                }

                // TODO: when System.Uri handles '/' correctly, re-enable.
                if (typeData.ClrType == typeof(System.Xml.Linq.XElement))
                {
                    return;
                }

                Type entityType = typeof(TypedEntity <,>).MakeGenericType(typeData.ClrType, typeof(int));
                CustomDataContextSetup setup = new CustomDataContextSetup(entityType);
                object idValue = typeData.NonNullValue;
                if (idValue is byte[])
                {
                    // idValue = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
                    return;
                }

                bool useSmallCasing   = (bool)values["UseSmallCasing"];
                bool useDoublePostFix = (bool)values["UseDoublePostfix"];

                if (!(idValue is double) && useDoublePostFix)
                {
                    return;
                }

                string valueAsString = TypeData.FormatForKey(idValue, useSmallCasing, useDoublePostFix);
                using (TestWebRequest request = TestWebRequest.CreateForLocation(WebServerLocation.InProcess))
                {
                    Trace.WriteLine("Running with value: [" + valueAsString + "] for [" + typeData.ToString() + "]");
                    setup.Id                 = idValue;
                    setup.MemberValue        = 1;
                    request.DataServiceType  = setup.DataServiceType;
                    request.Accept           = "application/json";
                    request.RequestUriString = "/Values(" + valueAsString + ")";

                    Trace.WriteLine("RequestUriString: " + request.RequestUriString);
                    request.SendRequest();
                    request.GetResponseStreamAsText();
                }

                setup.Cleanup();
            });
        }
예제 #15
0
        public void OpenTypeUrlTest()
        {
            string[] queries = new string[]
            {
                "/Values",
                "/Values('100')/sampleValue2",
                "/Values('100')/sampleValue4",  // no () after sample value 4, it's an array, gets rejected
                "/Values('100')/notfound",      // This should be bad query since we expect to return 404 for open-properties not found
            };

            string[] badQueries = new string[]
            {
                "/Values/sampleValue1",         // no () after Values
                "/Values('100')/sampleValue4()",
                "/Values('100')/sampleValue4('101')",
                "/Values('100')/sampleValue4('101')/ID",
                "/Values('100')/sampleValue4(101)",
                // Since we don't detect types during runtime, this queries will fail
                "/Values('100')/sampleValue3/Identity/Name",
                "/Values('100')/sampleValue3/Identity",
            };

            using (TestWebRequest request = TestWebRequest.CreateForInProcess())
            {
                request.DataServiceType = typeof(OpenTypeContextWithReflection <OpenElement>);
                int i = 0;
                using (StaticCallbackManager <PopulatingValuesEventArgs <OpenElement> > .RegisterStatic((sender, args) =>
                {
                    var o = new OpenElement();
                    o.ID = "100";
                    o.Properties.Add("sampleValue1", "abc");
                    o.Properties.Add("sampleValue2", 12345);
                    args.Values.Add(o);
                }))
                {
                    foreach (string query in queries)
                    {
                        i++;
                        Trace.WriteLine(query);
                        request.RequestUriString = query;
                        request.SendRequest();
                        Trace.WriteLine(request.GetResponseStreamAsText());
                    }

                    foreach (string query in badQueries)
                    {
                        i++;
                        Trace.WriteLine(query);
                        request.RequestUriString = query;
                        Exception exception = TestUtil.RunCatching(request.SendRequest);
                        TestUtil.AssertExceptionExpected(exception, true);
                    }
                }
            }
        }
예제 #16
0
        public void OpenTypeOrderByTest()
        {
            string[][] queries = new string[][]
            {
                new string[] { "/Values?$orderby=sampleValue1", "abc", "ABC" },
                new string[] { "/Values?$orderby=sampleValue1 desc", "ABC", "abc" },
                new string[] { "/Values?$orderby=sampleValue1,sampleValue2", "abc", "ABC" },
                new string[] { "/Values('101')/sampleValue4()?$orderby=ID", "101", "102" },
            };

            using (TestWebRequest request = TestWebRequest.CreateForInProcess())
            {
                request.DataServiceType = typeof(OpenTypeContextWithReflection <OpenElement>);

                using (StaticCallbackManager <PopulatingValuesEventArgs <OpenElement> > .RegisterStatic((sender, args) =>
                {
                    var o = new OpenElement();
                    o.ID = "101";
                    o.Properties.Add("sampleValue1", "abc");
                    o.Properties.Add("sampleValue2", 12345);
                    o.Properties.Add("sampleValue3", true);
                    args.Values.Add(o);

                    o = new OpenElement();
                    o.Properties.Add("sampleValue1", "ABC");
                    o.Properties.Add("sampleValue2", 1);
                    o.Properties.Add("sampleValue3", false);
                    args.Values.Add(o);
                }))
                {
                    int i = 0;
                    foreach (string[] queryParts in queries)
                    {
                        string query = queryParts[0];
                        Trace.WriteLine("Running " + query);
                        request.RequestUriString = query;
                        Exception exception = TestUtil.RunCatching(request.SendRequest);
                        TestUtil.AssertExceptionExpected(exception, i == queries.Length - 1);
                        if (exception == null)
                        {
                            string response     = request.GetResponseStreamAsText();
                            int    firstOffset  = response.IndexOf(queryParts[1]);
                            int    secondOffset = response.IndexOf(queryParts[2]);
                            if (firstOffset >= secondOffset)
                            {
                                Assert.Fail(
                                    "For '" + query + "' the offset for " + queryParts[1] + " (" + firstOffset + ") should be less than " +
                                    "the offset for " + queryParts[2] + " (" + secondOffset + ") in '" + response + "'");
                            }
                        }
                        i++;
                    }
                }
            }
        }
예제 #17
0
        private static void GetResponseAndVerify(TestWebRequest request, int expectedStatusCode, string[] verificationStrings)
        {
            TestUtil.RunCatching(request.SendRequest);
            Assert.AreEqual(expectedStatusCode, request.ResponseStatusCode);

            string responsePayload = request.GetResponseStreamAsText();

            foreach (string verifyString in verificationStrings)
            {
                Assert.IsTrue(responsePayload.Contains(verifyString));
            }
        }
예제 #18
0
 public void WebDataServiceReflectionNoLinqToSql()
 {
     // Verifies that no Linq to SQL-specific types appear in metadata.
     // Incorrect namespace always being defined as System.Data.Linq when you generated a ClientClassGeneration for a LinqToWorkspace uri
     using (TestWebRequest request = TestWebRequest.CreateForInProcess())
     {
         request.DataServiceType  = typeof(TypedCustomDataContext <AllTypes>);
         request.RequestUriString = "/$metadata";
         request.SendRequest();
         string text = request.GetResponseStreamAsText();
         TestUtil.AssertContainsFalse(text, "System.Data");
     }
 }
예제 #19
0
        public void CanOverloadUpdateRequestWithHeader()
        {
            foreach (var serviceType in Services)
            {
                using (CustomDataContext.CreateChangeScope())
                {
                    using (TestWebRequest webRequest = TestWebRequest.CreateForInProcessWcf())
                    {
                        // get an existing customer before sending PUT requests
                        webRequest.HttpMethod       = "GET";
                        webRequest.ServiceType      = serviceType;
                        webRequest.RequestUriString = "/Customers(1)";
                        webRequest.Accept           = UnitTestsUtil.JsonLightMimeType;
                        TestUtil.RunCatching(webRequest.SendRequest);
                        Assert.IsTrue(webRequest.ResponseContentType.ToLower().Contains(UnitTestsUtil.JsonLightMimeType.ToLower()));

                        // all the subsequent requests are PUT requests with specified Accept and Content-Type headers
                        webRequest.HttpMethod         = "PUT";
                        webRequest.Accept             = UnitTestsUtil.JsonLightMimeType;
                        webRequest.RequestContentType = "application/json";

                        // update the customer and send the correct ETag in query string header - should succeed
                        webRequest.RequestUriString = "/Customers(1)/Name?Override-If-Match=" + webRequest.ResponseETag;
                        webRequest.IfMatch          = "SomeBadValue";
                        webRequest.SetRequestStreamAsText("{\"value\": \"Name1\"}");
                        TestUtil.RunCatching(webRequest.SendRequest);
                        Assert.AreEqual(204, webRequest.ResponseStatusCode);
                        string eTag = webRequest.ResponseETag;

                        // update the customer and send ETag with reversed guid in query string header - should fail
                        // Length of a GUID is 36
                        string correctGuid  = webRequest.ResponseETag.Substring(webRequest.ResponseETag.IndexOf('"') + 1, 36);
                        string reversedGuid = string.Concat(correctGuid.ToArray().Reverse());
                        webRequest.RequestUriString = "/Customers(1)/Name?Override-If-Match=" + webRequest.ResponseETag.Replace(correctGuid, reversedGuid);
                        webRequest.IfMatch          = eTag;
                        webRequest.SetRequestStreamAsText("{\"value\": \"Name2\"}");
                        TestUtil.RunCatching(webRequest.SendRequest);
                        Assert.AreEqual(412, webRequest.ResponseStatusCode);

                        // update the customer and send prefer header return=representation in query string - expect 200
                        webRequest.RequestUriString = "/Customers(1)/Name?Override-Prefer=return=representation";
                        webRequest.IfMatch          = eTag;
                        webRequest.SetRequestStreamAsText("{\"value\": \"Name3\"}");
                        TestUtil.RunCatching(webRequest.SendRequest);
                        Assert.AreEqual(200, webRequest.ResponseStatusCode);
                        Assert.IsTrue(webRequest.GetResponseStreamAsText().Contains("TheTest/$metadata#Customers(1)/Name\",\"value\":\"Name3\""));
                    }
                }
            }
        }
예제 #20
0
        public void RequestUriProcessorKeySpecialRealTest()
        {
            double[]            doubleValues = new double[] { double.PositiveInfinity, double.NegativeInfinity, double.NaN };
            CombinatorialEngine engine       = CombinatorialEngine.FromDimensions(
                new Dimension("doubleValue", doubleValues));

            using (TestWebRequest request = TestWebRequest.CreateForInProcess())
            {
                request.DataServiceType = typeof(TypedCustomDataContext <TypedEntity <double, string> >);
                TypedCustomDataContext <TypedEntity <double, string> > .ClearHandlers();

                TypedCustomDataContext <TypedEntity <double, string> > .ClearValues();

                TestUtil.RunCombinatorialEngineFail(engine, delegate(Hashtable values)
                {
                    double doubleValue = (double)values["doubleValue"];
                    TypedCustomDataContext <TypedEntity <double, string> > .ValuesRequested += (sender, args) =>
                    {
                        TypedCustomDataContext <TypedEntity <double, string> > s = (TypedCustomDataContext <TypedEntity <double, string> >)sender;
                        TypedEntity <double, string> entity = new TypedEntity <double, string>();
                        entity.ID = doubleValue;
                        s.SetValues(new object[] { entity });
                    };
                    try
                    {
                        request.RequestUriString = "/Values";
                        request.Accept           = "application/atom+xml,application/xml";
                        request.SendRequest();
                        XmlDocument document = request.GetResponseStreamAsXmlDocument();
                        XmlElement element   = TestUtil.AssertSelectSingleElement(document, "/atom:feed/atom:entry/atom:id");

                        Trace.WriteLine("Found ID: " + element.InnerText);
                        request.FullRequestUriString = element.InnerText;
                        Exception exception          = TestUtil.RunCatching(request.SendRequest);

                        // One NaN value won't match another except throug the use of the .IsNaN
                        // method. It's probably OK to not support this.
                        TestUtil.AssertExceptionExpected(exception, double.IsNaN(doubleValue));

                        string responseText = request.GetResponseStreamAsText();
                        Trace.WriteLine(responseText);
                    }
                    finally
                    {
                        TypedCustomDataContext <TypedEntity <double, string> > .ClearHandlers();
                        TypedCustomDataContext <TypedEntity <double, string> > .ClearValues();
                    }
                });
            }
        }
        public void BatchCustomAnnotationOnInnerRequestErrorShouldGetWrittenInJsonLight()
        {
            StringBuilder batchQueryOperation = new StringBuilder();

            batchQueryOperation.AppendLine("GET Customers(1)/Addresssss?Override-Accept=" + UnitTestsUtil.JsonLightMimeType + " HTTP/1.1");
            batchQueryOperation.AppendLine("Host: host");
            batchQueryOperation.AppendLine("Accept: " + "application/json;odata.metadata=minimal");

            var test = new SimpleBatchTestCase
            {
                RequestPayload               = new BatchInfo(new BatchQuery(new Operation(batchQueryOperation.ToString()))),
                ResponseStatusCode           = 202,
                ResponseETag                 = default(string),
                ResponseVersion              = V4,
                RequestDataServiceVersion    = V4,
                RequestMaxDataServiceVersion = V4,
            };

            using (TestWebRequest webRequest = this.SetupRequest())
            {
                webRequest.HttpMethod       = "POST";
                webRequest.RequestUriString = "/$batch";

                webRequest.Accept             = UnitTestsUtil.MimeMultipartMixed;
                webRequest.RequestVersion     = "4.0;";
                webRequest.RequestMaxVersion  = "4.0;";
                webRequest.ForceVerboseErrors = true;

                const string boundary = "batch-set";
                webRequest.RequestContentType = String.Format("{0}; boundary={1}", UnitTestsUtil.MimeMultipartMixed, boundary);
                webRequest.SetRequestStreamAsText(BatchRequestWritingUtils.GetBatchText(test.RequestPayload, boundary));

                AnnotationValue = new ODataCollectionValue
                {
                    TypeName = "Collection(Edm.String)",
                    Items    = new []
                    {
                        "404",
                        new DateTimeOffset(2012, 10, 10, 1, 2, 3, new TimeSpan()).ToString()
                    }
                };

                TestUtil.RunCatching(webRequest.SendRequest);
                webRequest.ResponseStatusCode.Should().Be(202);
                webRequest.GetResponseStreamAsText().Should().Contain("{\"error\":{\"code\":\"\",\"message\":\"Resource not found for the segment 'Addresssss'.\",\"[email protected]\":\"#Collection(String)\",\"@location.error\":[\"404\",\"10/10/2012 1:02:03 AM +00:00\"]}}");
                HandleExceptionCalls.Should().Be(1);
            }
        }
예제 #22
0
        public void AnnotationBuilderShouldNotBeCalledOutsideMetadataUri()
        {
            NumAnnotationBuilderCalls = 0;
            var testServiceDef = new TestServiceDefinition {
                DataServiceType = typeof(AnnotationsBuilderDataService)
            };

            using (TestWebRequest request = (testServiceDef).CreateForInProcessWcf())
            {
                request.RequestUriString  = request.BaseUri + "/Customers";
                request.Accept            = "application/atom+xml";
                request.RequestMaxVersion = "4.0";
                request.SendRequest();
                request.GetResponseStreamAsText();
                Assert.AreEqual(0, NumAnnotationBuilderCalls);
            }
        }
예제 #23
0
        public void VerifyODataLibIsUsedForWritingTopLevelErrors()
        {
            // Only ODL knows about json lite serialization, so we know ODL is being used if the json lite error was serialized correctly.
            const string expectedJsonLitePayload = @"{""error"":{""code"":"""",""message"":""Resource not found for the segment 'Customers'.""}}";

            using (TestWebRequest r = TestWebRequest.CreateForInProcessWcf())
            {
                r.DataServiceType  = typeof(CustomDataContext);
                r.RequestUriString = "/Customers(-2345354)";
                r.HttpMethod       = "GET";
                r.Accept           = "application/json;odata.metadata=minimal";
                TestUtil.RunCatching(() => r.SendRequest());

                string responsePayload = r.GetResponseStreamAsText();
                Assert.AreEqual(404, r.ResponseStatusCode);
                Assert.AreEqual(expectedJsonLitePayload, responsePayload);
            }
        }
예제 #24
0
        public void CallbackOptionValueTest()
        {
            using (TestWebRequest request = TestWebRequest.CreateForInProcessWcf())
            {
                request.DataServiceType = typeof(CustomDataContext);
                Dictionary <string, string> testCases = new Dictionary <string, string>()
                {
                    // empty callback option
                    { "?$format=json&$callback=", string.Empty },

                    // example callback option values from JQuery and DataJS
                    { "?$callback=parent.handleJSONP_0&$format=json", "parent.handleJSONP_0" },
                    { "?$callback=jQuery18209805240577502099_1348783118115&$format=json&_=1348783118119", "jQuery18209805240577502099_1348783118115" },

                    // callback option values in special character/format
                    { "?$format=json&$callback=null", "null" },
                    { "?$callback=" + Uri.EscapeDataString("A string with characters :%*+,/.") + "&$format=json", "A string with characters :%*+,/." },
                    { "?$callback=" + "<script>$.getJSON(\"http://something.com\",function (data) {alert(data.value);});</script>" + "&$format=json", "<script>$.getJSON(\"http://something.com\",function (data) {alert(data.value);});</script>" },
                };

                foreach (var testCase in testCases)
                {
                    request.RequestUriString = "/Customers(1)" + testCase.Key;

                    request.SendRequest();
                    var actualText = request.GetResponseStreamAsText();
                    if (testCase.Value.Length == 0)
                    {
                        // We don't do JSONP for empty callback value
                        Assert.IsTrue(actualText.StartsWith(testCase.Value + "{"));
                        Assert.IsTrue(actualText.EndsWith("}"));
                        Assert.IsTrue(request.ResponseHeaders["content-type"].StartsWith("application/json;odata.metadata=minimal;"));
                    }
                    else
                    {
                        Assert.IsTrue(actualText.StartsWith(testCase.Value + "({"));
                        Assert.IsTrue(actualText.EndsWith("})"));
                        Assert.IsTrue(request.ResponseHeaders["content-type"].StartsWith("text/javascript;odata.metadata=minimal;"));
                    }

                    Assert.AreEqual(200, request.ResponseStatusCode);
                }
            }
        }
예제 #25
0
        public void EndToEndAnnotationTestEnsuringAnnotationBuilderCalledOnceAndMetadataBumpedToV3()
        {
            NumAnnotationBuilderCalls = 0;
            var testServiceDef = new TestServiceDefinition {
                DataServiceType = typeof(AnnotationsBuilderDataService)
            };

            using (TestWebRequest request = (testServiceDef).CreateForInProcessWcf())
            {
                request.RequestUriString  = request.BaseUri + "/$metadata";
                request.Accept            = "application/xml";
                request.RequestMaxVersion = "4.0";
                request.SendRequest();
                var results       = request.GetResponseStreamAsText();
                var returnedModel = EdmxReader.Parse(XmlTextReader.Create(new StringReader(results)));
                Assert.IsNotNull(returnedModel);

                Assert.AreEqual(1, NumAnnotationBuilderCalls);
            }
        }
        public void DollarFormatSmokeTest()
        {
            const string expectedJsonLight = @"{""@odata.context"":""BASE_URI$metadata#Customers(1)/Address"",""StreetAddress"":""Line1"",""City"":""Redmond"",""State"":""WA"",""PostalCode"":""98052""}";

            // $format should override accept header and give us json light since MDSV is 3
            using (TestWebRequest request = TestWebRequest.CreateForInProcess())
            {
                request.DataServiceType   = typeof(CustomDataContext);
                request.Accept            = "application/xml";
                request.RequestMaxVersion = "4.0";
                request.RequestVersion    = "4.0";
                request.RequestUriString  = "/Customers(1)/Address?$format=json";

                request.SendRequest();
                var actualText = request.GetResponseStreamAsText();

                Assert.AreEqual(200, request.ResponseStatusCode);
                Assert.AreEqual(expectedJsonLight.Replace("BASE_URI", request.BaseUri), actualText);
            }
        }
예제 #27
0
 public void OpenTypeJsonWithNulls()
 {
     using (TestWebRequest request = TestWebRequest.CreateForInProcess())
     {
         using (StaticCallbackManager <PopulatingValuesEventArgs <OpenElement> > .RegisterStatic((sender, args) =>
         {
             var o = new OpenElement();
             o.Properties["Foo"] = null;
             args.Values.Add(o);
         }))
         {
             request.DataServiceType  = typeof(OpenTypeContextWithReflection <OpenElement>);
             request.RequestUriString = "/Values";
             request.Accept           = UnitTestsUtil.JsonLightMimeType;
             Exception exception = TestUtil.RunCatching(request.SendRequest);
             String    response  = request.GetResponseStreamAsText();
             Assert.AreEqual(exception, null);
             Assert.IsTrue(response.Contains("\"Foo\":null"));
         }
     }
 }
        public void FailedTopLevelBatchRequestShouldBeXmlRegardlessOfCustomAnnotation()
        {
            StringBuilder batchQueryOperation = new StringBuilder();

            batchQueryOperation.AppendLine("GET Customers(1)/Address?Override-Accept=" + UnitTestsUtil.JsonLightMimeType + " HTTP/1.1");
            batchQueryOperation.AppendLine("Host: host");
            batchQueryOperation.AppendLine("Accept: " + "application/json;odata.metadata=minimal");

            var test = new SimpleBatchTestCase
            {
                RequestPayload     = new BatchInfo(new BatchQuery(new Operation(batchQueryOperation.ToString()))),
                ResponseStatusCode = 400,
            };

            using (TestWebRequest webRequest = this.SetupRequest())
            {
                webRequest.HttpMethod       = "POST";
                webRequest.RequestUriString = "/$batch";

                webRequest.Accept             = UnitTestsUtil.MimeMultipartMixed;
                webRequest.RequestVersion     = "4.0;";
                webRequest.RequestMaxVersion  = "4.0;";
                webRequest.ForceVerboseErrors = true;
                const string boundary = "batch-set";

                // set content type to json so the batch request fails with 400
                webRequest.RequestContentType = String.Format("{0}; boundary={1}", "application/json;odata.metadata=minimal", boundary);
                webRequest.SetRequestStreamAsText(BatchRequestWritingUtils.GetBatchText(test.RequestPayload, boundary));

                AnnotationValue = new ODataPrimitiveValue("This is a custom value message");

                TestUtil.RunCatching(webRequest.SendRequest);

                // Since the error response of top level batch request is xml, the custom error annotation will be ignored
                webRequest.ResponseStatusCode.Should().Be(test.ResponseStatusCode);
                webRequest.GetResponseStreamAsText().Should().NotContain("custom value message");
                HandleExceptionCalls.Should().Be(1);
            }
        }
예제 #29
0
        public void PlainSerializersMimeOverrideTest()
        {
            using (TestWebRequest request = TestWebRequest.CreateForInProcess())
            {
                request.DataServiceType  = typeof(CustomDataContext);
                request.RequestUriString = "/Customers(1)/NameAsHtml/$value";
                request.SendRequest();
                Assert.AreEqual("text/html", TestUtil.GetMediaType(request.ResponseContentType));
                Assert.IsTrue(request.GetResponseStreamAsText().Contains("<html>"), "Payloads contains '<html>'");
            }

            // Make sure an incompatible accept header causes a content negotiation failure.
            using (TestWebRequest request = TestWebRequest.CreateForInProcess())
            {
                request.DataServiceType  = typeof(CustomDataContext);
                request.RequestUriString = "/Customers(1)/NameAsHtml/$value";
                request.Accept           = "text/plain";
                Exception exception = System.Data.Test.Astoria.TestUtil.RunCatching(request.SendRequest);
                Assert.AreEqual(415, request.ResponseStatusCode);
                Assert.AreEqual(DataServicesResourceUtil.GetString("DataServiceException_UnsupportedMediaType"), exception.InnerException.Message);
            }
        }
예제 #30
0
            public void SecurityStackOverflowTest()
            {
                CombinatorialEngine engine = CombinatorialEngine.FromDimensions(
                    new Dimension("Feature", StackConsumingFeatureData.Values),
                    new Dimension("UseCollections", new bool [] { false, true }));

                TestUtil.RunCombinatorialEngineFail(engine, delegate(Hashtable values)
                {
                    StackConsumingFeatureData feature = (StackConsumingFeatureData)values["Feature"];
                    WebServerLocation location        = WebServerLocation.InProcess;
                    bool useCollections = (bool)values["UseCollections"];

                    using (TestWebRequest request = TestWebRequest.CreateForLocation(location))
                    {
                        if (useCollections)
                        {
                            // Collection switch only does a collection version of the test for serializers
                            if (feature.Feature != StackConsumingFeature.AtomSerializer &&
                                feature.Feature != StackConsumingFeature.JsonSerializer &&
                                feature.Feature != StackConsumingFeature.XmlSerializer)
                            {
                                return;
                            }
                            request.RequestVersion    = "4.0";
                            request.RequestMaxVersion = "4.0";
                        }

                        feature.SetupOverflowRequest(request, useCollections);
                        Exception exception = TestUtil.RunCatching(request.SendRequest);

                        TestUtil.AssertExceptionExpected(exception, true);
                        TestUtil.AssertExceptionStatusCode(exception, feature.ExpectedStatusCode, "");
                        if (location == WebServerLocation.InProcess)
                        {
                            TestUtil.AssertContains(request.GetResponseStreamAsText(), feature.ErrorMessageKey);
                        }
                    }
                });
            }
예제 #31
0
            private void PreferHeader_VerifyResponse(TestWebRequest request, string serviceRoot, bool considerResponsePreference, Action<XDocument> responsePayloadValidation)
            {
                bool? effectiveResponsePreference;
                bool expectedPayload = PreferHeader_ShouldContainResponseBody(request, considerResponsePreference, out effectiveResponsePreference);

                ServiceVersion responseVersion = ServiceVersion.FromHeaderValue(request.ResponseVersion);
                string preferApplied;
                request.ResponseHeaders.TryGetValue("Preference-Applied", out preferApplied);
                string odataEntityId;
                request.ResponseHeaders.TryGetValue("OData-EntityId", out odataEntityId);

                if (request.HttpMethod == "POST")
                {
                    // Substring(1) to remove the first slash
                    // For POST we need to add the (1) to identify the entity posted
                    string itemLocation = serviceRoot + request.RequestUriString.Substring(1) + "(1)";
                    if (effectiveResponsePreference == false)
                    {
                        Assert.AreEqual(204, request.ResponseStatusCode, "POST without response payload should respond with status 204.");
                        Assert.AreEqual(itemLocation, odataEntityId, "Response to POST without payload must include the OData-EntityId header with the value being the URL of the item posted.");
                    }
                    else
                    {
                        Assert.AreEqual(201, request.ResponseStatusCode, "POST with response payload should respond with status 201.");
                        Assert.IsNull(odataEntityId, "Response to POST with payload must NOT include the OData-EntityId header.");
                    }

                    Assert.AreEqual(itemLocation, request.ResponseLocation, "The response to POST should include the Location header and it must have the URL to the item posted.");
                }
                else
                {
                    Assert.AreEqual(expectedPayload ? 200 : 204, request.ResponseStatusCode, "Unexpected response status for PUT/PATCH.");
                    Assert.IsNull(odataEntityId, "Response to anything other than POST must NOT include the OData-EntityId header.");
                }

                if (effectiveResponsePreference.HasValue)
                {
                    Assert.IsTrue(responseVersion.Version >= 40, "Response which was influenced by the Prefer header must have DSV >= 4.0");
                    Assert.AreEqual(effectiveResponsePreference == false ? "return=minimal" : "return=representation", preferApplied,
                        "The preference was applied and thus Preference-Applied header should have been included with the right value.");
                }
                else
                {
                    Assert.IsNull(preferApplied, "No Prefer was sent or it was ignored thus Preference-Applied must not be sent in the response.");
                }

                if (expectedPayload)
                {
                    XDocument response = UnitTestsUtil.GetResponseAsAtomXLinq(request);
                    if (responsePayloadValidation != null)
                    {
                        responsePayloadValidation(response);
                    }
                }
                else
                {
                    string response = request.GetResponseStreamAsText();
                    Assert.IsTrue(string.IsNullOrEmpty(response), "No response should have been sent.");
                }
            }