-
Notifications
You must be signed in to change notification settings - Fork 358
Improve TestMode deserialization error message #1626
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
base: main
Are you sure you want to change the base?
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,66 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Text.Json; | ||
| using System.Text.Json.Serialization; | ||
| using Azure.Mcp.Tests.Helpers; | ||
| using Xunit; | ||
|
|
||
| namespace Azure.Mcp.Core.UnitTests.Helpers; | ||
|
|
||
| public class LiveTestSettingsTests | ||
| { | ||
| [Fact] | ||
| public void JsonDeserialization_WithInvalidTestMode_ThrowsJsonException() | ||
| { | ||
| // Arrange - Create JSON with an invalid TestMode value | ||
| var json = """{"TestMode": "InvalidMode", "TenantId": "test-tenant"}"""; | ||
|
|
||
| // Act & Assert - Verify JsonException is thrown | ||
| var exception = Assert.Throws<JsonException>(() => | ||
| JsonSerializer.Deserialize<LiveTestSettingsProxy>(json, new JsonSerializerOptions() | ||
| { | ||
| PropertyNameCaseInsensitive = true, | ||
| Converters = { new JsonStringEnumConverter() } | ||
| })); | ||
|
|
||
| // Verify the error message mentions TestMode | ||
| Assert.Contains("TestMode", exception.Message); | ||
| } | ||
|
|
||
| [Theory] | ||
| [InlineData("Live", TestMode.Live)] | ||
| [InlineData("Record", TestMode.Record)] | ||
| [InlineData("Playback", TestMode.Playback)] | ||
| [InlineData("live", TestMode.Live)] // Test case-insensitive | ||
| [InlineData("record", TestMode.Record)] | ||
| [InlineData("playback", TestMode.Playback)] | ||
| public void JsonDeserialization_WithValidTestMode_LoadsSuccessfully(string testModeValue, TestMode expectedMode) | ||
| { | ||
| // Arrange - Create JSON with valid TestMode value | ||
| var json = $$$"""{"TestMode": "{{{testModeValue}}}", "TenantId": "test-tenant", "SubscriptionId": "test-subscription"}"""; | ||
|
|
||
| // Act - Deserialize the JSON | ||
| var settings = JsonSerializer.Deserialize<LiveTestSettingsProxy>(json, new JsonSerializerOptions() | ||
| { | ||
| PropertyNameCaseInsensitive = true, | ||
| Converters = { new JsonStringEnumConverter() } | ||
| }); | ||
|
|
||
| // Assert - Verify the settings were loaded correctly | ||
| Assert.NotNull(settings); | ||
| Assert.Equal(expectedMode, settings.TestMode); | ||
| Assert.Equal("test-tenant", settings.TenantId); | ||
| Assert.Equal("test-subscription", settings.SubscriptionId); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Proxy class for testing LiveTestSettings JSON deserialization without file I/O | ||
| /// </summary> | ||
| private class LiveTestSettingsProxy | ||
| { | ||
| public TestMode TestMode { get; set; } = TestMode.Live; | ||
| public string TenantId { get; set; } = string.Empty; | ||
| public string SubscriptionId { get; set; } = string.Empty; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -53,16 +53,26 @@ public static bool TryLoadTestSettings([NotNullWhen(true)] out LiveTestSettings? | |||||||||||||
| { | ||||||||||||||
| var json = File.ReadAllText(path); | ||||||||||||||
|
|
||||||||||||||
| settings = JsonSerializer.Deserialize<LiveTestSettings>(json, new JsonSerializerOptions() | ||||||||||||||
| try | ||||||||||||||
| { | ||||||||||||||
| PropertyNameCaseInsensitive = true, | ||||||||||||||
| Converters = { new JsonStringEnumConverter() } | ||||||||||||||
| }); | ||||||||||||||
| settings = JsonSerializer.Deserialize<LiveTestSettings>(json, new JsonSerializerOptions() | ||||||||||||||
| { | ||||||||||||||
| PropertyNameCaseInsensitive = true, | ||||||||||||||
| Converters = { new JsonStringEnumConverter() } | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| if (settings != null) | ||||||||||||||
| if (settings != null) | ||||||||||||||
| { | ||||||||||||||
| settings.SettingsDirectory = Path.GetDirectoryName(path) ?? string.Empty; | ||||||||||||||
| return true; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| catch (JsonException ex) when (ex.Message.Contains("TestMode")) | ||||||||||||||
|
||||||||||||||
| catch (JsonException ex) when (ex.Message.Contains("TestMode")) | |
| catch (JsonException ex) when (ex.Path?.Contains(nameof(TestMode)) == true) |
Copilot
AI
Feb 3, 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.
Throwing an exception from a Try* method violates the standard Try-Parse pattern in .NET, where Try* methods should return false for errors rather than throwing exceptions. Existing callers of TryLoadTestSettings (e.g., ServerCommandTests.cs line 37) use it in conditional statements and don't expect exceptions. This breaking change could cause unexpected crashes. Consider either: (1) renaming the method to LoadTestSettings since it now throws exceptions, or (2) returning false and logging the detailed error message instead of throwing, to maintain the Try* pattern contract.
| throw new InvalidOperationException( | |
| $"Invalid TestMode value in {TestSettingsFileName}. Valid values are: {validValues}. " + | |
| $"Error details: {ex.Message}", ex); | |
| System.Console.Error.WriteLine( | |
| $"Invalid TestMode value in {TestSettingsFileName}. Valid values are: {validValues}. " + | |
| $"Error details: {ex.Message}"); |
Copilot
AI
Feb 3, 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.
The exception handling only catches and rethrows JsonException when the message contains "TestMode", but other JSON deserialization errors (e.g., invalid JSON syntax, type mismatches on other properties) will propagate as JsonException without the enhanced error handling. This could lead to inconsistent error messages. If you only want to enhance the error message for TestMode specifically, the current implementation is acceptable but document this limitation. Alternatively, consider whether other deserialization errors also deserve better error messages.
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.
The tests verify JSON deserialization behavior but don't actually test the TryLoadTestSettings method where the improved error message is thrown. The current tests use a LiveTestSettingsProxy class and test JsonSerializer.Deserialize directly, so they won't validate that the InvalidOperationException with the enhanced error message is actually thrown when loading an invalid .testsettings.json file. Consider adding an integration test that creates a temporary .testsettings.json file with an invalid TestMode value and verifies that TryLoadTestSettings throws the expected InvalidOperationException with the helpful error message listing valid values.