diff --git a/src/Microsoft.Identity.Web.TokenCache/CacheSerializerHints.cs b/src/Microsoft.Identity.Web.TokenCache/CacheSerializerHints.cs
index 2ea239e18..ea62cbde9 100644
--- a/src/Microsoft.Identity.Web.TokenCache/CacheSerializerHints.cs
+++ b/src/Microsoft.Identity.Web.TokenCache/CacheSerializerHints.cs
@@ -3,6 +3,7 @@
using System;
using System.Threading;
+using Microsoft.Identity.Client.TelemetryCore.TelemetryClient;
namespace Microsoft.Identity.Web.TokenCacheProviders
{
@@ -21,5 +22,10 @@ public class CacheSerializerHints
/// with the app token cache.
///
public DateTimeOffset? SuggestedCacheExpiry { get; set; }
+
+ ///
+ /// Stores details to log to MSAL's telemetry client
+ ///
+ internal TelemetryData? TelemetryData { get; set; }
}
}
diff --git a/src/Microsoft.Identity.Web.TokenCache/Distributed/MsalDistributedTokenCacheAdapter.cs b/src/Microsoft.Identity.Web.TokenCache/Distributed/MsalDistributedTokenCacheAdapter.cs
index f80c40b20..708eb3f4d 100644
--- a/src/Microsoft.Identity.Web.TokenCache/Distributed/MsalDistributedTokenCacheAdapter.cs
+++ b/src/Microsoft.Identity.Web.TokenCache/Distributed/MsalDistributedTokenCacheAdapter.cs
@@ -147,6 +147,7 @@ await L2OperationWithRetryOnFailureAsync(
{
const string read = "Read";
byte[]? result = null;
+ var telemetryData = cacheSerializerHints.TelemetryData;
if (_memoryCache != null)
{
@@ -169,6 +170,11 @@ await L2OperationWithRetryOnFailureAsync(
}, cacheSerializerHints.CancellationToken).Measure().ConfigureAwait(false);
#pragma warning restore CA1062 // Validate arguments of public methods
+ if (result != null && telemetryData != null)
+ {
+ telemetryData.CacheLevel = Client.Cache.CacheLevel.L2Cache;
+ }
+
Logger.DistributedCacheReadTime(_logger, _distributedCacheType, read, measure.MilliSeconds);
if (_memoryCache != null)
@@ -195,6 +201,11 @@ await L2OperationWithRetryOnFailureAsync(
(cacheKey) => _distributedCache.RefreshAsync(cacheKey, cacheSerializerHints.CancellationToken),
cacheKey,
result!).ConfigureAwait(false);
+
+ if (telemetryData != null)
+ {
+ telemetryData.CacheLevel = Client.Cache.CacheLevel.L1Cache;
+ }
}
#pragma warning disable CS8603 // Possible null reference return.
diff --git a/src/Microsoft.Identity.Web.TokenCache/InMemory/MsalMemoryTokenCacheProvider.cs b/src/Microsoft.Identity.Web.TokenCache/InMemory/MsalMemoryTokenCacheProvider.cs
index 1d29b8d5e..e3351f01d 100644
--- a/src/Microsoft.Identity.Web.TokenCache/InMemory/MsalMemoryTokenCacheProvider.cs
+++ b/src/Microsoft.Identity.Web.TokenCache/InMemory/MsalMemoryTokenCacheProvider.cs
@@ -62,6 +62,24 @@ protected override Task RemoveKeyAsync(string cacheKey)
return Task.FromResult(tokenCacheBytes);
}
+ ///
+ /// Method to be overridden by concrete cache serializers to Read the cache bytes.
+ ///
+ /// Cache key.
+ /// Hints for the cache serialization implementation optimization.
+ /// Read bytes.
+ protected override Task ReadCacheBytesAsync(string cacheKey, CacheSerializerHints cacheSerializerHints)
+ {
+ byte[]? tokenCacheBytes = (byte[]?)_memoryCache.Get(cacheKey);
+
+ if (tokenCacheBytes != null && cacheSerializerHints.TelemetryData != null)
+ {
+ cacheSerializerHints.TelemetryData.CacheLevel = Client.Cache.CacheLevel.L1Cache;
+ }
+
+ return Task.FromResult(tokenCacheBytes);
+ }
+
///
/// Writes a token cache blob to the serialization cache (identified by its key).
///
diff --git a/src/Microsoft.Identity.Web.TokenCache/MsalAbstractTokenCacheProvider.cs b/src/Microsoft.Identity.Web.TokenCache/MsalAbstractTokenCacheProvider.cs
index 88f2fe8a2..1fcd74ff2 100644
--- a/src/Microsoft.Identity.Web.TokenCache/MsalAbstractTokenCacheProvider.cs
+++ b/src/Microsoft.Identity.Web.TokenCache/MsalAbstractTokenCacheProvider.cs
@@ -101,7 +101,7 @@ private byte[] ProtectBytes(byte[] msalBytes)
}
private static CacheSerializerHints CreateHintsFromArgs(TokenCacheNotificationArgs args) => new CacheSerializerHints
- { CancellationToken = args.CancellationToken, SuggestedCacheExpiry = args.SuggestedCacheExpiry };
+ { CancellationToken = args.CancellationToken, SuggestedCacheExpiry = args.SuggestedCacheExpiry, TelemetryData = args.TelemetryData };
private async Task OnBeforeAccessAsync(TokenCacheNotificationArgs args)
{
diff --git a/src/Microsoft.Identity.Web.TokenCache/Properties/InternalsVisibleTo.cs b/src/Microsoft.Identity.Web.TokenCache/Properties/InternalsVisibleTo.cs
index bdaa961fd..41022c2b1 100644
--- a/src/Microsoft.Identity.Web.TokenCache/Properties/InternalsVisibleTo.cs
+++ b/src/Microsoft.Identity.Web.TokenCache/Properties/InternalsVisibleTo.cs
@@ -5,3 +5,4 @@
// Allow this assembly to be serviced when run on desktop CLR
[assembly: InternalsVisibleTo("Microsoft.Identity.Web.Test, PublicKey=00240000048000009400000006020000002400005253413100040000010001002D96616729B54F6D013D71559A017F50AA4861487226C523959D1579B93F3FDF71C08B980FD3130062B03D3DE115C4B84E7AC46AEF5E192A40E7457D5F3A08F66CEAB71143807F2C3CB0DA5E23B38F0559769978406F6E5D30CEADD7985FC73A5A609A8B74A1DF0A29399074A003A226C943D480FEC96DBEC7106A87896539AD")]
+[assembly: InternalsVisibleTo("Microsoft.Identity.Web.Test.Common, PublicKey=00240000048000009400000006020000002400005253413100040000010001002D96616729B54F6D013D71559A017F50AA4861487226C523959D1579B93F3FDF71C08B980FD3130062B03D3DE115C4B84E7AC46AEF5E192A40E7457D5F3A08F66CEAB71143807F2C3CB0DA5E23B38F0559769978406F6E5D30CEADD7985FC73A5A609A8B74A1DF0A29399074A003A226C943D480FEC96DBEC7106A87896539AD")]
diff --git a/src/Microsoft.Identity.Web.TokenCache/TokenCacheExtensions.cs b/src/Microsoft.Identity.Web.TokenCache/TokenCacheExtensions.cs
index 0289b1661..1b210c38e 100644
--- a/src/Microsoft.Identity.Web.TokenCache/TokenCacheExtensions.cs
+++ b/src/Microsoft.Identity.Web.TokenCache/TokenCacheExtensions.cs
@@ -19,7 +19,8 @@ namespace Microsoft.Identity.Web
///
public static class TokenCacheExtensions
{
- private static readonly ConcurrentDictionary s_serviceProviderFromAction
+ //internal for testing only
+ internal static readonly ConcurrentDictionary s_serviceProviderFromAction
= new ConcurrentDictionary();
///
diff --git a/tests/Microsoft.Identity.Web.Test.Common/Mocks/MockHttpMessageHandler.cs b/tests/Microsoft.Identity.Web.Test.Common/Mocks/MockHttpMessageHandler.cs
index b9d7d292e..ff1984057 100644
--- a/tests/Microsoft.Identity.Web.Test.Common/Mocks/MockHttpMessageHandler.cs
+++ b/tests/Microsoft.Identity.Web.Test.Common/Mocks/MockHttpMessageHandler.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System;
+using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@@ -11,6 +12,8 @@ namespace Microsoft.Identity.Web.Test.Common.Mocks
{
public class MockHttpMessageHandler : HttpMessageHandler
{
+ public Func ReplaceMockHttpMessageHandler;
+
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public MockHttpMessageHandler()
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
@@ -41,6 +44,25 @@ protected override Task SendAsync(HttpRequestMessage reques
var uri = request.RequestUri;
Assert.NotNull(uri);
+
+ //Intercept instance discovery requests and serve a response.
+ //Also, requeue the current mock handler for MSAL's next request.
+#if NET6_0_OR_GREATER
+ if (uri.AbsoluteUri.Contains("/discovery/instance", StringComparison.OrdinalIgnoreCase))
+#else
+ if (uri.AbsoluteUri.Contains("/discovery/instance"))
+#endif
+ {
+ ReplaceMockHttpMessageHandler(this);
+
+ var responseMessage = new HttpResponseMessage(HttpStatusCode.OK)
+ {
+ Content = new StringContent(TestConstants.DiscoveryJsonResponse),
+ };
+
+ return Task.FromResult(responseMessage);
+ }
+
if (!string.IsNullOrEmpty(ExpectedUrl))
{
Assert.Equal(
@@ -59,7 +81,7 @@ protected override Task SendAsync(HttpRequestMessage reques
string postData = request.Content.ReadAsStringAsync().Result;
}
- return new TaskFactory().StartNew(() => ResponseMessage, cancellationToken);
+ return Task.FromResult(ResponseMessage);
}
}
}
diff --git a/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/TestMsalDistributedTokenCacheAdapter.cs b/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/TestMsalDistributedTokenCacheAdapter.cs
index 18ae3b83e..7b51eeafa 100644
--- a/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/TestMsalDistributedTokenCacheAdapter.cs
+++ b/tests/Microsoft.Identity.Web.Test.Common/TestHelpers/TestMsalDistributedTokenCacheAdapter.cs
@@ -6,6 +6,7 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using Microsoft.Identity.Client.TelemetryCore.TelemetryClient;
using Microsoft.Identity.Web.TokenCacheProviders;
using Microsoft.Identity.Web.TokenCacheProviders.Distributed;
@@ -42,5 +43,10 @@ public async Task TestWriteCacheBytesAsync(string cacheKey, byte[] bytes, CacheS
{
return await ReadCacheBytesAsync(cacheKey).ConfigureAwait(false);
}
+
+ public async Task TestReadCacheBytesAsync(string cacheKey, TelemetryData telemetryData)
+ {
+ return await ReadCacheBytesAsync(cacheKey, new CacheSerializerHints() { TelemetryData = telemetryData }).ConfigureAwait(false);
+ }
}
}
diff --git a/tests/Microsoft.Identity.Web.Test/CacheExtensionsTests.cs b/tests/Microsoft.Identity.Web.Test/CacheExtensionsTests.cs
index 5ce5b9f7c..78986cf5f 100644
--- a/tests/Microsoft.Identity.Web.Test/CacheExtensionsTests.cs
+++ b/tests/Microsoft.Identity.Web.Test/CacheExtensionsTests.cs
@@ -2,13 +2,17 @@
// Licensed under the MIT License.
using System;
+using System.Globalization;
using System.Threading.Tasks;
-using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;
+using Microsoft.Identity.Client.Cache;
using Microsoft.Identity.Web.Test.Common;
using Microsoft.Identity.Web.Test.Common.Mocks;
+using Microsoft.Identity.Web.TokenCacheProviders.Distributed;
+using Microsoft.IdentityModel.Abstractions;
using Xunit;
namespace Microsoft.Identity.Web.Test
@@ -29,19 +33,42 @@ public void InMemoryCacheExtensionsTests()
public async Task CacheExtensions_CcaAlreadyExists_TestsAsync()
{
AuthenticationResult result;
+ TestTelemetryClient testTelemetryClient = new TestTelemetryClient(TestConstants.ClientId);
// new InMemory serializer and new cca
- result = await CreateAppAndGetTokenAsync(CacheType.InMemory, addInstanceMock: true).ConfigureAwait(false);
+ result = await CreateAppAndGetTokenAsync(CacheType.InMemory, testTelemetryClient).ConfigureAwait(false);
Assert.Equal(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
+ AssertCacheTelemetry(testTelemetryClient, CacheLevel.None);
- result = await CreateAppAndGetTokenAsync(CacheType.InMemory, addTokenMock: false).ConfigureAwait(false);
+ result = await CreateAppAndGetTokenAsync(CacheType.InMemory, testTelemetryClient, addTokenMock: false).ConfigureAwait(false);
Assert.Equal(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
+ AssertCacheTelemetry(testTelemetryClient, CacheLevel.L1Cache);
+
+ //Resetting token caches due to potential collision with other tests
+ TokenCacheExtensions.s_serviceProviderFromAction.Clear();
// new DistributedInMemory and same cca
- result = await CreateAppAndGetTokenAsync(CacheType.DistributedInMemory).ConfigureAwait(false);
+ result = await CreateAppAndGetTokenAsync(CacheType.DistributedInMemory, testTelemetryClient).ConfigureAwait(false);
+ Assert.Equal(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
+ AssertCacheTelemetry(testTelemetryClient, CacheLevel.None);
+
+ result = await CreateAppAndGetTokenAsync(CacheType.DistributedInMemory, testTelemetryClient, addTokenMock: false).ConfigureAwait(false);
+ Assert.Equal(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
+ AssertCacheTelemetry(testTelemetryClient, CacheLevel.L1Cache);
+ }
+
+ [Fact]
+ public async Task CacheExtensions_CcaAlreadyExistsL2_TestsAsync()
+ {
+ AuthenticationResult result;
+ TestTelemetryClient testTelemetryClient = new TestTelemetryClient(TestConstants.ClientId);
+ // new DistributedInMemory serializer with L1 cache disabled
+ result = await CreateAppAndGetTokenAsync(CacheType.DistributedInMemory, testTelemetryClient, disableL1Cache: true).ConfigureAwait(false);
Assert.Equal(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
+ AssertCacheTelemetry(testTelemetryClient, CacheLevel.None);
- result = await CreateAppAndGetTokenAsync(CacheType.DistributedInMemory, addTokenMock: false).ConfigureAwait(false);
+ result = await CreateAppAndGetTokenAsync(CacheType.DistributedInMemory, testTelemetryClient, addTokenMock: false, disableL1Cache: true).ConfigureAwait(false);
Assert.Equal(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
+ AssertCacheTelemetry(testTelemetryClient, CacheLevel.L2Cache);
}
[Fact]
@@ -68,7 +95,7 @@ public void InMemoryCache_WithServices_ExtensionsTests()
[Fact]
public void InMemoryCache_WithServices_NoCca_ThrowsException_Tests()
- {
+ {
IConfidentialClientApplication confidentialApp = null!;
var ex = Assert.Throws(() => confidentialApp.AddInMemoryTokenCache(services =>
{
@@ -102,7 +129,7 @@ public void DistributedCacheExtensionsTests()
[Fact]
public void DistributedCacheExtensions_NoCca_ThrowsException_Tests()
- {
+ {
IConfidentialClientApplication confidentialApp = null!;
var ex = Assert.Throws(() => confidentialApp.AddDistributedTokenCache(services =>
{
@@ -119,49 +146,52 @@ public void DistributedCacheExtensions_NoService_ThrowsException_Tests()
var ex = Assert.Throws(() => confidentialApp.AddDistributedTokenCache(null!));
Assert.Equal("initializeDistributedCache", ex.ParamName);
- }
-
+ }
+
[Fact]
- public async Task SingletonMsal_ResultsInCorrectCacheEntries_Test()
- {
- var tenantId1 = "tenant1";
- var tenantId2 = "tenant2";
- var cacheKey1 = $"{TestConstants.ClientId}_{tenantId1}_AppTokenCache";
- var cacheKey2 = $"{TestConstants.ClientId}_{tenantId2}_AppTokenCache";
-
+ public async Task SingletonMsal_ResultsInCorrectCacheEntries_Test()
+ {
+ var tenantId1 = "tenant1";
+ var tenantId2 = "tenant2";
+ var cacheKey1 = $"{TestConstants.ClientId}_{tenantId1}_AppTokenCache";
+ var cacheKey2 = $"{TestConstants.ClientId}_{tenantId2}_AppTokenCache";
+
+ //Resetting token caches due to potential collision with other tests
+ TokenCacheExtensions.s_serviceProviderFromAction.Clear();
+
using MockHttpClientFactory mockHttpClient = new MockHttpClientFactory();
using (mockHttpClient.AddMockHandler(MockHttpCreator.CreateClientCredentialTokenHandler()))
- using (mockHttpClient.AddMockHandler(MockHttpCreator.CreateClientCredentialTokenHandler()))
- {
- var confidentialApp = ConfidentialClientApplicationBuilder
- .Create(TestConstants.ClientId)
- .WithAuthority(TestConstants.AuthorityCommonTenant)
- .WithHttpClientFactory(mockHttpClient)
- .WithInstanceDiscovery(false)
- .WithClientSecret(TestConstants.ClientSecret)
- .Build();
-
- var distributedCache = new TestDistributedCache();
- confidentialApp.AddDistributedTokenCache(services =>
- {
- services.AddSingleton(distributedCache);
- });
-
- // Different tenants used to created different cache entries
- var result1 = await confidentialApp.AcquireTokenForClient(new[] { TestConstants.s_scopeForApp })
- .WithTenantId(tenantId1)
- .ExecuteAsync().ConfigureAwait(false);
- var result2 = await confidentialApp.AcquireTokenForClient(new[] { TestConstants.s_scopeForApp })
- .WithTenantId(tenantId2)
- .ExecuteAsync().ConfigureAwait(false);
-
- Assert.Equal(TokenSource.IdentityProvider, result1.AuthenticationResultMetadata.TokenSource);
- Assert.Equal(TokenSource.IdentityProvider, result2.AuthenticationResultMetadata.TokenSource);
- Assert.Equal(2, distributedCache._dict.Count);
- Assert.Equal(distributedCache.Get(cacheKey1)!.Length, distributedCache.Get(cacheKey2)!.Length);
- }
- }
-
+ using (mockHttpClient.AddMockHandler(MockHttpCreator.CreateClientCredentialTokenHandler()))
+ {
+ var confidentialApp = ConfidentialClientApplicationBuilder
+ .Create(TestConstants.ClientId)
+ .WithAuthority(TestConstants.AuthorityCommonTenant)
+ .WithHttpClientFactory(mockHttpClient)
+ .WithInstanceDiscovery(false)
+ .WithClientSecret(TestConstants.ClientSecret)
+ .Build();
+
+ var distributedCache = new TestDistributedCache();
+ confidentialApp.AddDistributedTokenCache(services =>
+ {
+ services.AddSingleton(distributedCache);
+ });
+
+ // Different tenants used to created different cache entries
+ var result1 = await confidentialApp.AcquireTokenForClient(new[] { TestConstants.s_scopeForApp })
+ .WithTenantId(tenantId1)
+ .ExecuteAsync().ConfigureAwait(false);
+ var result2 = await confidentialApp.AcquireTokenForClient(new[] { TestConstants.s_scopeForApp })
+ .WithTenantId(tenantId2)
+ .ExecuteAsync().ConfigureAwait(false);
+
+ Assert.Equal(TokenSource.IdentityProvider, result1.AuthenticationResultMetadata.TokenSource);
+ Assert.Equal(TokenSource.IdentityProvider, result2.AuthenticationResultMetadata.TokenSource);
+ Assert.Equal(2, distributedCache._dict.Count);
+ Assert.Equal(distributedCache.Get(cacheKey1)!.Length, distributedCache.Get(cacheKey2)!.Length);
+ }
+ }
+
private enum CacheType
{
InMemory,
@@ -170,21 +200,20 @@ private enum CacheType
private static async Task CreateAppAndGetTokenAsync(
CacheType cacheType,
+ ITelemetryClient telemetryClient,
bool addTokenMock = true,
- bool addInstanceMock = false)
+ bool disableL1Cache = false)
{
using MockHttpClientFactory mockHttp = new MockHttpClientFactory();
- using var discoveryHandler = MockHttpCreator.CreateInstanceDiscoveryMockHandler();
using var tokenHandler = MockHttpCreator.CreateClientCredentialTokenHandler();
- if (addInstanceMock)
- {
- mockHttp.AddMockHandler(discoveryHandler);
- }
// for when the token is requested from ESTS
if (addTokenMock)
{
mockHttp.AddMockHandler(tokenHandler);
+
+ //Enables the mock handler to requeue requests that have been intercepted for instance discovery for example
+ tokenHandler.ReplaceMockHttpMessageHandler = mockHttp.AddMockHandler;
}
var confidentialApp = ConfidentialClientApplicationBuilder
@@ -192,6 +221,7 @@ private static async Task CreateAppAndGetTokenAsync(
.WithAuthority(TestConstants.AuthorityCommonTenant)
.WithHttpClientFactory(mockHttp)
.WithClientSecret(TestConstants.ClientSecret)
+ .WithTelemetryClient(telemetryClient)
.Build();
switch (cacheType)
@@ -206,6 +236,14 @@ private static async Task CreateAppAndGetTokenAsync(
services.AddDistributedMemoryCache();
services.AddLogging(configure => configure.AddConsole())
.Configure(options => options.MinLevel = Microsoft.Extensions.Logging.LogLevel.Warning);
+
+ if (disableL1Cache)
+ {
+ services.Configure(options =>
+ {
+ options.DisableL1Cache = true;
+ });
+ }
});
break;
}
@@ -213,10 +251,17 @@ private static async Task CreateAppAndGetTokenAsync(
var result = await confidentialApp.AcquireTokenForClient(new[] { TestConstants.s_scopeForApp })
.ExecuteAsync().ConfigureAwait(false);
+ tokenHandler.ReplaceMockHttpMessageHandler = null!;
return result;
}
- private IConfidentialClientApplication CreateCca() =>
+ private void AssertCacheTelemetry(TestTelemetryClient testTelemetryClient, CacheLevel cacheLevel)
+ {
+ TelemetryEventDetails eventDetails = testTelemetryClient.TestTelemetryEventDetails;
+ Assert.Equal(Convert.ToInt64(cacheLevel, new CultureInfo("en-US")), eventDetails.Properties["CacheLevel"]);
+ }
+
+ private IConfidentialClientApplication CreateCca() =>
ConfidentialClientApplicationBuilder
.Create(TestConstants.ClientId)
.WithAuthority(TestConstants.AuthorityCommonTenant)
diff --git a/tests/Microsoft.Identity.Web.Test/L1L2CacheTests.cs b/tests/Microsoft.Identity.Web.Test/L1L2CacheTests.cs
index df3ca637d..8857f3d38 100644
--- a/tests/Microsoft.Identity.Web.Test/L1L2CacheTests.cs
+++ b/tests/Microsoft.Identity.Web.Test/L1L2CacheTests.cs
@@ -7,6 +7,8 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using Microsoft.Identity.Client.Cache;
+using Microsoft.Identity.Client.TelemetryCore.TelemetryClient;
using Microsoft.Identity.Web.Test.Common.TestHelpers;
using Microsoft.Identity.Web.TokenCacheProviders;
using Microsoft.Identity.Web.TokenCacheProviders.Distributed;
@@ -181,6 +183,7 @@ public async Task SetL1Cache_ReadL1_TestAsync()
// Arrange
byte[] cache = new byte[3];
cache[0] = 4;
+ TelemetryData telemetryData = new TelemetryData();
AssertCacheValues(_testCacheAdapter);
Assert.NotNull(_testCacheAdapter._memoryCache);
Assert.Equal(0, _testCacheAdapter._memoryCache.Count);
@@ -189,11 +192,12 @@ public async Task SetL1Cache_ReadL1_TestAsync()
Assert.Empty(L2Cache._dict);
// Act
- byte[]? result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey).ConfigureAwait(false);
+ byte[]? result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey, telemetryData).ConfigureAwait(false);
// Assert
Assert.NotNull(result);
Assert.Equal(4, result[0]);
+ Assert.Equal(CacheLevel.L1Cache, telemetryData.CacheLevel);
}
[Fact]
@@ -202,6 +206,7 @@ public async Task EmptyL1Cache_ReadL2AndSetL1_TestAsync()
// Arrange
byte[] cache = new byte[3];
cache[0] = 4;
+ TelemetryData telemetryData = new TelemetryData();
AssertCacheValues(_testCacheAdapter);
_testCacheAdapter._distributedCache.Set(DefaultCacheKey, cache);
Assert.Single(L2Cache._dict);
@@ -209,13 +214,48 @@ public async Task EmptyL1Cache_ReadL2AndSetL1_TestAsync()
Assert.Equal(0, _testCacheAdapter._memoryCache.Count);
// Act
- byte[]? result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey).ConfigureAwait(false);
+ byte[]? result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey, telemetryData).ConfigureAwait(false);
// Assert
Assert.NotNull(result);
Assert.Equal(4, result[0]);
Assert.Equal(1, _testCacheAdapter._memoryCache.Count);
Assert.Single(L2Cache._dict);
+ Assert.Equal(CacheLevel.L2Cache, telemetryData.CacheLevel);
+ }
+
+ [Fact]
+ public async Task EmptyL1Cache_ReadL2AndSetL1_ForTelemetryTestAsync()
+ {
+ // Arrange
+ byte[] cache = new byte[3];
+ cache[0] = 4;
+ AssertCacheValues(_testCacheAdapter);
+ _testCacheAdapter._distributedCache.Set(DefaultCacheKey, cache);
+ TelemetryData telemetryData = new TelemetryData();
+ Assert.Single(L2Cache._dict);
+ Assert.NotNull(_testCacheAdapter._memoryCache);
+ Assert.Equal(0, _testCacheAdapter._memoryCache.Count);
+
+ // Act
+ byte[]? result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey, telemetryData).ConfigureAwait(false);
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.Equal(4, result[0]);
+ Assert.Equal(1, _testCacheAdapter._memoryCache.Count);
+ Assert.Single(L2Cache._dict);
+ Assert.Equal(CacheLevel.L2Cache, telemetryData.CacheLevel);
+
+ // Act
+ result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey, telemetryData).ConfigureAwait(false);
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.Equal(4, result[0]);
+ Assert.Equal(1, _testCacheAdapter._memoryCache.Count);
+ Assert.Single(L2Cache._dict);
+ Assert.Equal(CacheLevel.L1Cache, telemetryData.CacheLevel);
}
[Fact]
@@ -224,17 +264,19 @@ public async Task EmptyL1L2Cache_ReturnNullCacheResult_TestAsync()
// Arrange
byte[] cache = new byte[3];
cache[0] = 4;
+ TelemetryData telemetryData = new TelemetryData();
AssertCacheValues(_testCacheAdapter);
Assert.NotNull(_testCacheAdapter._memoryCache);
Assert.Equal(0, _testCacheAdapter._memoryCache.Count);
// Act
- byte[]? result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey).ConfigureAwait(false);
+ byte[]? result = await _testCacheAdapter.TestReadCacheBytesAsync(DefaultCacheKey, telemetryData).ConfigureAwait(false);
// Assert
Assert.Null(result);
Assert.Equal(0, _testCacheAdapter._memoryCache.Count);
Assert.Empty(L2Cache._dict);
+ Assert.Equal(CacheLevel.None, telemetryData.CacheLevel);
}
[Fact]
diff --git a/tests/Microsoft.Identity.Web.Test/Microsoft.Identity.Web.Test.csproj b/tests/Microsoft.Identity.Web.Test/Microsoft.Identity.Web.Test.csproj
index f904618b0..cb7d90629 100644
--- a/tests/Microsoft.Identity.Web.Test/Microsoft.Identity.Web.Test.csproj
+++ b/tests/Microsoft.Identity.Web.Test/Microsoft.Identity.Web.Test.csproj
@@ -43,6 +43,7 @@
+
diff --git a/tests/Microsoft.Identity.Web.Test/TestTelemetryClient.cs b/tests/Microsoft.Identity.Web.Test/TestTelemetryClient.cs
new file mode 100644
index 000000000..37fa1e687
--- /dev/null
+++ b/tests/Microsoft.Identity.Web.Test/TestTelemetryClient.cs
@@ -0,0 +1,59 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.IdentityModel.Abstractions;
+
+namespace Microsoft.Identity.Web.Test
+{
+ internal class TestTelemetryClient : ITelemetryClient
+ {
+ private const string _eventName = "acquire_token";
+ public TelemetryEventDetails TestTelemetryEventDetails { get; set; }
+
+ public TestTelemetryClient(string clientId)
+ {
+ ClientId = clientId;
+ TestTelemetryEventDetails = new MsalTelemetryEventDetails(_eventName);
+ }
+
+ public string ClientId { get; set; }
+
+ public void Initialize()
+ {
+
+ }
+
+ public bool IsEnabled()
+ {
+ return true;
+ }
+
+ public bool IsEnabled(string eventName)
+ {
+ return _eventName.Equals(eventName, StringComparison.Ordinal);
+ }
+
+ public void TrackEvent(TelemetryEventDetails eventDetails)
+ {
+ TestTelemetryEventDetails = eventDetails;
+ }
+
+ public void TrackEvent(string eventName, IDictionary stringProperties, IDictionary longProperties, IDictionary boolProperties, IDictionary dateTimeProperties, IDictionary doubleProperties, IDictionary guidProperties)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ internal class MsalTelemetryEventDetails : TelemetryEventDetails
+ {
+ public MsalTelemetryEventDetails(string eventName)
+ {
+ Name = eventName;
+ }
+ }
+}