public void SpatialOpenProperty_AtomWrongTypeDeserialize() { var testCases = testData.Select(kvp => new { Type = SpatialTestUtil.GeographyTypeFor(kvp.Key), WktData = new String[] { kvp.Value.Last() } }); String[] edmCases = { "Edm.Double", "Edm.String" }; TestUtil.RunCombinations(testCases, edmCases, (tcase, edmName) => { using (TestWebRequest request = CreateSpatialPropertyService(new Geography[tcase.WktData.Length], tcase.Type, true, true).CreateForInProcess()) { request.RequestUriString = "/Entities"; request.HttpMethod = "POST"; request.RequestContentType = UnitTestsUtil.AtomFormat; request.SetRequestStreamAsText(AggregateAtomPayloadFromWkt(tcase.Type.Name, tcase.WktData, edmName)); Exception ex = TestUtil.RunCatching(request.SendRequest); Assert.IsNotNull(ex); while (ex.InnerException != null) { ex = ex.InnerException; } Assert.AreEqual(ODataLibResourceUtil.GetString("XmlReaderExtension_InvalidNodeInStringValue", "Element"), ex.Message); } }); }
public void RequestShouldFailIfTooManyItemsAreExpandedAtMultipleLevels() { string errorMessage = ODataLibResourceUtil.GetString("UriParser_ExpandCountExceeded", 4, 3); ResponseShouldMatchXPath( "/Entities?$expand=Reference($expand=Reference2),Reference3($expand=Reference4)", 400, "//adsm:error/adsm:message[text()='" + errorMessage + "']", serviceType: typeof(UriParserIntegrationTestServiceWithLowLimits)); }
public void RequestShouldFailIfExpandIsTooDeep() { string errorMessage = ODataLibResourceUtil.GetString("UriParser_ExpandDepthExceeded", 3, 2); ResponseShouldMatchXPath( "/Entities?$expand=Reference($expand=Reference($expand=Reference))", 400, "//adsm:error/adsm:message[text()='" + errorMessage + "']", serviceType: typeof(UriParserIntegrationTestServiceWithLowLimits)); }
public void TestEqualityHandling() { string geographyLiteral = GetUriLiteral(typeof(GeographyPoint), TestPoint.DefaultValues.TripLegGeography1.AsGeography()); string geometryLiteral = GetUriLiteral(typeof(GeometryPoint), TestPoint.DefaultValues.TripLegGeography1.AsGeography()); var testCases = new[] { new { Type = typeof(GeographyPoint), Left = "GeographyProperty1", Right = geographyLiteral, Operator = "eq", OperatorName = "Equal" }, new { Type = typeof(GeographyPoint), Left = geographyLiteral, Right = "GeographyProperty1", Operator = "eq", OperatorName = "Equal" }, new { Type = typeof(GeometryPoint), Left = "GeographyProperty1", Right = geometryLiteral, Operator = "eq", OperatorName = "Equal" }, new { Type = typeof(GeometryPoint), Left = geometryLiteral, Right = "GeographyProperty1", Operator = "eq", OperatorName = "Equal" }, }; TestUtil.RunCombinations(testCases, (testCase) => { DSPUnitTestServiceDefinition roadTripServiceDefinition = GetRoadTripServiceDefinition(testCase.Type, TestPoint.DefaultValues); using (TestWebRequest request = roadTripServiceDefinition.CreateForInProcess()) { request.StartService(); // GET request.Accept = UnitTestsUtil.MimeAny; request.RequestContentType = null; request.HttpMethod = "GET"; request.RequestUriString = string.Format("/TripLegs/?$filter={0} {1} {2}", testCase.Left, testCase.Operator, testCase.Right); int operatorPos = testCase.Left.Length + 1; WebException e = TestUtil.RunCatching <WebException>(() => request.SendRequest()); Assert.IsNotNull(e, "didn't get the exception we should have gotten"); string expectedMessage = ODataLibResourceUtil.GetString( "MetadataBinder_IncompatibleOperandsError", "Edm." + testCase.Type.Name, "Edm." + testCase.Type.Name, testCase.OperatorName, operatorPos); Assert.AreEqual(expectedMessage, e.InnerException.Message, "didn't get the correct error"); } }); }
[Ignore] // Remove Atom // [TestCategory("Partition2"), TestMethod, Variation] public void BatchContentTypeTest() { var testCases = new BatchContentTypeTestCase[] { // Completely wrong content type new BatchContentTypeTestCase { ContentType = "text/plain", ExpectedErrorStatusCode = 400, ExpectedClientErrorMessage = DataServicesClientResourceUtil.GetString("Batch_ExpectedContentType", "text/plain") }, // Just type is correct, subtype is wrong new BatchContentTypeTestCase { ContentType = "multipart/text", ExpectedErrorStatusCode = 400, ExpectedClientErrorMessage = DataServicesClientResourceUtil.GetString("Batch_ExpectedContentType", "multipart/text") }, // No boundary - still wrong new BatchContentTypeTestCase { ContentType = "multipart/mixed", ExpectedErrorStatusCode = 400, ExpectedClientErrorMessage = ODataLibResourceUtil.GetString("MediaTypeUtils_BoundaryMustBeSpecifiedForBatchPayloads", "multipart/mixed", "boundary") }, // Some other parameter but no boundary new BatchContentTypeTestCase { ContentType = "multipart/mixed;param=value", ExpectedErrorStatusCode = 400, ExpectedClientErrorMessage = ODataLibResourceUtil.GetString("MediaTypeUtils_BoundaryMustBeSpecifiedForBatchPayloads", "multipart/mixed;param=value", "boundary") }, // Empty boundary - fails new BatchContentTypeTestCase { ContentType = "multipart/mixed;boundary=", ExpectedErrorStatusCode = 400, ExpectedClientErrorMessage = ODataLibResourceUtil.GetString("ValidationUtils_InvalidBatchBoundaryDelimiterLength", string.Empty, "70") }, new BatchContentTypeTestCase { ContentType = "multipart/mixed;boundary=;param=value", ExpectedErrorStatusCode = 400, ExpectedClientErrorMessage = ODataLibResourceUtil.GetString("ValidationUtils_InvalidBatchBoundaryDelimiterLength", string.Empty, "70") }, // Two boundary parameters - wrong new BatchContentTypeTestCase { ContentType = "multipart/mixed;boundary=one;boundary=two", ExpectedErrorStatusCode = 400, ExpectedClientErrorMessage = ODataLibResourceUtil.GetString("MediaTypeUtils_BoundaryMustBeSpecifiedForBatchPayloads", "multipart/mixed;boundary=one;boundary=two", "boundary") }, // Valid simple boundary new BatchContentTypeTestCase { ContentType = "multipart/mixed;boundary=batchboundary", PayloadBatchBoundary = "batchboundary" }, // Valid simple boundary - mimetype using different casing new BatchContentTypeTestCase { ContentType = "MultiPart/mIxed;boundary=batchboundary", PayloadBatchBoundary = "batchboundary" }, // Valid simple boundary - boundary parameter name different casing new BatchContentTypeTestCase { ContentType = "multipart/mixed;BounDary=batchboundary", PayloadBatchBoundary = "batchboundary" }, }; OpenWebDataServiceDefinition serverService = new OpenWebDataServiceDefinition() { DataServiceType = typeof(CustomDataContext) }; PlaybackServiceDefinition clientService = new PlaybackServiceDefinition(); TestUtil.RunCombinations( testCases, (testCase) => { using (TestWebRequest request = serverService.CreateForInProcess()) { request.RequestContentType = testCase.ContentType; request.SetRequestStreamAsText(string.Format( "--{0}\r\n" + "Content-Type: multipart/mixed; boundary=changesetresponse_00000001-0000-0000-0000-000000000000\r\n\r\n" + "--changesetresponse_00000001-0000-0000-0000-000000000000\r\n" + "--changesetresponse_00000001-0000-0000-0000-000000000000--\r\n" + "--{0}--\r\n", testCase.PayloadBatchBoundary)); request.RequestUriString = "/$batch"; request.HttpMethod = "POST"; Exception exception = TestUtil.RunCatching(request.SendRequest); int actualStatusCode = 0; if (exception != null) { actualStatusCode = request.ResponseStatusCode; } else { Assert.AreEqual(202, request.ResponseStatusCode, "Wrong response code for no-exception request."); BatchWebRequest batchResponse = BatchWebRequest.FromResponse(InMemoryWebRequest.FromResponse(request)); if (batchResponse.Parts.Count > 0) { actualStatusCode = batchResponse.Parts[0].ResponseStatusCode; if (actualStatusCode == 200) { actualStatusCode = 0; } } } Assert.AreEqual(testCase.ExpectedErrorStatusCode, actualStatusCode, "Wrong status code."); } using (TestWebRequest request = clientService.CreateForInProcessWcf()) { request.StartService(); clientService.ProcessRequestOverride = clientRequest => { var clientResponse = new InMemoryWebRequest(); clientResponse.SetResponseStatusCode(202); clientResponse.ResponseHeaders["Content-Type"] = testCase.ContentType; clientResponse.SetResponseStreamAsText(string.Format( "--{0}\r\n" + "Content-Type: application/http\r\n" + "Content-Transfer-Encoding: binary\r\n" + "\r\n" + "200 OK\r\n" + "<feed xmlns='http://www.w3.org/2005/Atom'/>\r\n" + "--{0}--\r\n", testCase.PayloadBatchBoundary)); return(clientResponse); }; DataServiceContext ctx = new DataServiceContext(request.ServiceRoot); Exception exception = TestUtil.RunCatching(() => ctx.ExecuteBatch(ctx.CreateQuery <Customer>("/Customers"))); if (exception != null) { exception = ((DataServiceRequestException)exception).InnerException; Assert.AreEqual(testCase.ExpectedClientErrorMessage, exception.Message, "Unexpected error message."); } else { Assert.IsNull(testCase.ExpectedClientErrorMessage, "Expected exception, but none was thrown."); } } }); }
public void PrimitiveTypes_Generated_WithIncorrectNullability() { string orderPayloadWithNullableProperties = @"HTTP/1.1 200 OK Proxy-Connection: Keep-Alive Connection: Keep-Alive Content-Length: 2542 Via: 1.1 TK5-PRXY-08 Expires: Wed, 04 Jan 2012 23:39:02 GMT Date: Wed, 04 Jan 2012 23:38:02 GMT Content-Type: application/atom+xml;charset=utf-8 Server: Microsoft-IIS/7.5 Cache-Control: private Vary: * OData-Version: 4.0; X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET <?xml version='1.0' encoding='utf-8' standalone='yes'?> <feed xml:base='http://services.odata.org/Northwind/Northwind.svc/' xmlns:d='http://docs.oasis-open.org/odata/ns/data' xmlns:m='http://docs.oasis-open.org/odata/ns/metadata' xmlns='http://www.w3.org/2005/Atom'> <title type='text'>OrderDetails</title> <id>http://services.odata.org/Northwind/Northwind.svc/OrderDetails</id> <updated>2012-01-04T23:32:26Z</updated> <link rel='self' title='OrderDetails' href='OrderDetails' /> <entry> <id>http://services.odata.org/Northwind/Northwind.svc/OrderDetails(10248)</id> <title type='text'></title> <updated>2012-01-04T23:32:26Z</updated> <author> <name /> </author> <link rel='edit' title='OrderDetail' href='OrderDetails(10248)' /> <link rel='http://docs.oasis-open.org/odata/ns/related/Customer' type='application/atom+xml;type=entry' title='Customer' href='OrderDetails(10248)/Customer' /> <link rel='http://docs.oasis-open.org/odata/ns/related/Employee' type='application/atom+xml;type=entry' title='Employee' href='OrderDetails(10248)/Employee' /> <link rel='http://docs.oasis-open.org/odata/ns/related/OrderDetail_Details' type='application/atom+xml;type=feed' title='OrderDetail_Details' href='OrderDetails(10248)/OrderDetail_Details' /> <link rel='http://docs.oasis-open.org/odata/ns/related/Shipper' type='application/atom+xml;type=entry' title='Shipper' href='OrderDetails(10248)/Shipper' /> <category term='NorthwindModel.OrderDetail' scheme='http://docs.oasis-open.org/odata/ns/scheme' /> <content type='application/xml'> <m:properties> <d:OrderID m:type='Edm.Int32'>10248</d:OrderID> <d:ProductID m:type='Edm.Int32'>10248</d:ProductID> <d:UnitPrice m:null='true'/> <d:Quantity m:null='true'/> </m:properties> </content> </entry> </feed>"; PlaybackServiceDefinition playbackService = new PlaybackServiceDefinition(); using (TestWebRequest request = playbackService.CreateForInProcessWcf()) { request.ServiceType = typeof(PlaybackService); request.ForceVerboseErrors = true; request.StartService(); DataServiceContext ctx = new DataServiceContext(request.ServiceRoot); ctx.EnableAtom = true; playbackService.OverridingPlayback = orderPayloadWithNullableProperties; InvalidOperationException nullAssignmentError = null; try { foreach (var orderDetail in ctx.CreateQuery <OrderDetail>("OrderDetails")) { } } catch (InvalidOperationException ioException) { nullAssignmentError = ioException; } finally { request.StopService(); } Assert.IsNotNull(nullAssignmentError, "Client library should not allow assignment of null values to non-nullable properties"); Assert.AreEqual(ODataLibResourceUtil.GetString("ReaderValidationUtils_NullNamedValueForNonNullableType", "UnitPrice", "Edm.Double"), nullAssignmentError.Message); } }
public void AtomParserAttributeNamespaceTest() { const string atomPayloadTemplate = @"HTTP/1.1 200 OK Content-Type: application/atom+xml <feed xmlns:d='http://docs.oasis-open.org/odata/ns/data' xmlns:m='http://docs.oasis-open.org/odata/ns/metadata' xmlns:atom='http://www.w3.org/2005/Atom' xmlns:invalid='http://odata.org/invalid/namespace' xmlns:gml='http://www.opengis.net/gml' xmlns='http://www.w3.org/2005/Atom'> <title type='text'>ASet</title> <id>http://host/ASet</id> <updated>2010-09-01T23:36:00Z</updated> <link rel='self' title='ASet' href='ASet' /> <entry> <id>http://host/ASet(1)</id> <title type='text'></title> <updated>2010-09-01T23:36:00Z</updated> <author> <name /> </author> <link rel='self' title='EntityA' href='ASet(1)' /> <link rel='edit' title='EntityA' href='ASet(1)' /> <link rel='edit-media' title='EntityA' href='ASet(1)/$value' /> <category {0}='NamespaceName.EntityA' {1}='http://docs.oasis-open.org/odata/ns/scheme' /> <content {3}='http://odata.org/readstream1' /> <m:properties> <d:ID {4}='Edm.Int32'>1</d:ID> </m:properties> </entry> </feed>"; const string defaultCategoryTerm = "term"; const string defaultCategoryScheme = "scheme"; const string defaultContentType = "type"; const string defaultContentSource = "src"; const string defaultPropertyType = "m:type"; AtomParserAttributeNamespaceTestCase[] testCases = new AtomParserAttributeNamespaceTestCase[] { // Error cases new AtomParserAttributeNamespaceTestCase { CategoryScheme = "invalid:scheme" }, new AtomParserAttributeNamespaceTestCase { CategoryTerm = "invalid:term" }, new AtomParserAttributeNamespaceTestCase { ContentType = "invalid:type" }, new AtomParserAttributeNamespaceTestCase { ContentSrc = "invalid:src" }, new AtomParserAttributeNamespaceTestCase { PropertyType = "invalid:type" }, }; PlaybackServiceDefinition playbackService = new PlaybackServiceDefinition(); using (TestWebRequest request = playbackService.CreateForInProcessWcf()) { request.ServiceType = typeof(PlaybackService); request.ForceVerboseErrors = true; request.StartService(); TestUtil.RunCombinations( testCases, testCase => { DataServiceContext ctx = new DataServiceContext(request.ServiceRoot, ODataProtocolVersion.V4); ctx.EnableAtom = true; // {0} - atom:category/@term // {1} - atom:category/@scheme // {2} - atom:content/@type // {3} - atom:content/@src // {4} - d:property/@m:type string atomPayload = string.Format( atomPayloadTemplate, testCase.CategoryTerm ?? defaultCategoryTerm, testCase.CategoryScheme ?? defaultCategoryScheme, testCase.ContentType ?? defaultContentType, testCase.ContentSrc ?? defaultContentSource, testCase.PropertyType ?? defaultPropertyType); playbackService.OverridingPlayback = atomPayload; EntityA[] items; try { items = ctx.CreateQuery <EntityA>("ASet").ToArray(); } catch (InvalidOperationException ex) { if (testCase.ContentSrc != null && testCase.ContentSrc.StartsWith("invalid")) { Assert.AreEqual(ODataLibResourceUtil.GetString("ODataAtomReader_MediaLinkEntryMismatch"), ex.Message); return; } else if (testCase.PropertyType != null && testCase.PropertyType.StartsWith("invalid")) { Assert.AreEqual(DataServicesClientResourceUtil.GetString("Deserialize_ExpectingSimpleValue"), ex.Message); return; } Assert.Fail("Exception received but did not expect any failure.\n" + ex.Message); return; } Assert.AreEqual(1, items.Length, "Expected 1 item in the payload."); var firstItem = items[0]; var entities = ctx.Entities; Assert.AreEqual(1, entities.Count, "Expected 1 entity in the context."); var firstEntity = entities[0]; // Verify category/@term and category/@scheme by testing the type name string expectedTypeName = testCase.CategoryScheme != null && testCase.CategoryScheme.StartsWith("invalid") || testCase.CategoryTerm != null && testCase.CategoryTerm.StartsWith("invalid") ? null : "NamespaceName.EntityA"; Assert.AreEqual(expectedTypeName, firstEntity.ServerTypeName, "Type names don't match."); // Verify content/@src by checking that the read stream of the entry is correct Assert.AreEqual("http://odata.org/readstream1", firstEntity.ReadStreamUri.OriginalString, "ReadStreams don't match."); // Verify content/@type by making sure the properties were read Assert.AreEqual(1, firstItem.ID, "IDs don't match."); }); } }
public void AtomParserNavigationLinkTypeTest() { const string atomPayloadTemplate = @"HTTP/1.1 200 OK Content-Type: application/atom+xml <feed xmlns:d='http://docs.oasis-open.org/odata/ns/data' xmlns:m='http://docs.oasis-open.org/odata/ns/metadata' xmlns='http://www.w3.org/2005/Atom'> <title type='text'>ASet</title> <id>http://host/ASet</id> <updated>2010-09-01T23:36:00Z</updated> <link rel='self' title='ASet' href='ASet' /> <entry> <id>http://host/ASet(1)</id> <title type='text'></title> <updated>2010-09-01T23:36:00Z</updated> <author> <name /> </author> <link rel='http://docs.oasis-open.org/odata/ns/related/{0}' title='{0}' href='ASet' type='{1}'>{2}</link> <category term='NamespaceName.EntityA' scheme='http://docs.oasis-open.org/odata/ns/scheme' /> <content type='CustomType/CustomSubType' src='ASet(1)/$value' /> <m:properties> <d:ID m:type='Edm.Int32'>1</d:ID> </m:properties> </entry> </feed>"; var linkTypes = new[] { new { LinkType = "application/atom+xml;type=entry", ExpectedErrorMessage = new Func <bool, bool?, string>((collection, expandedFeed) => { // If the link type is entry: // - For collection property, it must fail since the type must match the model // - If the link is expanded the payload must match the model if (collection && expandedFeed == false) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedEntryInFeedNavigationLink")); } if (collection && expandedFeed == true) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedFeedInEntryNavigationLink")); } if (collection) { return(ODataLibResourceUtil.GetString("ODataAtomReader_DeferredEntryInFeedNavigationLink")); } if (!collection && expandedFeed == true) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedFeedInEntryNavigationLink")); } return(null); }), RecognizedLinkType = true, }, new { LinkType = "application/atom+xml;type=feed", ExpectedErrorMessage = new Func <bool, bool?, string>((collection, expandedFeed) => { // If the link type is feed: // - If the link is not expanded the type must match the model // - If the link is expanded the expanded payload must match the model as well. if (!collection) { return(ODataLibResourceUtil.GetString("ODataAtomReader_FeedNavigationLinkForResourceReferenceProperty", "Singleton")); } if (collection && expandedFeed == false) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedEntryInFeedNavigationLink")); } return(null); }), RecognizedLinkType = true, }, new { LinkType = "application/atom+xml", // Breaking change: we are not recognizing links even when type is missing // If the link has no type, client doesn't recognize this as a nav. prop. ExpectedErrorMessage = new Func <bool, bool?, string>((collection, expandedFeed) => { if (!collection && expandedFeed == true) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedFeedInEntryNavigationLink")); } if (collection && expandedFeed == false) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedEntryInFeedNavigationLink")); } return(null); }), RecognizedLinkType = true, }, new { LinkType = "application/atom+xml;type=test", // Breaking change: we are not recognizing links even when type is wrong // If the link has wrong type, client doesn't recognize this as a nav. prop. ExpectedErrorMessage = new Func <bool, bool?, string>((collection, expandedFeed) => { if (!collection && expandedFeed == true) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedFeedInEntryNavigationLink")); } if (collection && expandedFeed == false) { return(ODataLibResourceUtil.GetString("ODataAtomReader_ExpandedEntryInFeedNavigationLink")); } return(null); }), RecognizedLinkType = true, }, }; string deferredLinkBody = string.Empty; string expandedFeedBody = "<m:inline><feed/></m:inline>"; string expandedEntryBody = "<m:inline><entry><id>http://host/ASet</id></entry></m:inline>"; PlaybackServiceDefinition playbackService = new PlaybackServiceDefinition(); using (TestWebRequest request = playbackService.CreateForInProcessWcf()) { request.ServiceType = typeof(PlaybackService); request.ForceVerboseErrors = true; request.StartService(); TestUtil.RunCombinations( new string[] { "Singleton", "Collection" }, new bool?[] { null, false, true }, linkTypes, (propertyName, expandedFeed, linkType) => { DataServiceContext ctx = new DataServiceContext(request.ServiceRoot); ctx.EnableAtom = true; string linkBody = expandedFeed.HasValue ? (expandedFeed == true ? expandedFeedBody : expandedEntryBody) : deferredLinkBody; string atomPayload = string.Format(atomPayloadTemplate, propertyName, linkType.LinkType, linkBody); playbackService.OverridingPlayback = atomPayload; Exception exception = TestUtil.RunCatching(() => ctx.CreateQuery <EntityWithNavigationProperties>("ASet").AsEnumerable().Count()); string expectedExceptionMessage = linkType.ExpectedErrorMessage(propertyName == "Collection", expandedFeed); if (exception == null) { Assert.IsNull(expectedExceptionMessage, "The test case was expected to fail."); EntityDescriptor entity = ctx.Entities.Single(e => e.Identity == new Uri("http://host/ASet(1)")); if (linkType.RecognizedLinkType) { Assert.AreEqual(ctx.BaseUri + "/ASet", entity.LinkInfos.Single(li => li.Name == propertyName).NavigationLink.OriginalString); } else { Assert.AreEqual(0, entity.LinkInfos.Count, "The link should not have been recognized as a navigation link."); } } else { Assert.IsNotNull(expectedExceptionMessage, "The test case was expected to succeed."); Assert.AreEqual(expectedExceptionMessage, exception.Message, "Unexpected error."); } }); } }