Skip to content

Commit b90fd0e

Browse files
committed
add tests for new functionality
1 parent 23aa9e7 commit b90fd0e

File tree

6 files changed

+131
-23
lines changed

6 files changed

+131
-23
lines changed

.github/workflows/dotnetcore.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ jobs:
4242
- name: Build solution
4343
run: msbuild Microsoft.Identity.Web.sln -r -t:build -verbosity:m -property:Configuration=Release
4444

45-
- name: Test with .NET 6.0.x
46-
run: dotnet test --no-restore --no-build Microsoft.Identity.Web.sln -f net6.0 -v normal -p:FROM_GITHUB_ACTION=true --configuration Release --filter "(FullyQualifiedName!~Microsoft.Identity.Web.Test.Integration)&(FullyQualifiedName!~WebAppUiTests)&(FullyQualifiedName!~IntegrationTests)&(FullyQualifiedName!~TokenAcquirerTests)"
47-
4845
- name: Test with .NET 8.0.x
4946
run: dotnet test --no-restore --no-build Microsoft.Identity.Web.sln -f net8.0 -v normal -p:FROM_GITHUB_ACTION=true --configuration Release --collect "Xplat Code Coverage" --filter "(FullyQualifiedName!~Microsoft.Identity.Web.Test.Integration)&(FullyQualifiedName!~WebAppUiTests)&(FullyQualifiedName!~IntegrationTests)&(FullyQualifiedName!~TokenAcquirerTests)"
5047

5148
- name: Test with .NET 9.0.x
5249
run: dotnet test --no-restore --no-build Microsoft.Identity.Web.sln -f net9.0 -v normal -p:FROM_GITHUB_ACTION=true --configuration Release --collect "Xplat Code Coverage" --filter "(FullyQualifiedName!~Microsoft.Identity.Web.Test.Integration)&(FullyQualifiedName!~WebAppUiTests)&(FullyQualifiedName!~IntegrationTests)&(FullyQualifiedName!~TokenAcquirerTests)"
5350

51+
- name: Test with .NET 6.0.x
52+
run: dotnet test Microsoft.Identity.Web.sln -f net6.0 -v normal -p:FROM_GITHUB_ACTION=true --configuration Release --filter "(FullyQualifiedName!~Microsoft.Identity.Web.Test.Integration)&(FullyQualifiedName!~WebAppUiTests)&(FullyQualifiedName!~IntegrationTests)&(FullyQualifiedName!~TokenAcquirerTests)"
53+
5454
- name: Create code coverage report
5555
run: |
5656
dotnet tool install -g dotnet-reportgenerator-globaltool --version 5.4.1

src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquirerFactory.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ protected TokenAcquirerFactory()
110110
return (defaultInstance as T)!;
111111
}
112112

113-
114113
/// <summary>
115114
/// Get the default instance. Use this method to retrieve the instance, optionally add some services to
116115
/// the service collection, and build the instance.
@@ -148,7 +147,7 @@ static public TokenAcquirerFactory GetDefaultInstance(string configSection = "Az
148147
});
149148
instance.Services.AddSingleton<ITokenAcquirerFactory, DefaultTokenAcquirerFactoryImplementation>();
150149
instance.Services.AddSingleton(defaultInstance.Configuration);
151-
}
150+
}
152151
}
153152
}
154153
return defaultInstance!;

tests/DevApps/aspnet-mvc/OwinWebApi/Web.config

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@
5858
</dependentAssembly>
5959
<dependentAssembly>
6060
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
61-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
61+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
6262
</dependentAssembly>
6363
<dependentAssembly>
6464
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="CC7B13FFCD2DDD51" culture="neutral"/>
65-
<bindingRedirect oldVersion="0.0.0.0-6.0.0.2" newVersion="6.0.0.2"/>
65+
<bindingRedirect oldVersion="0.0.0.0-6.0.0.1" newVersion="6.0.0.1"/>
6666
</dependentAssembly>
6767
<dependentAssembly>
6868
<assemblyIdentity name="System.Buffers" publicKeyToken="CC7B13FFCD2DDD51" culture="neutral"/>
@@ -74,31 +74,31 @@
7474
</dependentAssembly>
7575
<dependentAssembly>
7676
<assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
77-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
77+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
7878
</dependentAssembly>
7979
<dependentAssembly>
8080
<assemblyIdentity name="Microsoft.IdentityModel.Protocols.WsFederation" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
8181
<bindingRedirect oldVersion="0.0.0.0-5.5.0.0" newVersion="5.5.0.0"/>
8282
</dependentAssembly>
8383
<dependentAssembly>
8484
<assemblyIdentity name="Microsoft.IdentityModel.Protocols.OpenIdConnect" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
85-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
85+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
8686
</dependentAssembly>
8787
<dependentAssembly>
8888
<assemblyIdentity name="Microsoft.IdentityModel.Protocols" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
89-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
89+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
9090
</dependentAssembly>
9191
<dependentAssembly>
9292
<assemblyIdentity name="Microsoft.IdentityModel.Logging" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
93-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
93+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
9494
</dependentAssembly>
9595
<dependentAssembly>
9696
<assemblyIdentity name="Microsoft.IdentityModel.Abstractions" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
97-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
97+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
9898
</dependentAssembly>
9999
<dependentAssembly>
100100
<assemblyIdentity name="Microsoft.Identity.Client" publicKeyToken="0A613F4DD989E8AE" culture="neutral"/>
101-
<bindingRedirect oldVersion="0.0.0.0-4.68.0.0" newVersion="4.68.0.0"/>
101+
<bindingRedirect oldVersion="0.0.0.0-4.67.2.0" newVersion="4.67.2.0"/>
102102
</dependentAssembly>
103103
<dependentAssembly>
104104
<assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="ADB9793829DDAE60" culture="neutral"/>

