From a96d32febdd3b3e91b691cdfda5157f74612f2be Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Fri, 27 Sep 2019 14:33:02 -0700 Subject: [PATCH] Statistics not getting populated correctly on CosmosException (#846) * Adding ToString * Adding test * Changelog * Changing serialization * Making test more robust * Fix test * Partition key * Using session consistency --- .../CosmosClientSideRequestStatistics.cs | 28 ++++++++++--- .../CosmosItemTests.cs | 39 +++++++++++++++++++ changelog.md | 1 + 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/CosmosClientSideRequestStatistics.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/CosmosClientSideRequestStatistics.cs index 28845c463c..65f7190969 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/CosmosClientSideRequestStatistics.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/CosmosClientSideRequestStatistics.cs @@ -13,6 +13,11 @@ namespace Microsoft.Azure.Cosmos internal sealed class CosmosClientSideRequestStatistics : IClientSideRequestStatistics { + private static JsonSerializerSettings SerializerSettings = new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }; internal const int MaxSupplementalRequestsForToString = 10; internal DateTime requestStartTime; @@ -20,15 +25,12 @@ internal sealed class CosmosClientSideRequestStatistics : IClientSideRequestStat private object lockObject = new object(); - internal List responseStatisticsList; - internal List supplementalResponseStatisticsList; - internal Dictionary addressResolutionStatistics; + public List responseStatisticsList { get; private set; } + public List supplementalResponseStatisticsList { get; internal set; } + public Dictionary addressResolutionStatistics { get; private set; } - [JsonIgnoreAttribute] public List ContactedReplicas { get; set; } - [JsonIgnoreAttribute] public HashSet FailedReplicas { get; private set; } - [JsonIgnoreAttribute] public HashSet RegionsContacted { get; private set; } public CosmosClientSideRequestStatistics() @@ -150,6 +152,20 @@ public void RecordAddressResolutionEnd(string identifier) } } + public override string ToString() + { + if (this.supplementalResponseStatisticsList != null) + { + int supplementalResponseStatisticsListCount = this.supplementalResponseStatisticsList.Count; + int countToRemove = Math.Max(supplementalResponseStatisticsListCount - CosmosClientSideRequestStatistics.MaxSupplementalRequestsForToString, 0); + if (countToRemove > 0) + { + this.supplementalResponseStatisticsList.RemoveRange(0, countToRemove); + } + } + return JsonConvert.SerializeObject(this, CosmosClientSideRequestStatistics.SerializerSettings); + } + internal struct StoreResponseStatistics { public DateTime RequestResponseTime; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs index f3fdb446c4..346a0983ba 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -1533,6 +1533,45 @@ public async Task VerifySessionTokenPassThrough() Assert.AreEqual(sessionToken, readResponse.Headers.Session); } + [TestMethod] + public async Task VerifySessionNotFoundStatistics() + { + CosmosClient cosmosClient = TestCommon.CreateCosmosClient(new CosmosClientOptions() { ConsistencyLevel = Cosmos.ConsistencyLevel.Session }); + DatabaseResponse database = await cosmosClient.CreateDatabaseIfNotExistsAsync("NoSession"); + Container container = await database.Database.CreateContainerIfNotExistsAsync("NoSession", "/status"); + + try + { + ToDoActivity temp = ToDoActivity.CreateRandomToDoActivity("TBD"); + + ItemResponse responseAstype = await container.CreateItemAsync(partitionKey: new Cosmos.PartitionKey(temp.status), item: temp); + + string invalidSessionToken = this.GetDifferentLSNToken(responseAstype.Headers.Session, 2000); + + try + { + ItemResponse readResponse = await container.ReadItemAsync(temp.id, new Cosmos.PartitionKey(temp.status), new ItemRequestOptions() { SessionToken = invalidSessionToken }); + Assert.Fail("Should had thrown ReadSessionNotAvailable"); + } + catch (CosmosException cosmosException) + { + Assert.IsTrue(cosmosException.Message.Contains("ContactedReplicas"), cosmosException.Message); + } + } + finally + { + await database.Database.DeleteAsync(); + } + } + + private string GetDifferentLSNToken(string token, long lsnDifferent) + { + string[] tokenParts = token.Split(':'); + ISessionToken sessionToken = SessionTokenHelper.Parse(tokenParts[1]); + ISessionToken differentSessionToken = TestCommon.CreateSessionToken(sessionToken, sessionToken.LSN + lsnDifferent); + return string.Format(CultureInfo.InvariantCulture, "{0}:{1}", tokenParts[0], differentSessionToken.ConvertToString()); + } + /// /// Stateless container re-create test. /// Create two client instances and do meta data operations through a single client diff --git a/changelog.md b/changelog.md index 52f7b21252..bc7bf14fc8 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - [#835](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/835) Fixed a bug that caused sortedRanges exceptions +- [#846](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/846) Statistics not getting populated correctly on CosmosException. ## [3.2.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.2.0) - 2019-09-17