private static void ExecuteUpdate(DSPResource resource, int id, TestWebRequest baseRequest, string httpMethod, string preferHeader, bool useBatch, DSPResourceSerializerFormat payloadFormat) { string payload = DSPResourceSerializer.WriteEntity(resource, payloadFormat); bool isPost = httpMethod == "POST"; bool expectedReturnContent = preferHeader == "return=representation" || isPost && preferHeader == null; string uriSuffix = isPost ? String.Empty : String.Format("({0})", id); TestWebRequest request = useBatch ? new InMemoryWebRequest() : baseRequest; request.RequestUriString = String.Format("/{0}s{1}", resource.ResourceType.Name, uriSuffix); request.HttpMethod = httpMethod; request.RequestVersion = "4.0;"; request.RequestMaxVersion = "4.0;"; request.RequestHeaders["Prefer"] = preferHeader; request.Accept = payloadFormat == DSPResourceSerializerFormat.Atom ? "application/atom+xml,application/xml" : UnitTestsUtil.JsonLightMimeType; request.RequestContentType = "application/atom+xml"; request.SetRequestStreamAsText(payload); if (useBatch) { var batchRequest = new BatchWebRequest(); var changeset = new BatchWebRequest.Changeset(); changeset.Parts.Add((InMemoryWebRequest)request); batchRequest.Changesets.Add(changeset); batchRequest.SendRequest(baseRequest); Assert.IsTrue(UnitTestsUtil.IsSuccessStatusCode(baseRequest.ResponseStatusCode), "Unexpected error occurred on batch."); } else { request.SendRequest(); } Assert.IsTrue(UnitTestsUtil.IsSuccessStatusCode(request.ResponseStatusCode), "Unexpected error occurred when sending the request."); if (expectedReturnContent) { // If the request is expected to return content, verify there were no instream errors Exception e = request.ParseResponseInStreamError(); string errorMessage = e != null ? e.Message : string.Empty; Assert.IsNull(e, "Expected no exception, but got the following error", errorMessage); } }
private void ParseBatchContent(Stream contentStream, string contentType, bool isResponse, bool matchToExisting) { int partIndex = 0; int changesetIndex = 0; if (!matchToExisting) { this.changesets = new List <Changeset>(); this.parts = new List <InMemoryWebRequest>(); } MemoryStream memoryStream = new MemoryStream(); // Create a copy since StreamReader will Close the stream, which might not be what we want TestUtil.CopyStream(contentStream, memoryStream); memoryStream.Position = 0; using (TextReader reader = new StreamReader(memoryStream)) { Assert.IsTrue(contentType.StartsWith("multipart/mixed; "), "Response is not a batch response. Expecting 'multipart.mixed', got '" + contentType + "'."); string boundary = "--" + contentType.Substring(contentType.IndexOf("; boundary=") + 11).Trim(); string endboundary = boundary + "--"; string line; while ((line = reader.ReadLine()) != null) { if (line == boundary) { break; } if (line == endboundary) { Assert.IsTrue(partIndex == this.parts.Count, "The response didn't contain enough parts."); return; } } while (true) { line = reader.ReadLine(); // Content-Type Assert.IsTrue(line.StartsWith("Content-Type:"), "The batch part doesn't specify its content type."); contentType = line.Substring("Content-Type:".Length).Trim(); if (contentType.StartsWith("multipart/mixed; ")) { string changesetBoundary = "--" + contentType.Substring(contentType.IndexOf("; boundary=") + 11).Trim(); string changesetEndBoundary = changesetBoundary + "--"; int cpartIndex = 0; Changeset changeset; if (matchToExisting) { Assert.IsTrue(this.changesets.Count > changesetIndex, "The batch response contains more changesets than the number of changesets sent."); changeset = this.changesets[changesetIndex]; } else { changeset = new Changeset(); this.changesets.Add(changeset); } changesetIndex++; while ((line = reader.ReadLine()) != null) { if (line.Trim().Length == 0) { break; } } while ((line = reader.ReadLine()) != null) { if (line == changesetBoundary) { break; } if (line == changesetEndBoundary) { goto ChangesetEnd; } } while (true) { reader.ReadLine(); // Content-Type reader.ReadLine(); // Content-Transfer-Encoding InMemoryWebRequest part; if (matchToExisting) { Assert.IsTrue(changeset.Parts.Count > cpartIndex, "The batch response contains more parts than the number of request parts sent."); part = changeset.Parts[cpartIndex]; } else { part = new InMemoryWebRequest(); changeset.Parts.Add(part); } line = reader.ReadLine(); if (!string.IsNullOrEmpty(line)) { part.RequestHeaders["Content-ID"] = line.Split(' ')[1]; reader.ReadLine(); } cpartIndex++; if (ParseBatchPart(isResponse, reader, part, changesetBoundary, changesetEndBoundary)) { break; } } ChangesetEnd: if (cpartIndex < changeset.Parts.Count) { int lastStatusCode = changeset.Parts[cpartIndex - 1].ResponseStatusCode; if (!UnitTestsUtil.IsSuccessStatusCode(lastStatusCode)) { for (; cpartIndex < changeset.Parts.Count; cpartIndex++) { changeset.Parts[cpartIndex].SetResponseStatusCode(lastStatusCode); } } } Assert.IsTrue(cpartIndex == changeset.Parts.Count, "The response didn't contain enough parts."); ; while (true) { line = reader.ReadLine(); if (line == boundary) { break; } // We can hit another exception after the changeset. For example if the changeset fails // and after the server serializes out the error for the changeset, writes the endboundary // for the changeset, and call IUpdatable.ClearChanges(), ClearChanges() can throw. // When that happens we will see the second error but there won't be any boundary after it. // We need to goto End when we either see the end boundary or reached the end of stream. if (line == null || line == endboundary) { goto End; } } } else { Assert.IsTrue(contentType.StartsWith("application/http"), "Batch part is neither changeset nor HTTP."); reader.ReadLine(); // Content-Transfer-Encoding reader.ReadLine(); // InMemoryWebRequest part; if (matchToExisting) { Assert.IsTrue(this.parts.Count > partIndex, "The batch response contains more parts than the number of request parts sent."); part = this.parts[partIndex]; partIndex++; } else { part = new InMemoryWebRequest(); this.parts.Add(part); partIndex++; } if (ParseBatchPart(isResponse, reader, part, boundary, endboundary)) { goto End; } } } End: Assert.IsTrue(partIndex == this.parts.Count, "The response didn't contain enough parts."); Assert.IsTrue(changesetIndex == this.changesets.Count, "The response didn't contain enough parts."); } }