| File: DefaultTokenCredentialProviderTests.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Azure.Tests\Aspire.Hosting.Azure.Tests.csproj (Aspire.Hosting.Azure.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #pragma warning disable ASPIREPIPELINES002 using Aspire.Hosting.Azure.Provisioning; using Aspire.Hosting.Azure.Provisioning.Internal; using Azure.Identity; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; namespace Aspire.Hosting.Azure.Tests; public class DefaultTokenCredentialProviderTests { [Fact] public void Constructor_PublishMode_NoCredentialSource_UsesAzureCli() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: null); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<AzureCliCredential>(provider.TokenCredential); } [Fact] public void Constructor_RunMode_NoCredentialSource_UsesDefaultAzureCredential() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: null); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<DefaultAzureCredential>(provider.TokenCredential); } [Fact] public void Constructor_PublishMode_ExplicitDefaultCredentialSource_UsesAzureCli() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "Default"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<AzureCliCredential>(provider.TokenCredential); } [Fact] public void Constructor_RunMode_ExplicitDefaultCredentialSource_UsesDefaultAzureCredential() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "Default"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<DefaultAzureCredential>(provider.TokenCredential); } [Fact] public void Constructor_PublishMode_ExplicitNonDefaultCredentialSource_RespectsSource() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "AzurePowerShell"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<AzurePowerShellCredential>(provider.TokenCredential); } [Fact] public void Constructor_RunMode_ExplicitCredentialSource_RespectsSource() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "VisualStudio"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<VisualStudioCredential>(provider.TokenCredential); } [Fact] public void Constructor_RunMode_InvalidCredentialSource_UsesDefaultAzureCredential() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "InvalidSource"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<DefaultAzureCredential>(provider.TokenCredential); } [Fact] public void Constructor_RunMode_AzureCliCredentialSource_UsesAzureCliCredential() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "AzureCli"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<AzureCliCredential>(provider.TokenCredential); } [Fact] public void Constructor_RunMode_AzureDeveloperCliCredentialSource_UsesAzureDeveloperCliCredential() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "AzureDeveloperCli"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<AzureDeveloperCliCredential>(provider.TokenCredential); } [Fact] public void Constructor_RunMode_InteractiveBrowserCredentialSource_UsesInteractiveBrowserCredential() { // Arrange var azureOptions = CreateAzureOptions(credentialSource: "InteractiveBrowser"); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); // Act var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, azureOptions, executionContext); // Assert Assert.IsType<InteractiveBrowserCredential>(provider.TokenCredential); } [Fact] public void TokenCredential_TenantIdChanges_RecreatesCredential() { // Arrange var azureOptions = new AzureProvisionerOptions { CredentialSource = "AzureCli", TenantId = "tenant-1" }; var options = new TestOptions<AzureProvisionerOptions>(azureOptions); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish); var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, options, executionContext); // Act - Access credential with first tenant var credential1 = provider.TokenCredential; Assert.IsType<AzureCliCredential>(credential1); // Change tenant ID azureOptions.TenantId = "tenant-2"; // Access credential again var credential2 = provider.TokenCredential; // Assert - Should get a new credential instance Assert.IsType<AzureCliCredential>(credential2); Assert.NotSame(credential1, credential2); } [Fact] public void TokenCredential_TenantIdUnchanged_ReturnsSameCredential() { // Arrange var azureOptions = new AzureProvisionerOptions { CredentialSource = "AzureCli", TenantId = "tenant-1" }; var options = new TestOptions<AzureProvisionerOptions>(azureOptions); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish); var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, options, executionContext); // Act - Access credential multiple times without changing tenant var credential1 = provider.TokenCredential; var credential2 = provider.TokenCredential; var credential3 = provider.TokenCredential; // Assert - Should get the same credential instance Assert.Same(credential1, credential2); Assert.Same(credential2, credential3); } [Fact] public void TokenCredential_TenantIdSetFromNull_RecreatesCredential() { // Arrange var azureOptions = new AzureProvisionerOptions { CredentialSource = "AzureDeveloperCli", TenantId = null }; var options = new TestOptions<AzureProvisionerOptions>(azureOptions); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish); var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, options, executionContext); // Act - Access credential with null tenant var credential1 = provider.TokenCredential; Assert.IsType<AzureDeveloperCliCredential>(credential1); // Set tenant ID azureOptions.TenantId = "70a036f6-8e4d-4615-bad6-149c02e7720d"; // Access credential again var credential2 = provider.TokenCredential; // Assert - Should get a new credential instance Assert.IsType<AzureDeveloperCliCredential>(credential2); Assert.NotSame(credential1, credential2); } [Fact] public void TokenCredential_MultipleCredentialTypes_RespectsCurrentTenantId() { // Arrange var azureOptions = new AzureProvisionerOptions { CredentialSource = "AzurePowerShell", TenantId = "tenant-1" }; var options = new TestOptions<AzureProvisionerOptions>(azureOptions); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run); var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, options, executionContext); // Act - Access credential var credential1 = provider.TokenCredential; Assert.IsType<AzurePowerShellCredential>(credential1); // Change both credential source and tenant ID azureOptions.CredentialSource = "VisualStudio"; azureOptions.TenantId = "tenant-2"; // Access credential again var credential2 = provider.TokenCredential; // Assert - Should get a new credential of the new type Assert.IsType<VisualStudioCredential>(credential2); Assert.NotSame(credential1, credential2); } [Fact] public void TokenCredential_LazyInitialization_DoesNotCreateUntilAccessed() { // Arrange var azureOptions = new AzureProvisionerOptions { CredentialSource = "AzureCli", TenantId = "tenant-1" }; var options = new TestOptions<AzureProvisionerOptions>(azureOptions); var executionContext = new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish); // Act - Create provider but don't access TokenCredential property var provider = new DefaultTokenCredentialProvider( NullLogger<DefaultTokenCredentialProvider>.Instance, options, executionContext); // Change tenant ID before first access azureOptions.TenantId = "tenant-2"; // Now access the credential var credential = provider.TokenCredential; // Assert - Should create credential with the current (second) tenant ID Assert.IsType<AzureCliCredential>(credential); // The credential should have been created with tenant-2, not tenant-1 // We can't directly verify the tenant ID in the credential, but we verified // it was created after the tenant ID change } private static IOptions<AzureProvisionerOptions> CreateAzureOptions(string? credentialSource) { var options = new AzureProvisionerOptions { // Intentionally allow CredentialSource to be null for tests that verify null handling. CredentialSource = credentialSource! }; return Options.Create(options); } /// <summary> /// Test implementation of IOptions that allows modifying the underlying options object. /// </summary> private sealed class TestOptions<T>(T value) : IOptions<T> where T : class { public T Value => value; } }