From 530f32503ce3c36659e05c3d6fb262aa05b28a7a Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Wed, 12 Nov 2025 15:56:15 +0800 Subject: [PATCH 01/11] add Audience error handling policy --- .../src/AudienceErrorHandlingPolicy.cs | 65 +++++++++++++++++++ .../src/Azure.Data.AppConfiguration.csproj | 1 + .../src/ConfigurationClient.cs | 2 +- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs new file mode 100644 index 000000000000..56fb1270d06d --- /dev/null +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.Identity; + +namespace Azure.Data.AppConfiguration +{ + /// + /// Pipeline policy that inspects instances for the Entra ID token audience error code (AADSTS500011) and rethrows a new exception with clearer guidance. + /// + internal class AudienceErrorHandlingPolicy : HttpPipelinePolicy + { + private bool _isAudienceConfigured; + private const string AadAudienceErrorCode = "AADSTS500011"; + private const string NoAudienceErrorMessage = "Unable to authenticate to Azure App Configuration. No authentication token audience was provided. Please set ConfigurationClientOptions.Audience to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; + private const string WrongAudienceErrorMessage = "Unable to authenticate to Azure App Configuration. An incorrect token audience was provided. Please set ConfigurationClientOptions.Audience to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; + + public AudienceErrorHandlingPolicy(bool isAudienceConfigured) + { + _isAudienceConfigured = isAudienceConfigured; + } + + public override void Process(HttpMessage message, ReadOnlyMemory pipeline) + { + try + { + ProcessNext(message, pipeline); + } + catch (AuthenticationFailedException ex) + { + HandleAuthenticationAudienceError(ex); + throw; + } + } + + public override async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory pipeline) + { + try + { + await ProcessNextAsync(message, pipeline).ConfigureAwait(false); + } + catch (AuthenticationFailedException ex) + { + HandleAuthenticationAudienceError(ex); + throw; + } + } + + private void HandleAuthenticationAudienceError(AuthenticationFailedException ex) + { + // Message string matching is used because AAD error codes are embedded in the exception message. + if (!ex.Message.Contains(AadAudienceErrorCode, StringComparison.OrdinalIgnoreCase)) + { + return; + } + + string message = _isAudienceConfigured ? WrongAudienceErrorMessage : NoAudienceErrorMessage; + throw new AuthenticationFailedException(message, ex); + } + } +} diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj index 6012044c7b8c..dbc1e2530a62 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj @@ -14,6 +14,7 @@ + diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs index 7b63921eb5b1..be24b889c12a 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs @@ -200,7 +200,7 @@ private static HttpPipeline CreatePipeline(ConfigurationClientOptions options, H { return HttpPipelineBuilder.Build(options, new HttpPipelinePolicy[] { new CustomHeadersPolicy(), new QueryParamPolicy() }, - new HttpPipelinePolicy[] { authenticationPolicy, syncTokenPolicy }, + new HttpPipelinePolicy[] { new AudienceErrorHandlingPolicy(options.Audience != null), authenticationPolicy, syncTokenPolicy }, new ResponseClassifier()); } From b40d5c68addf8484d14d5fae65ea74eea304a777 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Wed, 12 Nov 2025 16:19:59 +0800 Subject: [PATCH 02/11] update --- .../src/AudienceErrorHandlingPolicy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs index 56fb1270d06d..a9e8ae75a641 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs @@ -53,7 +53,7 @@ public override async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory private void HandleAuthenticationAudienceError(AuthenticationFailedException ex) { // Message string matching is used because AAD error codes are embedded in the exception message. - if (!ex.Message.Contains(AadAudienceErrorCode, StringComparison.OrdinalIgnoreCase)) + if (!ex.Message.Contains(AadAudienceErrorCode)) { return; } From e608aaabba8a47ca9a098efb5a64f6d9704748c1 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Thu, 13 Nov 2025 14:56:38 +0800 Subject: [PATCH 03/11] not introduce Azure.Identity --- .../src/AudienceErrorHandlingPolicy.cs | 14 +++++++------- .../src/Azure.Data.AppConfiguration.csproj | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs index a9e8ae75a641..f3db0e3ef472 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs @@ -5,12 +5,11 @@ using System.Threading.Tasks; using Azure.Core; using Azure.Core.Pipeline; -using Azure.Identity; namespace Azure.Data.AppConfiguration { /// - /// Pipeline policy that inspects instances for the Entra ID token audience error code (AADSTS500011) and rethrows a new exception with clearer guidance. + /// Pipeline policy that inspects the exception for the Entra ID token audience error code (AADSTS500011) and rethrows a new exception with clearer guidance. /// internal class AudienceErrorHandlingPolicy : HttpPipelinePolicy { @@ -30,7 +29,7 @@ public override void Process(HttpMessage message, ReadOnlyMemory - From 8d5d15fa4485597a630103eacee1920b80790db7 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Thu, 13 Nov 2025 15:39:54 +0800 Subject: [PATCH 04/11] update --- .../src/AudienceErrorHandlingPolicy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs index f3db0e3ef472..f9baee63cc22 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs @@ -13,7 +13,7 @@ namespace Azure.Data.AppConfiguration /// internal class AudienceErrorHandlingPolicy : HttpPipelinePolicy { - private bool _isAudienceConfigured; + private readonly bool _isAudienceConfigured; private const string AadAudienceErrorCode = "AADSTS500011"; private const string NoAudienceErrorMessage = "Unable to authenticate to Azure App Configuration. No authentication token audience was provided. Please set ConfigurationClientOptions.Audience to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; private const string WrongAudienceErrorMessage = "Unable to authenticate to Azure App Configuration. An incorrect token audience was provided. Please set ConfigurationClientOptions.Audience to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; From 4fbea4e254cda73021c7c29b07eab2d1f38d9197 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Thu, 13 Nov 2025 15:53:56 +0800 Subject: [PATCH 05/11] update --- .../src/AudienceErrorHandlingPolicy.cs | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs index f9baee63cc22..6e6748f79c28 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs @@ -9,7 +9,7 @@ namespace Azure.Data.AppConfiguration { /// - /// Pipeline policy that inspects the exception for the Entra ID token audience error code (AADSTS500011) and rethrows a new exception with clearer guidance. + /// Pipeline policy that provides more helpful errors when Entra ID audience misconfiguration is detected. /// internal class AudienceErrorHandlingPolicy : HttpPipelinePolicy { @@ -31,7 +31,12 @@ public override void Process(HttpMessage message, ReadOnlyMemory Date: Mon, 17 Nov 2025 16:40:05 +0800 Subject: [PATCH 06/11] update --- .../src/AudienceErrorHandlingPolicy.cs | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs index 6e6748f79c28..f43e29612763 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/AudienceErrorHandlingPolicy.cs @@ -15,8 +15,8 @@ internal class AudienceErrorHandlingPolicy : HttpPipelinePolicy { private readonly bool _isAudienceConfigured; private const string AadAudienceErrorCode = "AADSTS500011"; - private const string NoAudienceErrorMessage = "Unable to authenticate to Azure App Configuration. No authentication token audience was provided. Please set ConfigurationClientOptions.Audience to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; - private const string WrongAudienceErrorMessage = "Unable to authenticate to Azure App Configuration. An incorrect token audience was provided. Please set ConfigurationClientOptions.Audience to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; + private const string NoAudienceErrorMessage = $"Unable to authenticate to Azure App Configuration. No authentication token audience was provided. Please set {nameof(ConfigurationClientOptions)}.{nameof(ConfigurationClientOptions.Audience)} to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; + private const string WrongAudienceErrorMessage = $"Unable to authenticate to Azure App Configuration. An incorrect token audience was provided. Please set {nameof(ConfigurationClientOptions)}.{nameof(ConfigurationClientOptions.Audience)} to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; public AudienceErrorHandlingPolicy(bool isAudienceConfigured) { @@ -29,15 +29,10 @@ public override void Process(HttpMessage message, ReadOnlyMemory Date: Tue, 18 Nov 2025 11:57:01 +0800 Subject: [PATCH 07/11] add test --- .../Azure.Data.AppConfiguration/assets.json | 2 +- .../tests/AppConfigurationTestEnvironment.cs | 22 +++++++++++++++++++ .../tests/ConfigurationLiveTests.cs | 21 ++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json b/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json index abbad599e8f5..47152acb2fd2 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/appconfiguration/Azure.Data.AppConfiguration", - "Tag": "net/appconfiguration/Azure.Data.AppConfiguration_932ea57074" + "Tag": "net/appconfiguration/Azure.Data.AppConfiguration_254c657d43" } diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs index 8d4e07c832c7..8bc45de6c491 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs @@ -34,5 +34,27 @@ public AppConfigurationAudience GetAudience() throw new NotSupportedException($"Cloud for authority host {authorityHost} is not supported."); } + + public AppConfigurationAudience GetWrongAudience() + { + Uri authorityHost = new(AuthorityHostUrl); + + if (authorityHost == AzureAuthorityHosts.AzurePublicCloud) + { + return AppConfigurationAudience.AzureGovernment; + } + + if (authorityHost == AzureAuthorityHosts.AzureChina) + { + return AppConfigurationAudience.AzureGovernment; + } + + if (authorityHost == AzureAuthorityHosts.AzureGovernment) + { + return AppConfigurationAudience.AzurePublicCloud; + } + + throw new NotSupportedException($"Cloud for authority host {authorityHost} is not supported."); + } } } diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs index 0b9f9384a84e..39068076b87f 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs @@ -189,6 +189,27 @@ public async Task TokenAudienceSpecifiedAudience() } } + // This test validates that the client handles the original audience error and throws a informative exception. + [RecordedTest] + public void TokenAudienceWrongSpecifiedAudience() + { + ConfigurationClientOptions options = new(_serviceVersion) + { + Audience = TestEnvironment.GetWrongAudience(), + Retry = { + MaxRetries = 0 + } + }; + ConfigurationClient service = GetAADClient(options); + ConfigurationSetting testSetting = CreateSetting(); + + RequestFailedException exception = Assert.ThrowsAsync(async () => + { + await service.AddConfigurationSettingAsync(testSetting); + }); + Assert.True(exception.Message.Contains("Unable to authenticate to Azure App Configuration. An incorrect token audience was provided")); + } + [RecordedTest] public async Task DeleteSettingNotFound() { From 89f27062ce99e4d88b5287bc98d9e37eb797c45d Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Tue, 18 Nov 2025 13:18:26 +0800 Subject: [PATCH 08/11] Revert "add test" This reverts commit 414f6c4b2bfa840cbcb9a0d313922d24826a145e. --- .../Azure.Data.AppConfiguration/assets.json | 2 +- .../tests/AppConfigurationTestEnvironment.cs | 22 ------------------- .../tests/ConfigurationLiveTests.cs | 21 ------------------ 3 files changed, 1 insertion(+), 44 deletions(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json b/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json index 47152acb2fd2..abbad599e8f5 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/appconfiguration/Azure.Data.AppConfiguration", - "Tag": "net/appconfiguration/Azure.Data.AppConfiguration_254c657d43" + "Tag": "net/appconfiguration/Azure.Data.AppConfiguration_932ea57074" } diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs index 8bc45de6c491..8d4e07c832c7 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AppConfigurationTestEnvironment.cs @@ -34,27 +34,5 @@ public AppConfigurationAudience GetAudience() throw new NotSupportedException($"Cloud for authority host {authorityHost} is not supported."); } - - public AppConfigurationAudience GetWrongAudience() - { - Uri authorityHost = new(AuthorityHostUrl); - - if (authorityHost == AzureAuthorityHosts.AzurePublicCloud) - { - return AppConfigurationAudience.AzureGovernment; - } - - if (authorityHost == AzureAuthorityHosts.AzureChina) - { - return AppConfigurationAudience.AzureGovernment; - } - - if (authorityHost == AzureAuthorityHosts.AzureGovernment) - { - return AppConfigurationAudience.AzurePublicCloud; - } - - throw new NotSupportedException($"Cloud for authority host {authorityHost} is not supported."); - } } } diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs index 39068076b87f..0b9f9384a84e 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationLiveTests.cs @@ -189,27 +189,6 @@ public async Task TokenAudienceSpecifiedAudience() } } - // This test validates that the client handles the original audience error and throws a informative exception. - [RecordedTest] - public void TokenAudienceWrongSpecifiedAudience() - { - ConfigurationClientOptions options = new(_serviceVersion) - { - Audience = TestEnvironment.GetWrongAudience(), - Retry = { - MaxRetries = 0 - } - }; - ConfigurationClient service = GetAADClient(options); - ConfigurationSetting testSetting = CreateSetting(); - - RequestFailedException exception = Assert.ThrowsAsync(async () => - { - await service.AddConfigurationSettingAsync(testSetting); - }); - Assert.True(exception.Message.Contains("Unable to authenticate to Azure App Configuration. An incorrect token audience was provided")); - } - [RecordedTest] public async Task DeleteSettingNotFound() { From 16d06ee62881bb252cf8cf984f0311a2d9365d03 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Tue, 18 Nov 2025 13:38:52 +0800 Subject: [PATCH 09/11] add unit test --- .../tests/AudienceErrorHandlingPolicyTests.cs | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs new file mode 100644 index 000000000000..10f1eb13fbe9 --- /dev/null +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.Core.TestFramework; +using NUnit.Framework; + +namespace Azure.Data.AppConfiguration.Tests +{ + [TestFixture(true)] + [TestFixture(false)] + public class AudienceErrorHandlingPolicyTests : SyncAsyncPolicyTestBase + { + private const string AadAudienceErrorCode = "AADSTS500011"; // Must match code in AudienceErrorHandlingPolicy + + public AudienceErrorHandlingPolicyTests(bool isAsync) : base(isAsync) + { + } + + private static string ExpectedErrorMessage(bool isAudienceConfigured) + { + string leading = "Unable to authenticate to Azure App Configuration."; + string detail = isAudienceConfigured + ? " An incorrect token audience was provided." + : " No authentication token audience was provided."; + string guidance = $" Please set {nameof(ConfigurationClientOptions)}.{nameof(ConfigurationClientOptions.Audience)} to the appropriate audience for the target cloud. For details on how to configure the authentication token audience visit https://aka.ms/appconfig/client-token-audience."; + return leading + detail + guidance; + } + + private class ThrowingPolicy : HttpPipelinePolicy + { + private readonly string _message; + public ThrowingPolicy(string message) => _message = message; + public override void Process(HttpMessage message, ReadOnlyMemory pipeline) + { + throw new Exception(_message); + } + public override ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory pipeline) + { + throw new Exception(_message); + } + } + + [Test] + public async Task WrapsError_NoAudienceConfigured() + { + await AssertWrapsErrorAsync(isAudienceConfigured: false); + } + + [Test] + public async Task WrapsError_WrongAudienceConfigured() + { + await AssertWrapsErrorAsync(isAudienceConfigured: true); + } + + private async Task AssertWrapsErrorAsync(bool isAudienceConfigured) + { + var transport = new MockTransport(new MockResponse(200)); // Transport won't be reached because throwing policy throws first. + var pipeline = new HttpPipeline( + transport, + new HttpPipelinePolicy[] + { + new AudienceErrorHandlingPolicy(isAudienceConfigured), + new ThrowingPolicy($"Simulated authentication failure {AadAudienceErrorCode}: Resource principal not found") + }, + responseClassifier: null); + + var requestUri = new Uri("http://example.com"); + RequestFailedException ex = Assert.ThrowsAsync(async () => + { + if (IsAsync) + { + var message = pipeline.CreateMessage(); + message.Request.Method = RequestMethod.Get; + message.Request.Uri.Reset(requestUri); + await pipeline.SendAsync(message, CancellationToken.None); + } + else + { + var message = pipeline.CreateMessage(); + message.Request.Method = RequestMethod.Get; + message.Request.Uri.Reset(requestUri); + pipeline.Send(message, CancellationToken.None); + } + }); + + Assert.NotNull(ex); + StringAssert.Contains(ExpectedErrorMessage(isAudienceConfigured), ex.Message); + Assert.NotNull(ex.InnerException); + StringAssert.Contains(AadAudienceErrorCode, ex.InnerException.Message); + } + + [Test] + public async Task NonAudienceError_PassesThrough() + { + var transport = new MockTransport(new MockResponse(200)); + var pipeline = new HttpPipeline( + transport, + new HttpPipelinePolicy[] + { + new AudienceErrorHandlingPolicy(isAudienceConfigured: true), // value irrelevant since code won't match + new ThrowingPolicy("Simulated failure WITHOUT code") + }, + responseClassifier: null); + + var requestUri = new Uri("http://example.com"); + + Exception ex = Assert.ThrowsAsync(async () => + { + if (IsAsync) + { + var message = pipeline.CreateMessage(); + message.Request.Method = RequestMethod.Get; + message.Request.Uri.Reset(requestUri); + await pipeline.SendAsync(message, CancellationToken.None); + } + else + { + var message = pipeline.CreateMessage(); + message.Request.Method = RequestMethod.Get; + message.Request.Uri.Reset(requestUri); + pipeline.Send(message, CancellationToken.None); + } + }); + + Assert.IsNotInstanceOf(ex); // Should not be wrapped + Assert.AreEqual("Simulated failure WITHOUT code", ex.Message); + } + } +} From b8ee403c41e19e3d623c9056055c55eac5fd8441 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Tue, 18 Nov 2025 14:01:09 +0800 Subject: [PATCH 10/11] update --- .../tests/AudienceErrorHandlingPolicyTests.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs index 10f1eb13fbe9..09a557a333a2 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs @@ -46,16 +46,10 @@ public override ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory AssertWrapsErrorAsync(isAudienceConfigured: false); [Test] - public async Task WrapsError_WrongAudienceConfigured() - { - await AssertWrapsErrorAsync(isAudienceConfigured: true); - } + public Task WrapsError_WrongAudienceConfigured() => AssertWrapsErrorAsync(isAudienceConfigured: true); private async Task AssertWrapsErrorAsync(bool isAudienceConfigured) { @@ -95,7 +89,7 @@ private async Task AssertWrapsErrorAsync(bool isAudienceConfigured) } [Test] - public async Task NonAudienceError_PassesThrough() + public void NonAudienceError_PassesThrough() { var transport = new MockTransport(new MockResponse(200)); var pipeline = new HttpPipeline( From 17437862494777514d3478c779089213b50c3574 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Tue, 18 Nov 2025 18:16:33 +0800 Subject: [PATCH 11/11] update --- .../tests/AudienceErrorHandlingPolicyTests.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs index 09a557a333a2..978c3ff82239 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/AudienceErrorHandlingPolicyTests.cs @@ -46,25 +46,27 @@ public override ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory AssertWrapsErrorAsync(isAudienceConfigured: false); + public void WrapsError_NoAudienceConfigured() => AssertWrapsError(isAudienceConfigured: false); [Test] - public Task WrapsError_WrongAudienceConfigured() => AssertWrapsErrorAsync(isAudienceConfigured: true); + public void WrapsError_WrongAudienceConfigured() => AssertWrapsError(isAudienceConfigured: true); - private async Task AssertWrapsErrorAsync(bool isAudienceConfigured) + [Test] + public void NonAudienceError_PassesThrough() { - var transport = new MockTransport(new MockResponse(200)); // Transport won't be reached because throwing policy throws first. + var transport = new MockTransport(new MockResponse(200)); var pipeline = new HttpPipeline( transport, new HttpPipelinePolicy[] { - new AudienceErrorHandlingPolicy(isAudienceConfigured), - new ThrowingPolicy($"Simulated authentication failure {AadAudienceErrorCode}: Resource principal not found") + new AudienceErrorHandlingPolicy(isAudienceConfigured: true), // value irrelevant since code won't match + new ThrowingPolicy("Simulated failure WITHOUT code") }, responseClassifier: null); var requestUri = new Uri("http://example.com"); - RequestFailedException ex = Assert.ThrowsAsync(async () => + + Exception ex = Assert.ThrowsAsync(async () => { if (IsAsync) { @@ -82,28 +84,24 @@ private async Task AssertWrapsErrorAsync(bool isAudienceConfigured) } }); - Assert.NotNull(ex); - StringAssert.Contains(ExpectedErrorMessage(isAudienceConfigured), ex.Message); - Assert.NotNull(ex.InnerException); - StringAssert.Contains(AadAudienceErrorCode, ex.InnerException.Message); + Assert.IsNotInstanceOf(ex); // Should not be wrapped + Assert.AreEqual("Simulated failure WITHOUT code", ex.Message); } - [Test] - public void NonAudienceError_PassesThrough() + private void AssertWrapsError(bool isAudienceConfigured) { - var transport = new MockTransport(new MockResponse(200)); + var transport = new MockTransport(new MockResponse(200)); // Transport won't be reached because throwing policy throws first. var pipeline = new HttpPipeline( transport, new HttpPipelinePolicy[] { - new AudienceErrorHandlingPolicy(isAudienceConfigured: true), // value irrelevant since code won't match - new ThrowingPolicy("Simulated failure WITHOUT code") + new AudienceErrorHandlingPolicy(isAudienceConfigured), + new ThrowingPolicy($"Simulated authentication failure {AadAudienceErrorCode}: Resource principal not found") }, responseClassifier: null); var requestUri = new Uri("http://example.com"); - - Exception ex = Assert.ThrowsAsync(async () => + RequestFailedException ex = Assert.ThrowsAsync(async () => { if (IsAsync) { @@ -121,8 +119,10 @@ public void NonAudienceError_PassesThrough() } }); - Assert.IsNotInstanceOf(ex); // Should not be wrapped - Assert.AreEqual("Simulated failure WITHOUT code", ex.Message); + Assert.NotNull(ex); + StringAssert.Contains(ExpectedErrorMessage(isAudienceConfigured), ex.Message); + Assert.NotNull(ex.InnerException); + StringAssert.Contains(AadAudienceErrorCode, ex.InnerException.Message); } } }