From 1e2bc8f636a59fb93f8c45ade9c519cee8a14666 Mon Sep 17 00:00:00 2001 From: pmaytak <34331512+pmaytak@users.noreply.github.com> Date: Tue, 2 Mar 2021 18:29:12 -0800 Subject: [PATCH] Minor refactor and renamings. Set CacheInfo default. Rename CacheRefresh to CacheInfoTelemetry. Update unit tests to new API. Update cache info telemetry code. --- .../Cache/CacheInfoTelemetry.cs | 16 +++ .../Cache/CacheRefresh.cs | 15 -- .../Requests/ClientCredentialRequest.cs | 16 +-- .../Internal/Requests/OnBehalfOfRequest.cs | 13 +- .../Internal/Requests/RequestBase.cs | 1 + .../Requests/Silent/CacheSilentStrategy.cs | 14 +- .../Http/HttpTelemetryManager.cs | 13 +- .../Constants/MsalTelemetryBlobEventNames.cs | 3 +- .../TelemetryCore/Internal/Events/ApiEvent.cs | 21 +-- .../TelemetryCore/TelemetryConstants.cs | 2 +- .../TokenCache.ITokenCacheInternal.cs | 8 +- .../RegionalAuthIntegrationTests.cs | 10 +- .../UsernamePasswordIntegrationTests.cs | 12 +- .../Infrastructure/HttpTelemetryRecorder.cs | 14 +- .../TelemetryTests/HttpTelemetryTests.cs | 128 +++++++++--------- .../TelemetryTests/RegionalTelemetryTests.cs | 80 +++++------ 16 files changed, 172 insertions(+), 194 deletions(-) create mode 100644 src/client/Microsoft.Identity.Client/Cache/CacheInfoTelemetry.cs delete mode 100644 src/client/Microsoft.Identity.Client/Cache/CacheRefresh.cs diff --git a/src/client/Microsoft.Identity.Client/Cache/CacheInfoTelemetry.cs b/src/client/Microsoft.Identity.Client/Cache/CacheInfoTelemetry.cs new file mode 100644 index 0000000000..e6752bd001 --- /dev/null +++ b/src/client/Microsoft.Identity.Client/Cache/CacheInfoTelemetry.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License.; + +namespace Microsoft.Identity.Client.Cache +{ + // Enum to be used only for telemetry to log the reason for cache refresh and fetching access token from ESTS. + internal enum CacheInfoTelemetry + { + None = 0, // When the cache is not hit to make the request (interactive call, username password call, device code flow, etc.) + ForceRefresh = 1, // When the token request goes to ESTS because force_refresh was set to true + NoCachedAT = 2, // When the token request goes to ESTS because no cached access token exists + Expired = 3, // When the token request goes to ESTS because cached access token expired + RefreshIn = 4, // When the token request goes to ESTS because refresh_in was used and the existing token needs to be refreshed + //NonMsal = 5, // Reserved for non-MSAL customers (included here for consistency with the spec) + } +} diff --git a/src/client/Microsoft.Identity.Client/Cache/CacheRefresh.cs b/src/client/Microsoft.Identity.Client/Cache/CacheRefresh.cs deleted file mode 100644 index b071199bba..0000000000 --- a/src/client/Microsoft.Identity.Client/Cache/CacheRefresh.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License.; - -namespace Microsoft.Identity.Client.Region -{ - // Enum to be used only for telemetry, to log reason for cache refresh and fetching AT from ests. - internal enum CacheRefresh - { - None = -1, // When no cache is used - NoCachedAT = 0, // When there is no AT is found in the cache - Expired = 1, // When the token refresh happens due to expired token in cache - RefreshIn = 2, // When the token refresh happens due to refresh in - ForceRefresh = 3 // When the token refresh happens due to force refresh - } -} diff --git a/src/client/Microsoft.Identity.Client/Internal/Requests/ClientCredentialRequest.cs b/src/client/Microsoft.Identity.Client/Internal/Requests/ClientCredentialRequest.cs index 82f9ad0d06..6e6424260f 100644 --- a/src/client/Microsoft.Identity.Client/Internal/Requests/ClientCredentialRequest.cs +++ b/src/client/Microsoft.Identity.Client/Internal/Requests/ClientCredentialRequest.cs @@ -1,17 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using System.Collections.Generic; -using System.Globalization; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Identity.Client.ApiConfig.Parameters; using Microsoft.Identity.Client.Cache.Items; -using Microsoft.Identity.Client.Instance.Discovery; using Microsoft.Identity.Client.OAuth2; -using Microsoft.Identity.Client.Region; +using Microsoft.Identity.Client.Cache; using Microsoft.Identity.Client.TelemetryCore.Internal.Events; using Microsoft.Identity.Client.Utils; @@ -41,7 +37,7 @@ protected override async Task ExecuteAsync(CancellationTok MsalAccessTokenCacheItem cachedAccessTokenItem = null; var logger = AuthenticationRequestParameters.RequestContext.Logger; - CacheRefresh cacheRefresh = CacheRefresh.None; + CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; if (!_clientParameters.ForceRefresh && string.IsNullOrEmpty(AuthenticationRequestParameters.Claims)) @@ -60,7 +56,7 @@ protected override async Task ExecuteAsync(CancellationTok TokenSource.Cache); } - cacheRefresh = (cachedAccessTokenItem == null) ? CacheRefresh.NoCachedAT : CacheRefresh.RefreshIn; + cacheInfoTelemetry = (cachedAccessTokenItem == null) ? CacheInfoTelemetry.NoCachedAT : CacheInfoTelemetry.RefreshIn; } else { @@ -68,13 +64,13 @@ protected override async Task ExecuteAsync(CancellationTok if (_clientParameters.ForceRefresh) { - cacheRefresh = CacheRefresh.ForceRefresh; + cacheInfoTelemetry = CacheInfoTelemetry.ForceRefresh; } } - if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh == null) + if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo == (int)CacheInfoTelemetry.None) { - AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh = (int)cacheRefresh; + AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; } // No AT in the cache or AT needs to be refreshed diff --git a/src/client/Microsoft.Identity.Client/Internal/Requests/OnBehalfOfRequest.cs b/src/client/Microsoft.Identity.Client/Internal/Requests/OnBehalfOfRequest.cs index c688214dbe..2b19278547 100644 --- a/src/client/Microsoft.Identity.Client/Internal/Requests/OnBehalfOfRequest.cs +++ b/src/client/Microsoft.Identity.Client/Internal/Requests/OnBehalfOfRequest.cs @@ -5,11 +5,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Identity.Client.ApiConfig.Parameters; +using Microsoft.Identity.Client.Cache; using Microsoft.Identity.Client.Cache.Items; using Microsoft.Identity.Client.OAuth2; using Microsoft.Identity.Client.TelemetryCore.Internal.Events; -using System.Linq; -using Microsoft.Identity.Client.Region; namespace Microsoft.Identity.Client.Internal.Requests { @@ -36,7 +35,7 @@ protected override async Task ExecuteAsync(CancellationTok } await ResolveAuthorityEndpointsAsync().ConfigureAwait(false); - CacheRefresh cacheRefresh = CacheRefresh.None; + CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; MsalAccessTokenCacheItem msalAccessTokenItem = null; var logger = AuthenticationRequestParameters.RequestContext.Logger; @@ -64,17 +63,17 @@ protected override async Task ExecuteAsync(CancellationTok TokenSource.Cache); } - cacheRefresh = (msalAccessTokenItem == null) ? CacheRefresh.NoCachedAT : CacheRefresh.RefreshIn; + cacheInfoTelemetry = (msalAccessTokenItem == null) ? CacheInfoTelemetry.NoCachedAT : CacheInfoTelemetry.RefreshIn; } else { logger.Info("Skipped looking for an Access Token in the cache because ForceRefresh or Claims were set. "); - cacheRefresh = CacheRefresh.ForceRefresh; + cacheInfoTelemetry = CacheInfoTelemetry.ForceRefresh; } - if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh == null) + if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo == (int)CacheInfoTelemetry.None) { - AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh = (int)cacheRefresh; + AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; } // No AT in the cache or AT needs to be refreshed diff --git a/src/client/Microsoft.Identity.Client/Internal/Requests/RequestBase.cs b/src/client/Microsoft.Identity.Client/Internal/Requests/RequestBase.cs index 7affcf2fda..2164fbf8ae 100644 --- a/src/client/Microsoft.Identity.Client/Internal/Requests/RequestBase.cs +++ b/src/client/Microsoft.Identity.Client/Internal/Requests/RequestBase.cs @@ -168,6 +168,7 @@ private ApiEvent InitializeApiEvent(string accountId) apiEvent.IsTokenCacheSerialized = AuthenticationRequestParameters.CacheSessionManager.TokenCacheInternal.IsTokenCacheSerialized(); apiEvent.IsLegacyCacheEnabled = AuthenticationRequestParameters.RequestContext.ServiceBundle.Config.LegacyCacheCompatibilityEnabled; + apiEvent.CacheInfo = (int)CacheInfoTelemetry.None; // Give derived classes the ability to add or modify fields in the telemetry as needed. EnrichTelemetryApiEvent(apiEvent); diff --git a/src/client/Microsoft.Identity.Client/Internal/Requests/Silent/CacheSilentStrategy.cs b/src/client/Microsoft.Identity.Client/Internal/Requests/Silent/CacheSilentStrategy.cs index e63750ed06..d2e2b4717e 100644 --- a/src/client/Microsoft.Identity.Client/Internal/Requests/Silent/CacheSilentStrategy.cs +++ b/src/client/Microsoft.Identity.Client/Internal/Requests/Silent/CacheSilentStrategy.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Identity.Client.ApiConfig.Parameters; @@ -11,7 +10,6 @@ using Microsoft.Identity.Client.Cache.Items; using Microsoft.Identity.Client.Instance; using Microsoft.Identity.Client.OAuth2; -using Microsoft.Identity.Client.Region; namespace Microsoft.Identity.Client.Internal.Requests.Silent { @@ -40,7 +38,7 @@ public async Task ExecuteAsync(CancellationToken cancellat { var logger = AuthenticationRequestParameters.RequestContext.Logger; MsalAccessTokenCacheItem cachedAccessTokenItem = null; - CacheRefresh cacheRefresh = CacheRefresh.None; + CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; ThrowIfNoScopesOnB2C(); ThrowIfCurrentBrokerAccount(); @@ -58,22 +56,22 @@ public async Task ExecuteAsync(CancellationToken cancellat } else if (cachedAccessTokenItem == null) { - cacheRefresh = CacheRefresh.NoCachedAT; + cacheInfoTelemetry = CacheInfoTelemetry.NoCachedAT; } else { - cacheRefresh = CacheRefresh.RefreshIn; + cacheInfoTelemetry = CacheInfoTelemetry.RefreshIn; } } else { - cacheRefresh = CacheRefresh.ForceRefresh; + cacheInfoTelemetry = CacheInfoTelemetry.ForceRefresh; logger.Info("Skipped looking for an Access Token because ForceRefresh or Claims were set. "); } - if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh == null) + if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo == (int)CacheInfoTelemetry.None) { - AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh = (int)cacheRefresh; + AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; } // No AT or AT.RefreshOn > Now --> refresh the RT diff --git a/src/client/Microsoft.Identity.Client/TelemetryCore/Http/HttpTelemetryManager.cs b/src/client/Microsoft.Identity.Client/TelemetryCore/Http/HttpTelemetryManager.cs index 81e1d7dcc3..c3b115df76 100644 --- a/src/client/Microsoft.Identity.Client/TelemetryCore/Http/HttpTelemetryManager.cs +++ b/src/client/Microsoft.Identity.Client/TelemetryCore/Http/HttpTelemetryManager.cs @@ -88,7 +88,7 @@ public string GetLastRequestHeader() } string data = - $"{TelemetryConstants.HttpTelemetrySchemaVersion2}|" + + $"{TelemetryConstants.HttpTelemetrySchemaVersion}|" + $"{_successfulSilentCallCount}|" + $"{failedRequests}|" + $"{errors}|" + @@ -105,7 +105,7 @@ public string GetLastRequestHeader() } /// - /// Expected format: 3|api_id,force_refresh,cache_refresh|platform_config + /// Expected format: 3|api_id,cache_info|platform_config /// platform_config: region,region_source,is_token_cache_serialized,user_provided_region,validate_use_region,fallback_to_global,is_legacy_cache_enabled /// public string GetCurrentRequestHeader(ApiEvent eventInProgress) @@ -116,15 +116,14 @@ public string GetCurrentRequestHeader(ApiEvent eventInProgress) } eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.ApiIdConstStrKey, out string apiId); - eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.ForceRefreshId, out string forceRefresh); + eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.CacheInfoKey, out string cacheInfo); eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.RegionDiscovered, out string regionDiscovered); eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.RegionSource, out string regionSource); eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.IsTokenCacheSerializedKey, out string isTokenCacheSerialized); eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.UserProvidedRegion, out string userProvidedRegion); eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.IsValidUserProvidedRegion, out string isValidUserProvidedRegion); - eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.IsLegacyCacheEnabledKey, out string isLegacyCacheEnabled); eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.FallbackToGlobal, out string fallbackToGlobal); - eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.CacheRefreshKey, out string cacheRefresh); + eventInProgress.TryGetValue(MsalTelemetryBlobEventNames.IsLegacyCacheEnabledKey, out string isLegacyCacheEnabled); // Since regional fields will only be logged in case it is opted. var platformConfig = new StringBuilder(); @@ -137,8 +136,8 @@ public string GetCurrentRequestHeader(ApiEvent eventInProgress) platformConfig.Append((string.IsNullOrEmpty(fallbackToGlobal) ? fallbackToGlobal : ConvertFromStringToBitwise(fallbackToGlobal)) + ","); platformConfig.Append(ConvertFromStringToBitwise(isLegacyCacheEnabled)); - return $"{TelemetryConstants.HttpTelemetrySchemaVersion2}" + - $"|{apiId},{ConvertFromStringToBitwise(forceRefresh)},{cacheRefresh}" + + return $"{TelemetryConstants.HttpTelemetrySchemaVersion}" + + $"|{apiId},{cacheInfo}" + $"|{platformConfig}"; } diff --git a/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Constants/MsalTelemetryBlobEventNames.cs b/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Constants/MsalTelemetryBlobEventNames.cs index 07d76b2c60..b69e99ea4f 100644 --- a/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Constants/MsalTelemetryBlobEventNames.cs +++ b/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Constants/MsalTelemetryBlobEventNames.cs @@ -23,7 +23,6 @@ internal static class MsalTelemetryBlobEventNames public const string TenantIdConstStrKey = "Microsoft_MSAL_tenant_id"; public const string UiEventCountTelemetryBatchKey = "Microsoft_MSAL_ui_event_count"; public const string ApiErrorCodeConstStrKey = "msal.api_error_code"; - public const string ForceRefreshId = "api_with_force_refresh"; public const string RegionDiscovered = "msal.region_discovered"; public const string RegionSource = "msal.region_source"; public const string IsTokenCacheSerializedKey = "msal.is_token_cache_serialized"; @@ -31,6 +30,6 @@ internal static class MsalTelemetryBlobEventNames public const string IsValidUserProvidedRegion = "msal.is_valid_user_provided_region"; public const string FallbackToGlobal = "msal.fallback_to_global"; public const string IsLegacyCacheEnabledKey = "msal.is_legacy_cache_enabled"; - public const string CacheRefreshKey = "msal.cache_refresh"; + public const string CacheInfoKey = "msal.cache_info"; } } diff --git a/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Events/ApiEvent.cs b/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Events/ApiEvent.cs index 03de03f00c..3cc11b7e57 100644 --- a/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Events/ApiEvent.cs +++ b/src/client/Microsoft.Identity.Client/TelemetryCore/Internal/Events/ApiEvent.cs @@ -30,7 +30,7 @@ internal class ApiEvent : EventBase public const string IsValidUserProvidedRegionKey = EventNamePrefix + "is_valid_user_provided_region"; public const string FallbackToGlobalKey = EventNamePrefix + "fallback_to_global"; public const string IsLegacyCacheEnabledKey = EventNamePrefix + "is_legacy_cache_enabled"; - public const string CacheRefreshKey = EventNamePrefix + "cache_refresh"; + public const string CacheInfoKey = EventNamePrefix + "cache_info"; public enum ApiIds { @@ -233,23 +233,12 @@ public bool IsLegacyCacheEnabled #pragma warning restore CA1305 // Specify IFormatProvider } - public int? CacheRefresh + public int CacheInfo { - get - { - if (this.ContainsKey(CacheRefreshKey)) - { - int val = (int)Enum.Parse(typeof(CacheRefresh), this[CacheRefreshKey]); - if (val != -1) - { - return val; - } - } - - return null; - } + get => this.ContainsKey(CacheInfoKey) ? + (int)Enum.Parse(typeof(CacheInfoTelemetry), this[CacheInfoKey]) : (int)CacheInfoTelemetry.None; - set => this[CacheRefreshKey] = (value)?.ToString(CultureInfo.InvariantCulture); + set => this[CacheInfoKey] = value.ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/client/Microsoft.Identity.Client/TelemetryCore/TelemetryConstants.cs b/src/client/Microsoft.Identity.Client/TelemetryCore/TelemetryConstants.cs index f1c7255cab..44783957c1 100644 --- a/src/client/Microsoft.Identity.Client/TelemetryCore/TelemetryConstants.cs +++ b/src/client/Microsoft.Identity.Client/TelemetryCore/TelemetryConstants.cs @@ -11,7 +11,7 @@ internal static class TelemetryError internal static class TelemetryConstants { - public const string HttpTelemetrySchemaVersion2 = "3"; + public const string HttpTelemetrySchemaVersion = "4"; public const string HttpTelemetryPipe = "|"; public const string XClientCurrentTelemetry = "x-client-current-telemetry"; public const string XClientLastTelemetry = "x-client-last-telemetry"; diff --git a/src/client/Microsoft.Identity.Client/TokenCache.ITokenCacheInternal.cs b/src/client/Microsoft.Identity.Client/TokenCache.ITokenCacheInternal.cs index cfdfe18eec..03352e1c9d 100644 --- a/src/client/Microsoft.Identity.Client/TokenCache.ITokenCacheInternal.cs +++ b/src/client/Microsoft.Identity.Client/TokenCache.ITokenCacheInternal.cs @@ -326,13 +326,13 @@ async Task ITokenCacheInternal.FindAccessTokenAsync( // perf: take a snapshot as calling Count(), Any() etc. on the IEnumerable evaluates it each time IReadOnlyList finalList = tokenCacheItems.ToList(); - CacheRefresh cacheRefresh = CacheRefresh.None; + CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; // no match if (finalList.Count == 0) { logger.Verbose("No tokens found for matching authority, client_id, user and scopes."); - cacheRefresh = CacheRefresh.NoCachedAT; + cacheInfoTelemetry = CacheInfoTelemetry.NoCachedAT; return null; } @@ -342,10 +342,10 @@ async Task ITokenCacheInternal.FindAccessTokenAsync( if (msalAccessTokenCacheItem == null) { - cacheRefresh = CacheRefresh.Expired; + cacheInfoTelemetry = CacheInfoTelemetry.Expired; } - requestParams.RequestContext.ApiEvent.CacheRefresh = (int) cacheRefresh; + requestParams.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; return msalAccessTokenCacheItem; } diff --git a/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/RegionalAuthIntegrationTests.cs b/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/RegionalAuthIntegrationTests.cs index 19eb2be04e..a46b75e80e 100644 --- a/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/RegionalAuthIntegrationTests.cs +++ b/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/RegionalAuthIntegrationTests.cs @@ -103,7 +103,7 @@ public async Task AcquireTokenToRegionalEndpointAsync() AuthenticationResult result = await GetAuthenticationResultAsync().ConfigureAwait(false); // regional endpoint AssertTokenSource_IsIdP(result); AssertValidHost(true, factory); - AssertTelemetry(factory, "3|1004,0,0|centralus,1,0,,,0,1"); + AssertTelemetry(factory, "4|1004,2|centralus,1,0,,,0,1"); } @@ -125,12 +125,12 @@ public async Task AcquireTokenUserProvidedRegionSameAsRegionDetectedAsync() AuthenticationResult result = await GetAuthenticationResultAsync(userProvidedRegion: TestConstants.Region).ConfigureAwait(false); // regional endpoint AssertTokenSource_IsIdP(result); AssertValidHost(true, factory); - AssertTelemetry(factory, "3|1004,0,0|centralus,1,0,centralus,1,0,1"); + AssertTelemetry(factory, "4|1004,2|centralus,1,0,centralus,1,0,1"); result = await GetAuthenticationResultAsync(userProvidedRegion: TestConstants.Region, withForceRefresh: true).ConfigureAwait(false); // regional endpoint AssertTokenSource_IsIdP(result); AssertValidHost(true, factory, 1); - AssertTelemetry(factory, "3|1004,1,3|centralus,3,0,centralus,,0,1", 1); + AssertTelemetry(factory, "4|1004,1|centralus,3,0,centralus,,0,1", 1); } @@ -152,12 +152,12 @@ public async Task AcquireTokenUserProvidedRegionDifferentFromRegionDetectedAsync AuthenticationResult result = await GetAuthenticationResultAsync(userProvidedRegion: "invalid").ConfigureAwait(false); // regional endpoint AssertTokenSource_IsIdP(result); AssertValidHost(true, factory); - AssertTelemetry(factory, "3|1004,0,0|centralus,1,0,invalid,0,0,1"); + AssertTelemetry(factory, "4|1004,2|centralus,1,0,invalid,0,0,1"); result = await GetAuthenticationResultAsync(userProvidedRegion: TestConstants.Region, withForceRefresh: true).ConfigureAwait(false); // regional endpoint AssertTokenSource_IsIdP(result); AssertValidHost(true, factory, 1); - AssertTelemetry(factory, "3|1004,1,3|centralus,3,0,centralus,,0,1", 1); + AssertTelemetry(factory, "4|1004,1|centralus,3,0,centralus,,0,1", 1); } diff --git a/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/UsernamePasswordIntegrationTests.cs b/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/UsernamePasswordIntegrationTests.cs index 56563d7d21..194eba52b3 100644 --- a/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/UsernamePasswordIntegrationTests.cs +++ b/tests/Microsoft.Identity.Test.Integration.netfx/HeadlessTests/UsernamePasswordIntegrationTests.cs @@ -29,11 +29,11 @@ public class UsernamePasswordIntegrationTests // HTTP Telemetry Constants private static Guid CorrelationId = new Guid("ad8c894a-557f-48c0-b045-c129590c344e"); - private const string XClientCurrentTelemetryROPC = "3|1003,0,|,,0,,,,1"; - private const string XClientCurrentTelemetryROPCFailure = "3|1003,0,|,,0,,,,1"; - private const string XClientLastTelemetryROPC = "3|0|||"; + private const string XClientCurrentTelemetryROPC = "4|1003,0|,,0,,,,1"; + private const string XClientCurrentTelemetryROPCFailure = "4|1003,0|,,0,,,,1"; + private const string XClientLastTelemetryROPC = "4|0|||"; private const string XClientLastTelemetryROPCFailure = - "3|0|1003,ad8c894a-557f-48c0-b045-c129590c344e|invalid_grant|,"; + "4|0|1003,ad8c894a-557f-48c0-b045-c129590c344e|invalid_grant|,"; private const string ApiIdAndCorrelationIdSection = "1003,ad8c894a-557f-48c0-b045-c129590c344e"; private const string InvalidGrantError = "invalid_grant"; @@ -296,7 +296,7 @@ private void AssertTelemetryHeaders(HttpSnifferClientFactory factory, bool IsFai httpTelemetryRecorder.CheckSchemaVersion(csvCurrent); Assert.AreEqual(UPApiId, httpTelemetryRecorder.ApiId.FirstOrDefault(e => e.Contains(UPApiId))); - Assert.AreEqual(TelemetryConstants.Zero, httpTelemetryRecorder.ForceRefresh); + Assert.IsFalse(httpTelemetryRecorder.ForceRefresh); Assert.AreEqual(XClientLastTelemetryROPC, csvPrevious); } else @@ -311,7 +311,7 @@ private void AssertTelemetryHeaders(HttpSnifferClientFactory factory, bool IsFai Assert.AreEqual(UPApiId, httpTelemetryRecorder.ApiId.FirstOrDefault(e => e.Contains(UPApiId))); Assert.AreEqual(1, httpTelemetryRecorder.ErrorCode.Count()); Assert.AreEqual(TelemetryConstants.Zero, httpTelemetryRecorder.SilentCallSuccessfulCount); - Assert.AreEqual(TelemetryConstants.Zero, httpTelemetryRecorder.ForceRefresh); + Assert.IsFalse(httpTelemetryRecorder.ForceRefresh); Assert.AreEqual(ApiIdAndCorrelationIdSection, httpTelemetryRecorder.ApiIdAndCorrelationIds.FirstOrDefault()); Assert.AreEqual(InvalidGrantError, httpTelemetryRecorder.ErrorCode.FirstOrDefault()); } diff --git a/tests/Microsoft.Identity.Test.Integration.netfx/Infrastructure/HttpTelemetryRecorder.cs b/tests/Microsoft.Identity.Test.Integration.netfx/Infrastructure/HttpTelemetryRecorder.cs index 2349891a15..711893ee03 100644 --- a/tests/Microsoft.Identity.Test.Integration.netfx/Infrastructure/HttpTelemetryRecorder.cs +++ b/tests/Microsoft.Identity.Test.Integration.netfx/Infrastructure/HttpTelemetryRecorder.cs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; +using Microsoft.Identity.Client.Cache; using Microsoft.Identity.Client.TelemetryCore; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -11,22 +13,22 @@ public class HttpTelemetryRecorder { public List ApiId { get; set; } = new List(); public List ErrorCode { get; set; } = new List(); - public string ForceRefresh { get; set; } + public bool ForceRefresh { get; set; } public string SilentCallSuccessfulCount { get; set; } public List ApiIdAndCorrelationIds { get; set; } = new List(); public void CheckSchemaVersion(string telemetryCsv) { - Assert.IsNotNull(telemetryCsv.StartsWith(TelemetryConstants.HttpTelemetrySchemaVersion2)); + Assert.IsNotNull(telemetryCsv.StartsWith(TelemetryConstants.HttpTelemetrySchemaVersion)); } public void SplitCurrentCsv(string telemetryCsv) { string[] splitCsv = telemetryCsv.Split('|'); - string[] splitApiIdAndForceRefresh = splitCsv[1].Split(','); - ApiId.Add(splitApiIdAndForceRefresh[0]); - string forceRefresh = splitApiIdAndForceRefresh[splitApiIdAndForceRefresh.Length - 2]; - ForceRefresh = forceRefresh; + string[] splitApiIdAndCacheInfo = splitCsv[1].Split(','); + ApiId.Add(splitApiIdAndCacheInfo[0]); + Enum.TryParse(splitApiIdAndCacheInfo[1], out CacheInfoTelemetry cacheInfoTelemetry); + ForceRefresh = CacheInfoTelemetry.ForceRefresh == cacheInfoTelemetry; } public void SplitPreviousCsv(string telemetryCsv) diff --git a/tests/Microsoft.Identity.Test.Unit/TelemetryTests/HttpTelemetryTests.cs b/tests/Microsoft.Identity.Test.Unit/TelemetryTests/HttpTelemetryTests.cs index 8c19e3e280..8cf5fb73b2 100644 --- a/tests/Microsoft.Identity.Test.Unit/TelemetryTests/HttpTelemetryTests.cs +++ b/tests/Microsoft.Identity.Test.Unit/TelemetryTests/HttpTelemetryTests.cs @@ -9,7 +9,6 @@ using Microsoft.Identity.Test.Unit.Throttling; using System.Threading.Tasks; using Microsoft.Identity.Client; -using Microsoft.Identity.Client.Core; using Microsoft.Identity.Client.OAuth2.Throttling; using Microsoft.Identity.Client.TelemetryCore; using Microsoft.Identity.Client.UI; @@ -41,48 +40,49 @@ public override void TestCleanup() /// /// 1. Acquire Token Interactive successfully - /// Current_request = 3 | ATI_ID, 0, | 0 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATI_ID, 0 | 0 + /// Last_request = 4 | 0 | | | + /// /// 2. Acquire token silent with AT served from cache ... no calls to /token endpoint /// /// 3. Acquire token silent with AT not served from cache (AT expired) - /// Current_request = 3 | ATS_ID, 0, 0 | 0 - /// Last_request = 3 | 1 | | | + /// Current_request = 4 | ATS_ID, 2 | 0 + /// Last_request = 4 | 1 | | | /// /// 4. Acquire Token silent with force_refresh = true -> error invalid_client /// Sent to server - - /// Current_request = 3 | ATS_ID, 1, 3 | 0 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATS_ID, 1 | 0 + /// Last_request = 4 | 0 | | | /// /// State of client after error response is returned – (the successful silent request counter was flushed, last_request is reset, and now we add the error from step 4) - /// Last_request = 3 | 0 | ATS_ID, Corr_step_4 | invalid_client | + /// Last_request = 4 | 0 | ATS_ID, Corr_step_4 | invalid_client | /// /// 5. Acquire Token silent with force_refresh = true -> error interaction_required /// Sent to the server - - /// Current_request = 3 | ATS_ID, 1, 3 | 0 - /// Last_request = 3 | 0 | ATS_ID, corr_step_4 | invalid_client + /// Current_request = 4 | ATS_ID, 1 | 0 + /// Last_request = 4 | 0 | ATS_ID, corr_step_4 | invalid_client /// State of client after response is returned - - /// Last_request = 3 | 0 | ATS_ID, corr_step_5 | interaction_required + /// Last_request = 4 | 0 | ATS_ID, corr_step_5 | interaction_required /// /// 6. Acquire Token interactive -> error user_cancelled (i.e. no calls to /token endpoint) /// No calls to token endpoint /// /// 7. Acquire Token interactive -> HTTP error 503 (Service Unavailable) /// - /// Current_request = 3 | ATI_ID, 0, | 0 - /// Last_request = 3 | 0 | ATS_ID, corr_step_5, ATI_ID, corr_step-6, | interaction_required, + /// Current_request = 4 | ATI_ID, 0 | 0 + /// Last_request = 4 | 0 | ATS_ID, corr_step_5, ATI_ID, corr_step-6, | interaction_required, /// authentication_canceled| /// /// State of the client: /// - /// Last_request = 3 | 0 | ATS_ID, corr_step_5, ATI_ID, corr_step-6, ATI-ID, corr_step-6b | interaction_required, + /// Last_request = 4 | 0 | ATS_ID, corr_step_5, ATI_ID, corr_step-6, ATI-ID, corr_step-6b | interaction_required, /// authentication_canceled, ServiceUnavailable| /// /// 8. Acquire Token interactive -> successful /// /// Sent to the server - - /// Current_request = 3 | ATI_ID, 0, | 0 - /// Last_request = 3 | 0 | ATS_ID, corr_step_5, ATI_ID, corr_step-6, ATI-ID, corr_step-6b | interaction_required, + /// Current_request = 4 | ATI_ID, 0 | 0 + /// Last_request = 4 | 0 | ATS_ID, corr_step_5, ATI_ID, corr_step-6, ATI-ID, corr_step-6b | interaction_required, /// authentication_canceled, ServiceUnavailable | /// /// State of the client after response is returned - @@ -90,10 +90,10 @@ public override void TestCleanup() /// /// 9. Acquire Token Silent with force-refresh false -> successful /// Sent to the server - - /// Current_request = 3 | ATI_ID, 0, 0 | 0 + /// Current_request = 4 | ATI_ID, 2 | 0 /// Last_request = NULL /// State of the client after response is returned - - /// Last_request = 3 | 1 | | | + /// Last_request = 4 | 1 | | | /// [TestMethod] public async Task TelemetryAcceptanceTestAsync() @@ -110,8 +110,8 @@ public async Task TelemetryAcceptanceTestAsync() Trace.WriteLine("Step 1. Acquire Token Interactive successful"); var result = await RunAcquireTokenInteractiveAsync(AcquireTokenInteractiveOutcome.Success).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, forceRefresh: false); - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); // Previous_request = 2|0||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, CacheInfoTelemetry.None); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); Trace.WriteLine("Step 2. Acquire Token Silent successful - AT served from cache"); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.SuccessFromCache).ConfigureAwait(false); @@ -119,13 +119,13 @@ public async Task TelemetryAcceptanceTestAsync() Trace.WriteLine("Step 3. Acquire Token Silent successful - via refresh_token flow"); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.SuccessViaRefreshGrant).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, forceRefresh: false, cacheRefresh: "0"); - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 1); // Previous_request = 2|1||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, CacheInfoTelemetry.NoCachedAT); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 1); Trace.WriteLine("Step 4. Acquire Token Silent with force_refresh = true and failure = invalid_grant"); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.FailInvalidGrant, forceRefresh: true).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, forceRefresh: true, cacheRefresh: "3"); // Current_request = 3 | ATS_ID, 1, 3 | - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); // Previous_request = 2|0||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, CacheInfoTelemetry.ForceRefresh); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); // invalid grant error puts MSAL in a throttled state - simulate some time passing for this _harness.ServiceBundle.ThrottlingManager.SimulateTimePassing( @@ -134,7 +134,7 @@ public async Task TelemetryAcceptanceTestAsync() Guid step4Correlationid = result.Correlationid; Trace.WriteLine("Step 5. Acquire Token Silent with force_refresh = true and failure = interaction_required"); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.FailInteractionRequired, forceRefresh: true).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, forceRefresh: true, cacheRefresh: "3");// Current_request = 3 | ATS_ID, 1, 3 | + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, CacheInfoTelemetry.ForceRefresh); AssertPreviousTelemetry( result.HttpRequest, expectedSilentCount: 0, @@ -153,7 +153,7 @@ public async Task TelemetryAcceptanceTestAsync() Guid step7CorrelationId = result.Correlationid; // we can assert telemetry here, as it will be sent to AAD. However, AAD is down, so it will not record it. - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, forceRefresh: false); + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, CacheInfoTelemetry.None); AssertPreviousTelemetry( result.HttpRequest, expectedSilentCount: 0, @@ -168,7 +168,7 @@ public async Task TelemetryAcceptanceTestAsync() Trace.WriteLine("Step 8. Acquire Token Interactive -> Success"); result = await RunAcquireTokenInteractiveAsync(AcquireTokenInteractiveOutcome.Success).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, forceRefresh: false); + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, CacheInfoTelemetry.None); AssertPreviousTelemetry( result.HttpRequest, expectedSilentCount: 0, @@ -178,28 +178,29 @@ public async Task TelemetryAcceptanceTestAsync() Trace.WriteLine("Step 9. Acquire Token Silent with force-refresh false -> successful"); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.SuccessViaRefreshGrant, false).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, forceRefresh: false, cacheRefresh: "0"); + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, CacheInfoTelemetry.NoCachedAT); AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); } } /// /// 1. Acquire Token Interactive successfully - /// Current_request = 3 |ATS_ID, 0, | , , 0, , , , 1 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 |ATS_ID, 0 | , , 0, , , , 1 + /// Last_request = 4 | 0 | | | + /// /// 2. Acquire token silent with AT served from cache ... no calls to /token endpoint /// /// 3. Acquire token silent with AT expired - /// Current_request = 3 | ATS_ID, 0, 1 | , , 1, , , , 1 - /// Last_request = 3 | 1 | | | + /// Current_request = 4 | ATS_ID, 3 | , , 1, , , , 1 + /// Last_request = 4 | 1 | | | /// /// 4. Acquire Token silent with refresh on - /// Current_request = 3 | ATS_ID, 1, 2 | , , 1, , , , 1 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATS_ID, 4 | , , 1, , , , 1 + /// Last_request = 4 | 0 | | | /// /// 5. Acquire Token silent with force_refresh = true - /// Current_request = 3 | ATS_ID, 1, 3 | , , 1, , , , 1 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATS_ID, 1 | , , 1, , , , 1 + /// Last_request = 4 | 0 | | | /// /// [TestMethod] @@ -219,8 +220,8 @@ public async Task TelemetryCacheRefreshTestAsync() Trace.WriteLine("Step 1. Acquire Token Interactive successful"); var result = await RunAcquireTokenInteractiveAsync(AcquireTokenInteractiveOutcome.Success).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, forceRefresh: false); - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); // Previous_request = 2|0||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, CacheInfoTelemetry.None); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); Trace.WriteLine("Step 2. Acquire Token Silent successful - AT served from cache"); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.SuccessFromCache).ConfigureAwait(false); @@ -230,27 +231,27 @@ public async Task TelemetryCacheRefreshTestAsync() UpdateATWithRefreshOn(_app.UserTokenCacheInternal.Accessor, DateTime.UtcNow - TimeSpan.FromMinutes(1), true); TokenCacheAccessRecorder cacheAccess = _app.UserTokenCache.RecordAccess(); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.SuccessViaCacheRefresh).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, forceRefresh: false, isCacheSerialized: true, cacheRefresh: "1"); - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 1); // Previous_request = 2|1||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, CacheInfoTelemetry.Expired, isCacheSerialized: true); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 1); Trace.WriteLine("Step 4. Acquire Token Silent successful - via refresh on"); UpdateATWithRefreshOn(_app.UserTokenCacheInternal.Accessor, DateTime.UtcNow - TimeSpan.FromMinutes(1)); cacheAccess = _app.UserTokenCache.RecordAccess(); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.SuccessViaCacheRefresh).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, forceRefresh: false, isCacheSerialized: true, cacheRefresh: "2"); - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); // Previous_request = 2|1||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, CacheInfoTelemetry.RefreshIn, isCacheSerialized: true); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); Trace.WriteLine("Step 5. Acquire Token Silent with force_refresh = true"); result = await RunAcquireTokenSilentAsync(AcquireTokenSilentOutcome.SuccessViaCacheRefresh, forceRefresh: true).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, forceRefresh: true, isCacheSerialized: true, cacheRefresh: "3"); // Current_request = 3 | ATS_ID, 1, 3 | - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); // Previous_request = 2|0||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenSilent, CacheInfoTelemetry.ForceRefresh, isCacheSerialized: true); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); } } /// /// Acquire token with serialized token cache successfully - /// Current_request = 2 | ATC_ID, 0 | 1 - /// Last_request = 2 | 0 | | | + /// Current_request = 4 | ATC_ID, 0 | 1 + /// Last_request = 4 | 0 | | | /// [TestMethod] public async Task TelemetryTestSerializedTokenCacheAsync() @@ -270,7 +271,7 @@ public async Task TelemetryTestSerializedTokenCacheAsync() Trace.WriteLine("Step 1. Acquire Token Interactive successful"); var result = await RunAcquireTokenInteractiveAsync(AcquireTokenInteractiveOutcome.Success).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, forceRefresh: false, isCacheSerialized: true); + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, CacheInfoTelemetry.None, isCacheSerialized: true); AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); } } @@ -292,7 +293,7 @@ public async Task LegacyCacheEnabledTelemetryTestAsync(bool isLegacyCacheEnabled .BuildConcrete(); var result = await RunAcquireTokenInteractiveAsync(AcquireTokenInteractiveOutcome.Success).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, forceRefresh: false, isLegacyCacheEnabled: isLegacyCacheEnabled); + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, CacheInfoTelemetry.None, isLegacyCacheEnabled: isLegacyCacheEnabled); AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); } } @@ -482,30 +483,29 @@ private enum AcquireTokenInteractiveOutcome private static void AssertCurrentTelemetry( HttpRequestMessage requestMessage, ApiIds apiId, - bool forceRefresh, + CacheInfoTelemetry cacheInfo, bool isCacheSerialized = false, - bool isLegacyCacheEnabled = true, - string cacheRefresh = "") + bool isLegacyCacheEnabled = true) { - string actualCurrentTelemetry = requestMessage.Headers.GetValues( - TelemetryConstants.XClientCurrentTelemetry).Single(); + string[] telemetryCategories = requestMessage.Headers.GetValues( + TelemetryConstants.XClientCurrentTelemetry).Single().Split('|'); - var actualTelemetryParts = actualCurrentTelemetry.Split('|'); - Assert.AreEqual(3, actualTelemetryParts.Length); + Assert.AreEqual(3, telemetryCategories.Length); + Assert.AreEqual(1, telemetryCategories[0].Split(',').Length); // version + Assert.AreEqual(2, telemetryCategories[1].Split(',').Length); // api_id, cache_info + Assert.AreEqual(7, telemetryCategories[2].Split(',').Length); // platform_fields - Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion2, actualTelemetryParts[0]); // version + Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion, telemetryCategories[0]); // version Assert.AreEqual( - ((int)apiId).ToString(CultureInfo.InvariantCulture), - actualTelemetryParts[1].Split(',')[0]); // current_api_id - - Assert.AreEqual(forceRefresh ? "1" : "0", actualTelemetryParts[1].Split(',')[1]); // force_refresh flag + apiId.ToString("D"), + telemetryCategories[1].Split(',')[0]); // current_api_id - Assert.AreEqual(isCacheSerialized ? "1" : "0", actualTelemetryParts[2].Split(',')[2]); // is_cache_serialized + Assert.AreEqual(cacheInfo.ToString("D"), telemetryCategories[1].Split(',')[1]); // cache_info - Assert.AreEqual(isLegacyCacheEnabled ? "1" : "0", actualTelemetryParts[2].Split(',')[6]); // is_legacy_cache_enabled + Assert.AreEqual(isCacheSerialized ? "1" : "0", telemetryCategories[2].Split(',')[2]); // is_cache_serialized - Assert.AreEqual(cacheRefresh, actualTelemetryParts[1].Split(',')[2]); // Cache_refresh + Assert.AreEqual(isLegacyCacheEnabled ? "1" : "0", telemetryCategories[2].Split(',')[6]); // is_legacy_cache_enabled } private static void AssertPreviousTelemetry( @@ -546,7 +546,7 @@ private static (int SilentCount, string[] FailedApis, string[] CorrelationIds, s var lastRequestParts = lastTelemetryHeader.Split('|'); Assert.AreEqual(5, lastRequestParts.Length); // 2 | 1 | | | - Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion2, lastRequestParts[0]); // version + Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion, lastRequestParts[0]); // version int actualSuccessfullSilentCount = int.Parse(lastRequestParts[1], CultureInfo.InvariantCulture); diff --git a/tests/Microsoft.Identity.Test.Unit/TelemetryTests/RegionalTelemetryTests.cs b/tests/Microsoft.Identity.Test.Unit/TelemetryTests/RegionalTelemetryTests.cs index ab41311c22..7ebbeb9b53 100644 --- a/tests/Microsoft.Identity.Test.Unit/TelemetryTests/RegionalTelemetryTests.cs +++ b/tests/Microsoft.Identity.Test.Unit/TelemetryTests/RegionalTelemetryTests.cs @@ -6,13 +6,13 @@ using System.Globalization; using System.Linq; using System.Net.Http; -using Microsoft.Identity.Test.Unit.Throttling; using System.Threading.Tasks; using Microsoft.Identity.Client; using Microsoft.Identity.Client.OAuth2.Throttling; using Microsoft.Identity.Client.TelemetryCore; using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Common.Core.Mocks; +using Microsoft.Identity.Test.Unit.Throttling; using Microsoft.VisualStudio.TestTools.UnitTesting; using static Microsoft.Identity.Client.TelemetryCore.Internal.Events.ApiEvent; @@ -48,19 +48,19 @@ public override void TestCleanup() /// /// 1. Acquire Token For Client with Region successfully - /// Current_request = 3 | ATC_ID, 0, | centralus, 1, 0, - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATC_ID, 0 | centralus, 1, 0, + /// Last_request = 4 | 0 | | | /// /// 2. Acquire Token for client with Region -> HTTP error 503 (Service Unavailable) /// - /// Current_request = 3 | ATC_ID, 1, | centralus, 3, 0, - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATC_ID, 1 | centralus, 3, 0, + /// Last_request = 4 | 0 | | | /// /// 3. Acquire Token For Client with Region -> successful /// /// Sent to the server - - /// Current_request = 3 | ATC_ID, 1, | centralus, 3, 0, - /// Last_request = 3 | 0 | ATC_ID, corr_step_2 | ServiceUnavailable | centralus, 3 + /// Current_request = 4 | ATC_ID, 1 | centralus, 3, 0, + /// Last_request = 4 | 0 | ATC_ID, corr_step_2 | ServiceUnavailable | centralus, 3 /// [TestMethod] public async Task TelemetryAcceptanceTestAsync() @@ -69,15 +69,15 @@ public async Task TelemetryAcceptanceTestAsync() Trace.WriteLine("Step 1. Acquire Token For Client with region successful"); var result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.Success).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, forceRefresh: false, "1"); - AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); // Previous_request = 3|0||| + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, "1"); + AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); Trace.WriteLine("Step 2. Acquire Token For Client -> HTTP 5xx error (i.e. AAD is down)"); result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.AADUnavailableError).ConfigureAwait(false); Guid step2CorrelationId = result.Correlationid; // we can assert telemetry here, as it will be sent to AAD. However, AAD is down, so it will not record it. - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, forceRefresh: true, "3"); + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, "3"); AssertPreviousTelemetry( result.HttpRequest, expectedSilentCount: 0); @@ -89,7 +89,7 @@ public async Task TelemetryAcceptanceTestAsync() Trace.WriteLine("Step 3. Acquire Token For Client -> Success"); result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.Success, true).ConfigureAwait(false); - AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, forceRefresh: true, "3"); + AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, "3"); AssertPreviousTelemetry( result.HttpRequest, expectedSilentCount: 0, @@ -102,8 +102,8 @@ public async Task TelemetryAcceptanceTestAsync() /// /// Acquire token for client with serialized token cache successfully - /// Current_request = 3 | ATC_ID, 0, | centralus, 1, 1 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATC_ID, 0 | centralus, 1, 1 + /// Last_request = 4 | 0 | | | /// [TestMethod] public async Task TelemetrySerializedTokenCacheTestAsync() @@ -117,7 +117,6 @@ public async Task TelemetrySerializedTokenCacheTestAsync() var result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.Success).ConfigureAwait(false); AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, - forceRefresh: false, "1", isCacheSerialized: true); AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); @@ -125,8 +124,8 @@ public async Task TelemetrySerializedTokenCacheTestAsync() /// /// Acquire token for client with regionToUse when auto region discovery fails - /// Current_request = 3 | ATC_ID, 0, | centralus, 1, 1, centralus, - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATC_ID, 0 | centralus, 1, 1, centralus, + /// Last_request = 4 | 0 | | | /// [TestMethod] public async Task TelemetryUserProvidedRegionAutoDiscoveryFailsTestsAsync() @@ -136,7 +135,6 @@ public async Task TelemetryUserProvidedRegionAutoDiscoveryFailsTestsAsync() var result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.UserProvidedRegion).ConfigureAwait(false); AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, - forceRefresh: false, "4", isCacheSerialized: false, userProvidedRegion: TestConstants.Region); @@ -145,8 +143,8 @@ public async Task TelemetryUserProvidedRegionAutoDiscoveryFailsTestsAsync() /// /// Acquire token for client with regionToUse when auto region discovery passes with region same as regionToUse - /// Current_request = 3 | ATC_ID, 0, | centralus, 1, 1, centralus, 1 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATC_ID, 0 | centralus, 1, 1, centralus, 1 + /// Last_request = 4 | 0 | | | /// [TestMethod] public async Task TelemetryUserProvidedRegionAutoDiscoverRegionSameTestsAsync() @@ -157,18 +155,17 @@ public async Task TelemetryUserProvidedRegionAutoDiscoverRegionSameTestsAsync() var result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.UserProvidedRegion).ConfigureAwait(false); AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, - forceRefresh: false, "1", isCacheSerialized: false, userProvidedRegion: TestConstants.Region, - isvalidUserProvidedRegion: "1"); + isValidUserProvidedRegion: "1"); AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); } /// /// Acquire token for client with regionToUse when auto region discovery passes with region different from regionToUse - /// Current_request = 3 | ATC_ID, 0, | centralus, 1, 1, invalid, 0 - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATC_ID, 0 | centralus, 1, 1, invalid, 0 + /// Last_request = 4 | 0 | | | /// [TestMethod] public async Task TelemetryUserProvidedRegionAutoDiscoverRegionDifferentTestsAsync() @@ -179,18 +176,17 @@ public async Task TelemetryUserProvidedRegionAutoDiscoverRegionDifferentTestsAsy var result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.UserProvidedInvalidRegion).ConfigureAwait(false); AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, - forceRefresh: false, "1", isCacheSerialized: false, userProvidedRegion: "invalid", - isvalidUserProvidedRegion: "0"); + isValidUserProvidedRegion: "0"); AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0); } /// /// Acquire token for client with regionToUse when auto region discovery fails - /// Current_request = 3 | ATC_ID, 0, | centralus, 1, 1, centralus, - /// Last_request = 3 | 0 | | | + /// Current_request = 4 | ATC_ID, 0 | centralus, 1, 1, centralus, + /// Last_request = 4 | 0 | | | /// [TestMethod] public async Task TelemetryUserProvidedRegionAutoDiscoveryFailsFallbackToGlobalTestsAsync() @@ -200,7 +196,6 @@ public async Task TelemetryUserProvidedRegionAutoDiscoveryFailsFallbackToGlobalT var result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.FallbackToGlobal).ConfigureAwait(false); AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenForClient, - forceRefresh: false, "", region: "", isCacheSerialized: false, @@ -316,34 +311,33 @@ private enum AcquireTokenForClientOutcome private static void AssertCurrentTelemetry( HttpRequestMessage requestMessage, ApiIds apiId, - bool forceRefresh, string regionSource, string region = TestConstants.Region, bool isCacheSerialized = false, string userProvidedRegion = "", - string isvalidUserProvidedRegion = "", + string isValidUserProvidedRegion = "", string fallbackToGlobal = "0") { - string actualCurrentTelemetry = requestMessage.Headers.GetValues( - TelemetryConstants.XClientCurrentTelemetry).Single(); + string[] telemetryCategories = requestMessage.Headers.GetValues( + TelemetryConstants.XClientCurrentTelemetry).Single().Split('|'); - var actualTelemetryParts = actualCurrentTelemetry.Split('|'); - Assert.AreEqual(3, actualTelemetryParts.Length); + Assert.AreEqual(3, telemetryCategories.Length); + Assert.AreEqual(1, telemetryCategories[0].Split(',').Length); // version + Assert.AreEqual(2, telemetryCategories[1].Split(',').Length); // api_id, cache_info + Assert.AreEqual(7, telemetryCategories[2].Split(',').Length); // platform_fields - Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion2, actualTelemetryParts[0]); // version + Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion, telemetryCategories[0]); // version Assert.AreEqual( - ((int)apiId).ToString(CultureInfo.InvariantCulture), - actualTelemetryParts[1].Split(',')[0]); // current_api_id + apiId.ToString("D"), + telemetryCategories[1].Split(',')[0]); // current_api_id - Assert.AreEqual(forceRefresh ? "1" : "0", actualTelemetryParts[1].Split(',')[1]); // force_refresh flag - - string[] platformConfig = actualTelemetryParts[2].Split(','); - Assert.AreEqual(isCacheSerialized ? "1" : "0", platformConfig[2]); + string[] platformConfig = telemetryCategories[2].Split(','); Assert.AreEqual(region, platformConfig[0]); Assert.AreEqual(regionSource, platformConfig[1]); + Assert.AreEqual(isCacheSerialized ? "1" : "0", platformConfig[2]); Assert.AreEqual(userProvidedRegion, platformConfig[3]); - Assert.AreEqual(isvalidUserProvidedRegion, platformConfig[4]); + Assert.AreEqual(isValidUserProvidedRegion, platformConfig[4]); Assert.AreEqual(fallbackToGlobal, platformConfig[5]); } @@ -397,7 +391,7 @@ private static (int SilentCount, string[] FailedApis, string[] CorrelationIds, s var lastRequestParts = lastTelemetryHeader.Split('|'); Assert.AreEqual(5, lastRequestParts.Length); // 2 | 1 | | | - Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion2, lastRequestParts[0]); // version + Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion, lastRequestParts[0]); // version int actualSuccessfullSilentCount = int.Parse(lastRequestParts[1], CultureInfo.InvariantCulture);