-
Notifications
You must be signed in to change notification settings - Fork 466
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
Fix broken tests when running Config Schema Generator on .NET 9 #6312
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 |
---|---|---|
|
@@ -61,7 +61,7 @@ private void GenerateLogCategories(JsonObject parent) | |
{ | ||
var categoryNode = new JsonObject(); | ||
categoryNode["$ref"] = "#/definitions/logLevelThreshold"; | ||
propertiesNode[categories[i]] = categoryNode; | ||
ReplaceNodeWithKeyCasingChange(propertiesNode, categories[i], categoryNode); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that this is code copied from the config binder generator, is it appropriate to be making changes locally? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part of the code isn't copied from the config binder generator. The part that is copied is inside the https://github.com/dotnet/aspire/tree/main/src/Tools/ConfigurationSchemaGenerator/RuntimeSource directory. |
||
} | ||
|
||
parent["definitions"] = new JsonObject | ||
|
@@ -138,7 +138,7 @@ private bool GeneratePathSegment(JsonObject currentNode, TypeSpec type, Queue<st | |
else | ||
{ | ||
pathSegmentNode = new JsonObject(); | ||
propertiesNode[pathSegment] = pathSegmentNode; | ||
ReplaceNodeWithKeyCasingChange(propertiesNode, pathSegment, pathSegmentNode); | ||
ownsPathSegment = true; | ||
} | ||
} | ||
|
@@ -148,9 +148,7 @@ private bool GeneratePathSegment(JsonObject currentNode, TypeSpec type, Queue<st | |
|
||
if (backupCasingOfPathSegmentName != pathSegment) | ||
{ | ||
// Re-add existing node, so the new casing of pathSegment is used. | ||
propertiesNode.Remove(pathSegment); | ||
propertiesNode[pathSegment] = pathSegmentNode; | ||
ReplaceNodeWithKeyCasingChange(propertiesNode, pathSegment, pathSegmentNode); | ||
} | ||
else | ||
{ | ||
|
@@ -173,10 +171,8 @@ private bool GeneratePathSegment(JsonObject currentNode, TypeSpec type, Queue<st | |
} | ||
else if (backupCasingOfPathSegmentName != null) | ||
{ | ||
// Revert casing change of pathSegment. | ||
var existingValue = propertiesNode[pathSegment]; | ||
propertiesNode.Remove(pathSegment); | ||
propertiesNode[backupCasingOfPathSegmentName] = existingValue; | ||
ReplaceNodeWithKeyCasingChange(propertiesNode, backupCasingOfPathSegmentName, existingValue); | ||
} | ||
} | ||
|
||
|
@@ -288,7 +284,7 @@ private bool GenerateProperty(JsonObject currentNode, PropertySpec property, IPr | |
var backupPropertyNode = currentNode[property.ConfigurationKeyName]; | ||
|
||
var propertyNode = new JsonObject(); | ||
currentNode[property.ConfigurationKeyName] = propertyNode; | ||
ReplaceNodeWithKeyCasingChange(currentNode, property.ConfigurationKeyName, propertyNode); | ||
|
||
var hasGenerated = GenerateType(propertyNode, propertyType); | ||
if (hasGenerated) | ||
|
@@ -343,7 +339,7 @@ private static void RestoreBackup(JsonNode? backupNode, string name, JsonObject | |
} | ||
else | ||
{ | ||
parentNode[name] = backupNode; | ||
ReplaceNodeWithKeyCasingChange(parentNode, name, backupNode); | ||
} | ||
} | ||
|
||
|
@@ -719,6 +715,32 @@ private static string[] CreateExclusionPaths(List<string>? exclusionPaths) | |
return result; | ||
} | ||
|
||
private static void ReplaceNodeWithKeyCasingChange(JsonObject jsonObject, string key, JsonNode value) | ||
{ | ||
#if NET9_0_OR_GREATER | ||
Comment on lines
+718
to
+720
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eiriktsarpalis - is this the recommended way to respond to the breaking change? Do we have documentation guidance on the break? I almost wonder if we should be checking the System.Text.Json major version number instead. Or doing some sort of "runtime capability test" - for example, execute a method that checks for the new behavior and set a The situation that can break this is if you are targeting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I fully understand what tests were broken by the particular change in STJ 9, but per the discussion in dotnet/runtime#108790 (comment) the pre-9 behaviour is undocumented, accidental behaviour that is inconsistent with how all other dictionary types work in the same context. We've agreed to add a breaking change note in our documentation for completeness, but beyond that I don't think it's appropriate to introduce mitigations down the stack just so that the pre-9 behavior is preserved. Assuming there are failing tests that check against that behavior, then I would recommend just updating the tests. |
||
// In .NET 9, the key casing is never adapted. See https://github.com/dotnet/runtime/issues/108790. | ||
var index = jsonObject.IndexOf(key); | ||
if (index != -1) | ||
{ | ||
jsonObject.RemoveAt(index); | ||
jsonObject.Insert(index, key, value); | ||
} | ||
else | ||
{ | ||
jsonObject[key] = value; | ||
} | ||
#else | ||
// In .NET 8, the key casing is adapted, except when the value doesn't change. | ||
if (ReferenceEquals(jsonObject[key], value)) | ||
{ | ||
// There's no API to preserve property order. | ||
jsonObject.Remove(key); | ||
} | ||
|
||
jsonObject[key] = value; | ||
#endif | ||
} | ||
|
||
private sealed class SchemaOrderJsonNodeConverter : JsonConverter<JsonNode> | ||
{ | ||
public static SchemaOrderJsonNodeConverter Instance { get; } = new SchemaOrderJsonNodeConverter(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>$(DefaultTargetFramework)</TargetFramework> | ||
<TargetFrameworks>$(AllTargetFrameworks)</TargetFrameworks> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't need to multi-target the generator. It should only need to target |
||
<OutputType>Exe</OutputType> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>annotations</Nullable> | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,7 @@ | ||||||||||
<Project Sdk="Microsoft.NET.Sdk"> | ||||||||||
|
||||||||||
<PropertyGroup> | ||||||||||
<TargetFramework>$(DefaultTargetFramework)</TargetFramework> | ||||||||||
<TargetFrameworks>$(AllTargetFrameworks)</TargetFrameworks> | ||||||||||
<PreserveCompilationContext>true</PreserveCompilationContext> | ||||||||||
<CopyDocumentationFilesFromPackages>true</CopyDocumentationFilesFromPackages> | ||||||||||
</PropertyGroup> | ||||||||||
|
@@ -18,10 +18,19 @@ | |||||||||
|
||||||||||
<ItemGroup> | ||||||||||
<PackageReference Include="Microsoft.DotNet.XUnitExtensions" /> | ||||||||||
<PackageReference Include="Microsoft.Extensions.Hosting" /> | ||||||||||
<PackageReference Include="Newtonsoft.Json" /> | ||||||||||
</ItemGroup> | ||||||||||
|
||||||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net9.0'"> | ||||||||||
<PackageReference Include="Microsoft.Extensions.Hosting" /> | ||||||||||
</ItemGroup> | ||||||||||
|
||||||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'"> | ||||||||||
<PackageReference Include="Microsoft.Extensions.Hosting" VersionOverride="9.0.0-rc.2.24473.5" /> | ||||||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" VersionOverride="9.0.0-rc.2.24473.5" /> | ||||||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" VersionOverride="9.0.0-rc.2.24473.5" /> | ||||||||||
</ItemGroup> | ||||||||||
Comment on lines
+28
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if there's a better way. I've tried updating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be fixed now. You should be able to revert these changes because of the following: Lines 76 to 79 in 2e60ee6
This will automatically reference the 9.0 hosting packages when targeting |
||||||||||
|
||||||||||
<ItemGroup> | ||||||||||
<ProjectReference Include="..\..\src\Tools\ConfigurationSchemaGenerator\ConfigurationSchemaGenerator.csproj" /> | ||||||||||
</ItemGroup> | ||||||||||
|
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.
I'm not sure this is right. (actually I'm pretty sure it is wrong). Can you explain why you are proposing this change? What doesn't work about the current code?