-
Notifications
You must be signed in to change notification settings - Fork 452
refactor: extract pure resolver methods for subscription resolution #2395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,105 @@ | ||||||||||||||||||
| // Copyright (c) Microsoft Corporation. | ||||||||||||||||||
| // Licensed under the MIT License. | ||||||||||||||||||
|
|
||||||||||||||||||
| using Microsoft.Mcp.Core.Helpers; | ||||||||||||||||||
| using Xunit; | ||||||||||||||||||
|
|
||||||||||||||||||
| namespace Azure.Mcp.Core.UnitTests.Helpers; | ||||||||||||||||||
|
|
||||||||||||||||||
| public class CommandHelperResolverTests | ||||||||||||||||||
| { | ||||||||||||||||||
| // --- ResolveDefaultSubscription tests --- | ||||||||||||||||||
|
|
||||||||||||||||||
| [Fact] | ||||||||||||||||||
| public void ResolveDefaultSubscription_ProfileTakesPriority() | ||||||||||||||||||
| { | ||||||||||||||||||
| var result = CommandHelper.ResolveDefaultSubscription("cli-sub", "env-sub"); | ||||||||||||||||||
| Assert.Equal("cli-sub", result); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| [Fact] | ||||||||||||||||||
| public void ResolveDefaultSubscription_FallsBackToEnv_WhenProfileNull() | ||||||||||||||||||
| { | ||||||||||||||||||
| var result = CommandHelper.ResolveDefaultSubscription(null, "env-sub"); | ||||||||||||||||||
| Assert.Equal("env-sub", result); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| [Fact] | ||||||||||||||||||
| public void ResolveDefaultSubscription_FallsBackToEnv_WhenProfileEmpty() | ||||||||||||||||||
| { | ||||||||||||||||||
| var result = CommandHelper.ResolveDefaultSubscription("", "env-sub"); | ||||||||||||||||||
| Assert.Equal("env-sub", result); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| [Fact] | ||||||||||||||||||
| public void ResolveDefaultSubscription_ReturnsNull_WhenBothNull() | ||||||||||||||||||
| { | ||||||||||||||||||
| var result = CommandHelper.ResolveDefaultSubscription(null, null); | ||||||||||||||||||
| Assert.Null(result); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| [Fact] | ||||||||||||||||||
| public void ResolveDefaultSubscription_ReturnsEnv_WhenBothEmpty() | ||||||||||||||||||
| { | ||||||||||||||||||
| var result = CommandHelper.ResolveDefaultSubscription("", ""); | ||||||||||||||||||
| Assert.Equal("", result); | ||||||||||||||||||
|
Comment on lines
+42
to
+45
|
||||||||||||||||||
| public void ResolveDefaultSubscription_ReturnsEnv_WhenBothEmpty() | |
| { | |
| var result = CommandHelper.ResolveDefaultSubscription("", ""); | |
| Assert.Equal("", result); | |
| public void ResolveDefaultSubscription_ReturnsNull_WhenBothEmpty() | |
| { | |
| var result = CommandHelper.ResolveDefaultSubscription("", ""); | |
| Assert.Null(result); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,34 +7,41 @@ | |
|
|
||
| namespace Azure.Mcp.Core.UnitTests.Helpers; | ||
|
|
||
| public class CommandHelperTests | ||
| public class CommandHelperTests : IDisposable | ||
| { | ||
| public void Dispose() | ||
| { | ||
| EnvironmentHelpers.ClearAzureSubscriptionId(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetSubscription_EmptySubscriptionParameter_ReturnsEnvironmentValue() | ||
| { | ||
| // Arrange | ||
| EnvironmentHelpers.SetAzureSubscriptionId("env-subs"); | ||
| var expected = CommandHelper.GetDefaultSubscription(); | ||
| var parseResult = GetParseResult(["--subscription", ""]); | ||
|
|
||
| // Act | ||
| var actual = CommandHelper.GetSubscription(parseResult); | ||
|
|
||
| // Assert | ||
| Assert.Equal("env-subs", actual); | ||
| Assert.Equal(expected, actual); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetSubscription_MissingSubscriptionParameter_ReturnsEnvironmentValue() | ||
| { | ||
| // Arrange | ||
| EnvironmentHelpers.SetAzureSubscriptionId("env-subs"); | ||
| var expected = CommandHelper.GetDefaultSubscription(); | ||
| var parseResult = GetParseResult([]); | ||
|
|
||
| // Act | ||
| var actual = CommandHelper.GetSubscription(parseResult); | ||
|
|
||
| // Assert | ||
| Assert.Equal("env-subs", actual); | ||
| Assert.Equal(expected, actual); | ||
|
Comment on lines
17
to
+44
|
||
| } | ||
|
|
||
| [Fact] | ||
|
|
@@ -56,53 +63,57 @@ public void GetSubscription_ParameterValueContainingSubscription_ReturnsEnvironm | |
| { | ||
| // Arrange | ||
| EnvironmentHelpers.SetAzureSubscriptionId("env-subs"); | ||
| var expected = CommandHelper.GetDefaultSubscription(); | ||
| var parseResult = GetParseResult(["--subscription", "Azure subscription 1"]); | ||
|
|
||
| // Act | ||
| var actual = CommandHelper.GetSubscription(parseResult); | ||
|
|
||
| // Assert | ||
| Assert.Equal("env-subs", actual); | ||
| Assert.Equal(expected, actual); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetSubscription_ParameterValueContainingDefault_ReturnsEnvironmentValue() | ||
| { | ||
| // Arrange | ||
| EnvironmentHelpers.SetAzureSubscriptionId("env-subs"); | ||
| var expected = CommandHelper.GetDefaultSubscription(); | ||
| var parseResult = GetParseResult(["--subscription", "Some default name"]); | ||
|
|
||
| // Act | ||
| var actual = CommandHelper.GetSubscription(parseResult); | ||
|
|
||
| // Assert | ||
| Assert.Equal("env-subs", actual); | ||
| Assert.Equal(expected, actual); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetSubscription_NoEnvironmentVariableParameterValueContainingDefault_ReturnsParameterValue() | ||
| { | ||
| // Arrange | ||
| var subscription = CommandHelper.GetProfileSubscription(); | ||
| var parseResult = GetParseResult(["--subscription", "Some default name"]); | ||
|
|
||
| // Act | ||
| var actual = CommandHelper.GetSubscription(parseResult); | ||
|
|
||
| // Assert | ||
| Assert.Equal("Some default name", actual); | ||
| Assert.Equal(subscription ?? "Some default name", actual); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetSubscription_NoEnvironmentVariableParameterValueContainingSubscription_ReturnsParameterValue() | ||
| { | ||
| // Arrange | ||
| var subscription = CommandHelper.GetProfileSubscription(); | ||
| var parseResult = GetParseResult(["--subscription", "Azure subscription 1"]); | ||
|
|
||
| // Act | ||
| var actual = CommandHelper.GetSubscription(parseResult); | ||
|
|
||
| // Assert | ||
| Assert.Equal("Azure subscription 1", actual); | ||
| Assert.Equal(subscription ?? "Azure subscription 1", actual); | ||
| } | ||
|
|
||
| private static ParseResult GetParseResult(params string[] args) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -30,18 +30,8 @@ public static bool HasSubscriptionAvailable(CommandResult commandResult) | |||||||||||||
|
|
||||||||||||||
| public static string? GetSubscription(ParseResult parseResult) | ||||||||||||||
| { | ||||||||||||||
| // Get subscription from command line option or fallback to default subscription | ||||||||||||||
| var subscriptionValue = parseResult.GetValueOrDefault<string>(OptionDefinitions.Common.Subscription.Name); | ||||||||||||||
|
|
||||||||||||||
| if (!string.IsNullOrEmpty(subscriptionValue) && !IsPlaceholder(subscriptionValue)) | ||||||||||||||
| { | ||||||||||||||
| return subscriptionValue; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| var defaultSubscription = GetDefaultSubscription(); | ||||||||||||||
| return !string.IsNullOrEmpty(defaultSubscription) | ||||||||||||||
| ? defaultSubscription | ||||||||||||||
| : subscriptionValue; | ||||||||||||||
| return ResolveSubscription(subscriptionValue, GetDefaultSubscription()); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
|
|
@@ -50,16 +40,31 @@ public static bool HasSubscriptionAvailable(CommandResult commandResult) | |||||||||||||
| /// The CLI profile read is cached for the lifetime of the process to avoid redundant file I/O. | ||||||||||||||
| /// </summary> | ||||||||||||||
| public static string? GetDefaultSubscription() | ||||||||||||||
| => ResolveDefaultSubscription(GetProfileSubscription(), EnvironmentHelpers.GetAzureSubscriptionId()); | ||||||||||||||
|
|
||||||||||||||
| internal static string? GetProfileSubscription() => s_profileDefault.Value; | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Pure resolution logic: returns the first non-empty subscription source. | ||||||||||||||
| /// Priority: Azure CLI profile > AZURE_SUBSCRIPTION_ID environment variable. | ||||||||||||||
| /// </summary> | ||||||||||||||
| internal static string? ResolveDefaultSubscription(string? profileSubscription, string? envSubscription) | ||||||||||||||
| => !string.IsNullOrEmpty(profileSubscription) ? profileSubscription : envSubscription; | ||||||||||||||
|
||||||||||||||
| => !string.IsNullOrEmpty(profileSubscription) ? profileSubscription : envSubscription; | |
| => !string.IsNullOrEmpty(profileSubscription) | |
| ? profileSubscription | |
| : !string.IsNullOrEmpty(envSubscription) | |
| ? envSubscription | |
| : null; |
Copilot
AI
Apr 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ResolveSubscription’s XML doc says placeholder values are treated as absent, but the method currently returns the placeholder when defaultSubscription is null/empty (to preserve the old behavior). Either update the documentation to reflect this fallback, or change the behavior so placeholders are never returned.
Copilot
AI
Apr 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IsPlaceholder uses case-sensitive substring matching. This will miss placeholder text like "Azure Subscription 1" or "Default" depending on casing, which can cause unintended validation behavior. Use a StringComparison (e.g., OrdinalIgnoreCase) when checking for placeholder tokens.
| private static bool IsPlaceholder(string value) => value.Contains("subscription") || value.Contains("default"); | |
| private static bool IsPlaceholder(string value) => | |
| value.Contains("subscription", StringComparison.OrdinalIgnoreCase) || | |
| value.Contains("default", StringComparison.OrdinalIgnoreCase); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These test names still refer to “environment variable only”, but the expected/verified subscription is now the resolved default (Azure CLI profile can override the env var). Rename the tests to reflect that they validate default-subscription resolution rather than specifically env-var behavior.