tests/DevApps/aspnet-mvc/OwinWebApp/Web.config

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@
5959
</dependentAssembly>
6060
<dependentAssembly>
6161
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
62-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
62+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
6363
</dependentAssembly>
6464
<dependentAssembly>
6565
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="CC7B13FFCD2DDD51" culture="neutral"/>
66-
<bindingRedirect oldVersion="0.0.0.0-6.0.0.2" newVersion="6.0.0.2"/>
66+
<bindingRedirect oldVersion="0.0.0.0-6.0.0.1" newVersion="6.0.0.1"/>
6767
</dependentAssembly>
6868
<dependentAssembly>
6969
<assemblyIdentity name="System.Buffers" publicKeyToken="CC7B13FFCD2DDD51" culture="neutral"/>
@@ -75,31 +75,31 @@
7575
</dependentAssembly>
7676
<dependentAssembly>
7777
<assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
78-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
78+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
7979
</dependentAssembly>
8080
<dependentAssembly>
8181
<assemblyIdentity name="Microsoft.IdentityModel.Protocols.WsFederation" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
8282
<bindingRedirect oldVersion="0.0.0.0-5.5.0.0" newVersion="5.5.0.0"/>
8383
</dependentAssembly>
8484
<dependentAssembly>
8585
<assemblyIdentity name="Microsoft.IdentityModel.Protocols.OpenIdConnect" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
86-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
86+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
8787
</dependentAssembly>
8888
<dependentAssembly>
8989
<assemblyIdentity name="Microsoft.IdentityModel.Protocols" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
90-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
90+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
9191
</dependentAssembly>
9292
<dependentAssembly>
9393
<assemblyIdentity name="Microsoft.IdentityModel.Logging" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
94-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
94+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
9595
</dependentAssembly>
9696
<dependentAssembly>
9797
<assemblyIdentity name="Microsoft.IdentityModel.Abstractions" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
98-
<bindingRedirect oldVersion="0.0.0.0-8.6.0.0" newVersion="8.6.0.0"/>
98+
<bindingRedirect oldVersion="0.0.0.0-8.3.1.0" newVersion="8.3.1.0"/>
9999
</dependentAssembly>
100100
<dependentAssembly>
101101
<assemblyIdentity name="Microsoft.Identity.Client" publicKeyToken="0A613F4DD989E8AE" culture="neutral"/>
102-
<bindingRedirect oldVersion="0.0.0.0-4.68.0.0" newVersion="4.68.0.0"/>
102+
<bindingRedirect oldVersion="0.0.0.0-4.67.2.0" newVersion="4.67.2.0"/>
103103
</dependentAssembly>
104104
<dependentAssembly>
105105
<assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="ADB9793829DDAE60" culture="neutral"/>

