public void PreferHeader_UnrelatedRequests() { DSPMetadata metadata = PreferHeader_CreateMetadata(); var item = new DSPSelfmodifyingResource(metadata.GetResourceType("Item")); item.SetRawValue("ID", 0); item.SetRawValue("ETagProperty", 0); item.SetRawValue("Self", item); var collection = new DSPResource(metadata.GetResourceType("Collection")); collection.SetRawValue("ID", 0); collection.SetRawValue("CollectionProperty", new List<int>() { 1, 2, 3 }); var stream = new DSPSelfmodifyingResource(metadata.GetResourceType("Stream")); stream.SetRawValue("ID", 42); var namedStream = new DSPSelfmodifyingResource(metadata.GetResourceType("NamedStream")); namedStream.SetRawValue("ID", 42); DSPServiceDefinition service = PreferHeader_CreateService(metadata, item, collection, stream, namedStream); service.DataServiceBehavior.MaxProtocolVersion = ODataProtocolVersion.V4; var entityReferencePayload = new XElement(UnitTestsUtil.MetadataNamespace + "ref"); entityReferencePayload.SetAttributeValue("id", "/Items(0)"); var testCases = new[] { new { HttpMethod = "GET", RequestUri = "/Items", Payload = "", ContentType = "" }, new { HttpMethod = "GET", RequestUri = "/Collection", Payload = "", ContentType = "" }, new { HttpMethod = "GET", RequestUri = "/$metadata", Payload = "", ContentType = "" }, new { HttpMethod = "GET", RequestUri = "/Items/$count", Payload = "", ContentType = "" }, new { HttpMethod = "GET", RequestUri = "/Items(0)/Self/$ref", Payload = "", ContentType = "" }, new { HttpMethod = "DELETE", RequestUri = "/Collection(0)/Description/$value", Payload = "", ContentType = "" }, new { HttpMethod = "PUT", RequestUri = "/Items(0)/Self/$ref", Payload = entityReferencePayload.ToString(), ContentType = UnitTestsUtil.MimeApplicationXml }, new { // GET MR HttpMethod = "GET", RequestUri = "/Streams(42)/$value", Payload = "", ContentType = "" }, new { // GET named stream HttpMethod = "GET", RequestUri = "/NamedStreams(42)/NamedStream1", Payload = "", ContentType = "" }, new { // PUT named stream HttpMethod = "PUT", RequestUri = "/NamedStreams(42)/NamedStream1", Payload = "another text file", ContentType = UnitTestsUtil.MimeTextPlain }, }; using (TestWebRequest request = service.CreateForInProcess()) { TestUtil.RunCombinations( testCases, new string[] { null, "return=representation", "return=minimal" }, (testCase, preferHeader) => { service.ClearChanges(); request.HttpMethod = testCase.HttpMethod; request.RequestUriString = testCase.RequestUri; request.RequestHeaders["Prefer"] = preferHeader; request.RequestVersion = "4.0;"; request.RequestMaxVersion = "4.0;"; request.RequestContentType = string.IsNullOrEmpty(testCase.ContentType) ? null : testCase.ContentType; string payload = testCase.Payload; if (!string.IsNullOrEmpty(payload) && payload.StartsWith("[")) { int i = payload.IndexOf("]"); string header = payload.Substring(1, i - 1); string[] headervalue = header.Split(':'); request.RequestHeaders[headervalue[0]] = headervalue[1]; payload = payload.Substring(i + 1); } if (!string.IsNullOrEmpty(payload)) { request.SetRequestStreamAsText(payload); } request.SendRequest(); string preferApplied; request.ResponseHeaders.TryGetValue("Preference-Applied", out preferApplied); Assert.IsNull(preferApplied, "No Preference-Applied header should be present on the response."); }); } }
public void ItemsChangeInterceptor(DSPSelfmodifyingResource resource, UpdateOperations operation) { LastItemsUpdateOperation = operation; }
public void PreferHeader_CrossFeature() { DSPMetadata metadata = PreferHeader_CreateMetadata(); DSPSelfmodifyingResource existingItem = new DSPSelfmodifyingResource(metadata.GetResourceType("Item")); existingItem.SetRawValue("ID", 0); existingItem.SetRawValue("ETagProperty", 1); DSPServiceDefinition service = PreferHeader_CreateService(metadata, existingItem, null, null, null); ProcessingPipelineCallCount callCount = new ProcessingPipelineCallCount(); service.ProcessingPipeline.ProcessingRequest += (sender, args) => { callCount.ProcessingRequestCallCount++; }; service.ProcessingPipeline.ProcessedRequest += (sender, args) => { callCount.ProcessedRequestCallCount++; }; service.ProcessingPipeline.ProcessingChangeset += (sender, args) => { callCount.ProcessingChangesetCallCount++; }; service.ProcessingPipeline.ProcessedChangeset += (sender, args) => { callCount.ProcessedChangesetCallCount++; }; service.DataServiceType = typeof(PreferHeader_InterceptorsService); ProcessingPipelineCallCount expectedCallCount = new ProcessingPipelineCallCount() { ProcessingRequestCallCount = 1, ProcessedRequestCallCount = 1, ProcessingChangesetCallCount = 1, ProcessedChangesetCallCount = 1 }; // Can't get the payload from the service since we sometimes don't allow read rights XDocument existingItemAtom = XDocument.Parse("<entry 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'>" + "<id>http://host/Items(0)</id>" + "<title type='text'></title>" + "<updated>2010-07-19T14:20:32Z</updated>" + "<author><name /></author>" + "<category term='TestNS.Item' scheme='http://docs.oasis-open.org/odata/ns/scheme' />" + "<content type='application/xml'><m:properties>" + "<d:ID m:type='Edm.Int32'>0</d:ID>" + "<d:ETagProperty m:type='Edm.Int32'>1</d:ETagProperty>" + "</m:properties></content></entry>"); TestUtil.RunCombinations( UnitTestsUtil.BooleanValues, UnitTestsUtil.BooleanValues, (includeRelationshipLinks, allowReadAccess) => { service.DataServiceBehavior.IncludeRelationshipLinksInResponse = includeRelationshipLinks; service.EntitySetAccessRule = new Dictionary<string,EntitySetRights>() { {"Items", EntitySetRights.AllWrite | (allowReadAccess ? EntitySetRights.AllRead : EntitySetRights.None)} }; using (TestWebRequest request = service.CreateForInProcess()) { request.RegisterForDispose(PreferHeader_InterceptorsService.InterceptItems.Restore()); TestUtil.RunCombinations( new string[] { "POST", "PUT", "PATCH" }, new string[] { null, "return=representation", "return=minimal" }, new string[] { UnitTestsUtil.AtomFormat }, UnitTestsUtil.BooleanValues, UnitTestsUtil.BooleanValues, (httpMethod, preferHeader, format, batch, interceptItems) => { PreferHeader_InterceptorsService.InterceptItems.Value = interceptItems; PreferHeader_InterceptorsService.LastItemsUpdateOperation = UpdateOperations.None; PreferHeader_InterceptorsService.ItemsQueryInterceptorInvoked = false; service.ClearChanges(); callCount.Clear(); TestWebRequest r = request; if (batch) { r = new InMemoryWebRequest(); } r.RequestVersion = "4.0;"; r.RequestMaxVersion = "4.0;"; r.RequestHeaders["Prefer"] = preferHeader; PreferHeader_SetupRequest(r, httpMethod, format, existingItemAtom, existingItem, null); if (batch) { var batchRequest = new BatchWebRequest(); var changeset = new BatchWebRequest.Changeset(); changeset.Parts.Add((InMemoryWebRequest)r); batchRequest.Changesets.Add(changeset); batchRequest.SendRequest(request); } else { TestUtil.RunCatching(request.SendRequest); } Assert.AreEqual(httpMethod != "POST", PreferHeader_InterceptorsService.ItemsQueryInterceptorInvoked, "The query interceptor fire or didn't fire when it should have."); if (!allowReadAccess && httpMethod != "POST") { Assert.AreEqual(403, r.ResponseStatusCode, "The request should have failed due to access rights."); } else if (interceptItems && httpMethod != "POST") { Assert.AreEqual(404, r.ResponseStatusCode, "The request should not have found any resource."); } else { PreferHeader_VerifyResponse(r, request.ServiceRoot.ToString(), true, (response) => { var relationshipLinks = response.Root.Elements(UnitTestsUtil.AtomNamespace + "link") .Where(e => e.Attribute("rel").Value.Contains("http://docs.oasis-open.org/odata/ns/relatedlinks/")); if (includeRelationshipLinks) { Assert.AreEqual(1, relationshipLinks.Count(), "The response should contain a relationship link."); } else { Assert.AreEqual(0, relationshipLinks.Count(), "The resounrce should not contain any relationship links."); } }); callCount.AssertEquals(expectedCallCount); Assert.AreEqual(httpMethod == "POST" ? UpdateOperations.Add : UpdateOperations.Change, PreferHeader_InterceptorsService.LastItemsUpdateOperation, "The change interceptor didn't fire correctly."); } }); } }); }
public void PreferHeader_Server() { DSPMetadata metadata = PreferHeader_CreateMetadata(); TestUtil.RunCombinations( new[] { typeof(IDataServiceHost), typeof(IDataServiceHost2) }, new[] { ODataProtocolVersion.V4 }, (hostInterfaceType, maxProtocolVersion) => { DSPSelfmodifyingResource existingItem = new DSPSelfmodifyingResource(metadata.GetResourceType("Item")); existingItem.SetRawValue("ID", 0); existingItem.SetRawValue("ETagProperty", 1); DSPSelfmodifyingResource existingStream = new DSPSelfmodifyingResource(metadata.GetResourceType("Stream")); existingStream.SetRawValue("ID", 0); existingStream.SetRawValue("ETagProperty", 1); bool supportsMR = hostInterfaceType != typeof(IDataServiceHost); DSPServiceDefinition service = this.PreferHeader_CreateService(metadata, existingItem, null, existingStream, null); service.HostInterfaceType = hostInterfaceType; service.DataServiceBehavior.MaxProtocolVersion = maxProtocolVersion; using (TestWebRequest request = service.CreateForInProcess()) { XDocument existingItemAtom = UnitTestsUtil.GetResponseAsAtomXLinq(request, "/Items(0)", "application/atom+xml,application/xml"); XDocument existingStreamAtom = !supportsMR ? null : UnitTestsUtil.GetResponseAsAtomXLinq(request, "/Streams(0)", "application/atom+xml,application/xml"); IEnumerable<string> httpMethods = new string[] { "POST", "POSTMR", "PUT", "PATCH" }; TestUtil.RunCombinations( new string[] { null, "return=representation", "return=minimal", "ReTURN=RePrESenTaTioN", "foo" }, httpMethods, new string[] { UnitTestsUtil.AtomFormat }, (preferHeader, httpMethod, format) => { // Skip MR verification since we use MRs in that entity and as such the request would not work without support on the server if (httpMethod == "POSTMR" && !supportsMR) { return; } service.ClearChanges(); request.RequestVersion = "4.0;"; request.RequestMaxVersion = "4.0;"; request.Accept = "application/atom+xml,application/xml"; request.RequestHeaders["Prefer"] = preferHeader; XDocument existingAtom = httpMethod == "POSTMR" ? existingStreamAtom : existingItemAtom; DSPSelfmodifyingResource existingResource = httpMethod == "POSTMR" ? existingStream : existingItem; this.PreferHeader_SetupRequest(request, httpMethod, format, existingAtom, existingResource, (inputAtom) => { var triggerModification = inputAtom.Root.Descendants(UnitTestsUtil.MetadataNamespace + "properties").First().Element(UnitTestsUtil.DataNamespace + "TriggerModification"); triggerModification.Attributes(UnitTestsUtil.MetadataNamespace + "null").Remove(); triggerModification.Value = "trigger" + existingItem.GetETag().Replace('"', '_'); }); bool serviceAllowsPreferHeader = hostInterfaceType == typeof(IDataServiceHost2); bool? effectiveResponsePreference; this.PreferHeader_ShouldContainResponseBody(request, serviceAllowsPreferHeader, out effectiveResponsePreference); TestUtil.RunCatching(request.SendRequest); DSPSelfmodifyingResource returnedItem; if (httpMethod == "POST" || httpMethod == "POSTMR") { returnedItem = service.CurrentDataSource.GetResourceSetEntities(httpMethod == "POSTMR" ? "Streams" : "Items").OfType<DSPSelfmodifyingResource>().First(r => (int)r.GetValue("ID") == 1); } else { returnedItem = existingResource; } this.PreferHeader_VerifyResponse(request, request.ServiceRoot.ToString(), serviceAllowsPreferHeader, (response) => { if (httpMethod != "POSTMR") // with POST MR the ETagProperty will not be updated since the payload didn't set any properties (it's just the stream) { string etagPropertyValue = returnedItem.GetValue("ETagProperty").ToString(); XElement etagPropertyElement = response.Root.Descendants(UnitTestsUtil.MetadataNamespace + "properties").First().Element(UnitTestsUtil.DataNamespace + "ETagProperty"); Assert.AreEqual(etagPropertyValue, etagPropertyElement.Value, "The updated value was not included in the response."); } }); Assert.AreEqual(returnedItem.GetETag(), request.ResponseETag, "The response ETag does not match the current ETag value on the server."); }); } }); }