/// <summary>Writes the batch as a response into an in-memory request (sets up properties and such).</summary> /// <param name="request">The request to apply the batch as a response to.</param> public void WriteResponse(InMemoryWebRequest request) { request.SetResponseStatusCode(200); string boundary = "boundary_" + Guid.NewGuid().ToString(); request.ResponseHeaders["Content-Type"] = String.Format("{0}; boundary={1}", UnitTestsUtil.MimeMultipartMixed, boundary); request.SetResponseStream(this.CreateBatchContent(true, boundary)); }
/// <summary>Creates the in-memory response from another TestWebRequest, copying its reponse.</summary> /// <param name="sourceResponse">The request to read the response from.</param> /// <returns>The newly create request object with the response proeprties filled with the data from the request response.</returns> public static InMemoryWebRequest FromResponse(TestWebRequest sourceResponse) { InMemoryWebRequest response = new InMemoryWebRequest(); response.SetResponseStatusCode(sourceResponse.ResponseStatusCode); foreach (var header in GetAllResponseHeaders(sourceResponse)) { response.ResponseHeaders[header.Key] = header.Value; } using (Stream responseStream = sourceResponse.GetResponseStream()) { response.SetResponseStream(responseStream); } return response; }
/// <summary>Creates the in-memory response from another TestWebRequest, copying its reponse.</summary> /// <param name="sourceResponse">The request to read the response from.</param> /// <returns>The newly create request object with the response proeprties filled with the data from the request response.</returns> public static InMemoryWebRequest FromResponse(TestWebRequest sourceResponse) { InMemoryWebRequest response = new InMemoryWebRequest(); response.SetResponseStatusCode(sourceResponse.ResponseStatusCode); foreach (var header in GetAllResponseHeaders(sourceResponse)) { response.ResponseHeaders[header.Key] = header.Value; } using (Stream responseStream = sourceResponse.GetResponseStream()) { response.SetResponseStream(responseStream); } return(response); }
public InMemoryWebRequest ProcessRequestOverride(InMemoryWebRequest request) { if (IsTextPayloadType(request.RequestContentType)) { string payload = ReplaceUriOccurences( this.playbackServiceBaseUri, this.underlyingServiceBaseUri, new StreamReader(request.GetRequestStream()).ReadToEnd()); // Remove all Content-Length headers (if it's a batch since we just changed the length of the requests by replacing strings) StringBuilder sb = new StringBuilder(); TextReader reader = new StringReader(payload); string line; while ((line = reader.ReadLine()) != null) { if (!line.StartsWith("Content-Length")) { sb.AppendLine(line); } } request.SetRequestStreamAsText(sb.ToString()); } // Copy the request to the server request request.WriteRequest(this.underlyingService); // Send the request try { this.underlyingService.SendRequest(); // Copy the response to our in-memory representation var response = InMemoryWebRequest.FromResponse(this.underlyingService); if (IsTextPayloadType(response.ResponseContentType)) { response.SetResponseStreamAsText( ReplaceUriOccurences( this.underlyingServiceBaseUri, this.playbackServiceBaseUri, response.GetResponseStreamAsText())); } var headersToReplace = new string[] { "Location", "OData-EntityId" }; foreach (var headerName in headersToReplace) { string value; if (response.ResponseHeaders.TryGetValue(headerName, out value)) { response.ResponseHeaders[headerName] = ReplaceUriOccurences( this.underlyingServiceBaseUri, this.playbackServiceBaseUri, value); } } return(response); } catch (Exception exception) { // Translate everything into a 500, it's easier and we don't need correct error reporting on the client anyway (for versioning tests) var response = new InMemoryWebRequest(); response.SetResponseStatusCode(500); response.ResponseHeaders["Content-Type"] = UnitTestsUtil.MimeTextPlain; response.SetResponseStreamAsText(exception.ToString()); return(response); } }
public InMemoryWebRequest ProcessRequestOverride(InMemoryWebRequest request) { if (IsTextPayloadType(request.RequestContentType)) { string payload = ReplaceUriOccurences( this.playbackServiceBaseUri, this.underlyingServiceBaseUri, new StreamReader(request.GetRequestStream()).ReadToEnd()); // Remove all Content-Length headers (if it's a batch since we just changed the length of the requests by replacing strings) StringBuilder sb = new StringBuilder(); TextReader reader = new StringReader(payload); string line; while((line = reader.ReadLine()) != null) { if (!line.StartsWith("Content-Length")) sb.AppendLine(line); } request.SetRequestStreamAsText(sb.ToString()); } // Copy the request to the server request request.WriteRequest(this.underlyingService); // Send the request try { this.underlyingService.SendRequest(); // Copy the response to our in-memory representation var response = InMemoryWebRequest.FromResponse(this.underlyingService); if (IsTextPayloadType(response.ResponseContentType)) { response.SetResponseStreamAsText( ReplaceUriOccurences( this.underlyingServiceBaseUri, this.playbackServiceBaseUri, response.GetResponseStreamAsText())); } var headersToReplace = new string[] { "Location", "OData-EntityId" }; foreach (var headerName in headersToReplace) { string value; if (response.ResponseHeaders.TryGetValue(headerName, out value)) { response.ResponseHeaders[headerName] = ReplaceUriOccurences( this.underlyingServiceBaseUri, this.playbackServiceBaseUri, value); } } return response; } catch (Exception exception) { // Translate everything into a 500, it's easier and we don't need correct error reporting on the client anyway (for versioning tests) var response = new InMemoryWebRequest(); response.SetResponseStatusCode(500); response.ResponseHeaders["Content-Type"] = UnitTestsUtil.MimeTextPlain; response.SetResponseStreamAsText(exception.ToString()); return response; } }
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."); } } }); }