From d918f4cc4aaab680af00affda458e465e287d35f Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Wed, 23 Sep 2020 19:29:52 -0700 Subject: [PATCH 1/7] Potential fix --- .../src/HttpClient/CosmosHttpClientCore.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index a4a4542260..d7d3170270 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -228,6 +228,11 @@ public override Task SendHttpAsync( HttpCompletionOption.ResponseHeadersRead, cancellationToken); + if (responseMessage.RequestMessage == null) + { + responseMessage.RequestMessage = requestMessage; + } + DateTime receivedTimeUtc = DateTime.UtcNow; TimeSpan durationTimeSpan = receivedTimeUtc - sendTimeUtc; From 82cb641be86abb52c51a749b22976a3f0dc766b7 Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 24 Sep 2020 10:56:44 -0700 Subject: [PATCH 2/7] test --- .../GatewayStoreModelTest.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs index 5c2a9f7c4c..5fd896ccad 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs @@ -689,6 +689,31 @@ private async Task GatewayStoreModel_Exceptionless_NotUpdateSessionTokenOnKnownR } } + [TestMethod] + public async Task WhenHttpClientSendAsyncSetsNoRequestMessage() + { + // We don't set the RequestMessage property on purpose on the Failed response + // This will make it go through GatewayStoreClient.CreateDocumentClientExceptionAsync + Func> sendFunc = request => Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)); + + Mock mockDocumentClient = new Mock(); + mockDocumentClient.Setup(client => client.ServiceEndpoint).Returns(new Uri("https://foo")); + GlobalEndpointManager endpointManager = new GlobalEndpointManager(mockDocumentClient.Object, new ConnectionPolicy()); + SessionContainer sessionContainer = new SessionContainer(string.Empty); + DocumentClientEventSource eventSource = DocumentClientEventSource.Instance; + HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); + GatewayStoreModel storeModel = new GatewayStoreModel( + endpointManager, + sessionContainer, + ConsistencyLevel.Eventual, + eventSource, + null, + MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler))); + + DocumentServiceRequest documentServiceRequest = new DocumentServiceRequest(OperationType.Read, ResourceType.Database, "/dbs/test", body: null, AuthorizationTokenType.PrimaryMasterKey, null); + await storeModel.ProcessMessageAsync(documentServiceRequest); + } + private class MockMessageHandler : HttpMessageHandler { private readonly Func> sendFunc; From 8ea1c2583b848de5f3e2e3dc94e22087e3863590 Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 24 Sep 2020 11:07:09 -0700 Subject: [PATCH 3/7] comment --- Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index d7d3170270..b14aff4d6c 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -228,6 +228,7 @@ public override Task SendHttpAsync( HttpCompletionOption.ResponseHeadersRead, cancellationToken); + // WebAssembly HttpClient does not set the RequestMessage property on SendAsync if (responseMessage.RequestMessage == null) { responseMessage.RequestMessage = requestMessage; From 0622b2f015062e7dab261a642e7f7eb31baf0c1d Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 24 Sep 2020 11:24:34 -0700 Subject: [PATCH 4/7] missing expectedexception --- .../GatewayStoreModelTest.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs index 5fd896ccad..3b00bb3ee5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs @@ -690,11 +690,23 @@ private async Task GatewayStoreModel_Exceptionless_NotUpdateSessionTokenOnKnownR } [TestMethod] + [ExpectedException(typeof(DocumentClientException))] public async Task WhenHttpClientSendAsyncSetsNoRequestMessage() { + Guid previousActivityId = Trace.CorrelationManager.ActivityId; + Guid testActivityId = Guid.NewGuid(); + Trace.CorrelationManager.ActivityId = testActivityId; // We don't set the RequestMessage property on purpose on the Failed response // This will make it go through GatewayStoreClient.CreateDocumentClientExceptionAsync - Func> sendFunc = request => Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)); + Func> sendFunc = request => + { + HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NotFound) + { + Content = new StringContent("test") + }; + + return Task.FromResult(response); + }; Mock mockDocumentClient = new Mock(); mockDocumentClient.Setup(client => client.ServiceEndpoint).Returns(new Uri("https://foo")); @@ -712,6 +724,7 @@ public async Task WhenHttpClientSendAsyncSetsNoRequestMessage() DocumentServiceRequest documentServiceRequest = new DocumentServiceRequest(OperationType.Read, ResourceType.Database, "/dbs/test", body: null, AuthorizationTokenType.PrimaryMasterKey, null); await storeModel.ProcessMessageAsync(documentServiceRequest); + Trace.CorrelationManager.ActivityId = previousActivityId; } private class MockMessageHandler : HttpMessageHandler From aec0639090cde74495be2eb54bd32678469315b1 Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 24 Sep 2020 20:07:18 -0700 Subject: [PATCH 5/7] Moving test --- .../CosmosHttpClientCoreTests.cs | 66 +++++++++++++++++++ .../GatewayStoreModelTest.cs | 38 ----------- 2 files changed, 66 insertions(+), 38 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs new file mode 100644 index 0000000000..1c5f3d49c1 --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tests +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Microsoft.Azure.Documents; + using Microsoft.Azure.Documents.Collections; + using Microsoft.Azure.Cosmos.Core.Trace; + using Microsoft.Azure.Cosmos.Tests; + using System; + using System.Net.Http; + using System.Net; + using System.Diagnostics; + using System.Threading; + + [TestClass] + public class CosmosHttpClientCoreTests + { + [TestMethod] + public async Task ResponseMessageHasRequestMessageAsync() + { + Guid previousActivityId = Trace.CorrelationManager.ActivityId; + Guid testActivityId = Guid.NewGuid(); + Trace.CorrelationManager.ActivityId = testActivityId; + // We don't set the RequestMessage property on purpose on the Failed response + // This will make it go through GatewayStoreClient.CreateDocumentClientExceptionAsync + Func> sendFunc = request => + { + HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NotFound) + { + Content = new StringContent("test") + }; + return Task.FromResult(response); + }; + + DocumentClientEventSource eventSource = DocumentClientEventSource.Instance; + HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); + CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); + + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri("http://localhost")); + + DocumentServiceRequest documentServiceRequest = new DocumentServiceRequest(OperationType.Read, ResourceType.Database, "/dbs/test", body: null, AuthorizationTokenType.PrimaryMasterKey, null); + HttpResponseMessage responseMessage = await cosmoshttpClient.SendHttpAsync(() => new ValueTask(httpRequestMessage), ResourceType.Collection, null, default); + + Assert.AreEqual(httpRequestMessage, responseMessage.RequestMessage); + } + + private class MockMessageHandler : HttpMessageHandler + { + private readonly Func> sendFunc; + public MockMessageHandler(Func> func) + { + this.sendFunc = func; + } + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await this.sendFunc(request); + } + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs index 3b00bb3ee5..5c2a9f7c4c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs @@ -689,44 +689,6 @@ private async Task GatewayStoreModel_Exceptionless_NotUpdateSessionTokenOnKnownR } } - [TestMethod] - [ExpectedException(typeof(DocumentClientException))] - public async Task WhenHttpClientSendAsyncSetsNoRequestMessage() - { - Guid previousActivityId = Trace.CorrelationManager.ActivityId; - Guid testActivityId = Guid.NewGuid(); - Trace.CorrelationManager.ActivityId = testActivityId; - // We don't set the RequestMessage property on purpose on the Failed response - // This will make it go through GatewayStoreClient.CreateDocumentClientExceptionAsync - Func> sendFunc = request => - { - HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NotFound) - { - Content = new StringContent("test") - }; - - return Task.FromResult(response); - }; - - Mock mockDocumentClient = new Mock(); - mockDocumentClient.Setup(client => client.ServiceEndpoint).Returns(new Uri("https://foo")); - GlobalEndpointManager endpointManager = new GlobalEndpointManager(mockDocumentClient.Object, new ConnectionPolicy()); - SessionContainer sessionContainer = new SessionContainer(string.Empty); - DocumentClientEventSource eventSource = DocumentClientEventSource.Instance; - HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); - GatewayStoreModel storeModel = new GatewayStoreModel( - endpointManager, - sessionContainer, - ConsistencyLevel.Eventual, - eventSource, - null, - MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler))); - - DocumentServiceRequest documentServiceRequest = new DocumentServiceRequest(OperationType.Read, ResourceType.Database, "/dbs/test", body: null, AuthorizationTokenType.PrimaryMasterKey, null); - await storeModel.ProcessMessageAsync(documentServiceRequest); - Trace.CorrelationManager.ActivityId = previousActivityId; - } - private class MockMessageHandler : HttpMessageHandler { private readonly Func> sendFunc; From 54ddb5499a9055e12d1a8191e60cfeede973c7bb Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 24 Sep 2020 20:09:12 -0700 Subject: [PATCH 6/7] Removing variable --- .../Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 1c5f3d49c1..cc13a25247 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -44,7 +44,6 @@ public async Task ResponseMessageHasRequestMessageAsync() HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri("http://localhost")); - DocumentServiceRequest documentServiceRequest = new DocumentServiceRequest(OperationType.Read, ResourceType.Database, "/dbs/test", body: null, AuthorizationTokenType.PrimaryMasterKey, null); HttpResponseMessage responseMessage = await cosmoshttpClient.SendHttpAsync(() => new ValueTask(httpRequestMessage), ResourceType.Collection, null, default); Assert.AreEqual(httpRequestMessage, responseMessage.RequestMessage); From d009843ce2ba1059607455ef6e0faf2002ad130f Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 24 Sep 2020 20:09:45 -0700 Subject: [PATCH 7/7] cleaning up --- .../CosmosHttpClientCoreTests.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index cc13a25247..cf3fc2b668 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -4,18 +4,12 @@ namespace Microsoft.Azure.Cosmos.Tests { - using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; using Microsoft.Azure.Documents; - using Microsoft.Azure.Documents.Collections; - using Microsoft.Azure.Cosmos.Core.Trace; - using Microsoft.Azure.Cosmos.Tests; using System; using System.Net.Http; using System.Net; - using System.Diagnostics; using System.Threading; [TestClass] @@ -24,9 +18,6 @@ public class CosmosHttpClientCoreTests [TestMethod] public async Task ResponseMessageHasRequestMessageAsync() { - Guid previousActivityId = Trace.CorrelationManager.ActivityId; - Guid testActivityId = Guid.NewGuid(); - Trace.CorrelationManager.ActivityId = testActivityId; // We don't set the RequestMessage property on purpose on the Failed response // This will make it go through GatewayStoreClient.CreateDocumentClientExceptionAsync Func> sendFunc = request =>