tests/Microsoft.Identity.Web.Test.Common/Microsoft.Identity.Web.Test.Common.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFrameworks>net462; net472; net6.0; net8.0; net9.0</TargetFrameworks>
@@ -17,7 +17,6 @@
1717
<PackageReference Include="Microsoft.Identity.Lab.Api" Version="$(MicrosoftIdentityLabApiVersion)" />
1818
<PackageReference Include="NSubstitute" Version="$(NSubstituteVersion)" />
1919
<PackageReference Include="xunit" Version="$(XunitVersion)" />
20-
<PackageReference Include="xunit.assert" Version="$(XunitAssertVersion)" />
2120
<PackageReference Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
2221
<PackageReference Include="System.Net.Http" Version="$(SystemNetHttpVersion)" />
2322
<PackageReference Include="System.Text.RegularExpressions" Version="$(SystemTextRegularExpressions)" />
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Threading.Tasks;
6+
using Microsoft.Identity.Web.Test.Common;
7+
using Xunit;
8+
9+
namespace Microsoft.Identity.Web.Test
10+
{
11+
[Collection(nameof(TokenAcquirerFactorySingletonProtection))]
12+
public class TokenAcquirerFactoryTests
13+
{
14+
private readonly int numberOfIterations = 5;
15+
16+
[Fact]
17+
public void Build_ThrowsInvalidOperationException_WhenCalledTwiceConcurrently()
18+
{
19+
// Locally this test failed appropriately on the first run every time when the relevant locks were removed.
20+
// However, for robustness, we run it multiple times to protect against false positives in the future.
21+
for (int i = 0; i < numberOfIterations; i++)
22+
{
23+
// Arrange
24+
TokenAcquirerFactory.ResetDefaultInstance();
25+
var testFactory = TokenAcquirerFactory.GetDefaultInstance();
26+
27+
// Act & Assert
28+
try
29+
{
30+
var exception = Assert.Throws<AggregateException>(() =>
31+
{
32+
Parallel.Invoke(
33+
() => testFactory.Build(),
34+
() => testFactory.Build()
35+
);
36+
});
37+
Assert.Single(exception.InnerExceptions);
38+
Assert.All(exception.InnerExceptions, ex => Assert.IsType<InvalidOperationException>(ex));
39+
}
40+
catch (Exception ex)
41+
{
42+
throw new Exception($"Test failed on iteration {i}", ex);
43+
}
44+
}
45+
}
46+
47+
[Fact]
48+
public void GetDefaultInstance_ParallelExecutionGeneric()
49+
{
50+
// Locally this test failed appropriately on the first run every time when the relevant locks were removed.
51+
// However, for robustness, we run it multiple times to protect against false positives in the future.
52+
for (int i = 0; i < numberOfIterations; i++)
53+
{
54+
// Arrange
55+
TokenAcquirerFactoryWithCounter.ResetDefaultInstance();
56+
// Act
57+
Parallel.Invoke(
58+
() => TokenAcquirerFactoryWithCounter.GetDefaultInstance<TokenAcquirerFactoryWithCounter>(),
59+
() => TokenAcquirerFactoryWithCounter.GetDefaultInstance<TokenAcquirerFactoryWithCounter>(),
60+
() => TokenAcquirerFactoryWithCounter.GetDefaultInstance<TokenAcquirerFactoryWithCounter>(),
61+
() => TokenAcquirerFactoryWithCounter.GetDefaultInstance<TokenAcquirerFactoryWithCounter>()
62+
);
63+
// Assert
64+
Assert.Equal(1, TokenAcquirerFactoryWithCounter.InstanceCount);
65+
}
66+
}
67+
68+
/// <summary>
69+
/// Due to how the non-Generic GetDefaultInstance method creates a new TokenAcquirerFactory instance immediately, it is not easy to
70+
/// test concurrent access without adding a counter to the TokenAcquirerFactory class. This test is for manual testing only to avoid
71+
/// adding a counter to the class and method permanently so to use this test uncomment the lines using s_defaultInstanceCounter, make
72+
/// the member inside the TokenAcquirerFactory class, and increment in the constructor. Don't forget to reset it between tests.
73+
/// The current lock implementation as of March 2025 has been tested to work correctly.
74+
/// </summary>
75+
[Fact(Skip = "Requires manual testing")]
76+
public void GetDefaultInstance_ParallelExecutionNonGeneric()
77+
{
78+
// Arrange
79+
TokenAcquirerFactory.ResetDefaultInstance();
80+
//TokenAcquirerFactory.s_defaultInstanceCounter = 0;
81+
82+
// Act
83+
Parallel.Invoke(
84+
() => TokenAcquirerFactory.GetDefaultInstance(),
85+
() => TokenAcquirerFactory.GetDefaultInstance(),
86+
() => TokenAcquirerFactory.GetDefaultInstance(),
87+
() => TokenAcquirerFactory.GetDefaultInstance()
88+
);
89+
90+
// Assert
91+
//Assert.Equal(1, TokenAcquirerFactory.s_defaultInstanceCounter);
92+
}
93+
}
94+
95+
public class TokenAcquirerFactoryWithCounter : TokenAcquirerFactory
96+
{
97+
public static int InstanceCount { get; private set; } = 0;
98+
99+
public TokenAcquirerFactoryWithCounter()
100+
{
101+
InstanceCount++;
102+
}
103+
104+
public static new void ResetDefaultInstance()
105+
{
106+
TokenAcquirerFactory.ResetDefaultInstance();
107+
InstanceCount = 0;
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)