Skip to content

Commit 1a8ccb6

Browse files
authored
Report invalid global.json state in dotnet --info and hostfxr_resolve_sdk2 (#118418)
We currently ignore invalid global.json, which can lead to unexpected/undesired behaviour. While we're not going to change that behaviour right now, this change adds some indication about this situation in `dotnet --info` and updates a `hostfxr` API to indicate if an invalid global.json was found. - Make `sdk_resolver` track/store information about global.json even when it is deemed invalid - Update `dotnet --info` to list invalid global.json file path and error message - Add `hostfxr_resolve_sdk2_result_key_t::global_json_state` for `hostfxr_resolve_sdk2` API - string values of: `not_found`, `valid`, `invalid_json`, `invalid_data` - This can be used in the SDK to add telemetry for when we have invalid global.json Example part of `dotnet --info`: ``` global.json file: Invalid [C:\repos\helloworld\global.json] Version '9.0' is not valid for the 'sdk/version' value Invalid global.json is ignored for SDK resolution. ``` Before: ``` global.json file: Not found ```
1 parent a2ba998 commit 1a8ccb6

File tree

20 files changed

+384
-159
lines changed

20 files changed

+384
-159
lines changed

src/installer/tests/Assets/Projects/HostApiInvokerApp/HostFXR.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ internal enum hostfxr_resolve_sdk2_result_key_t : int
2323
resolved_sdk_dir = 0,
2424
global_json_path = 1,
2525
requested_version = 2,
26+
global_json_state = 3,
2627
}
2728

2829
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
@@ -159,7 +160,7 @@ static void Test_hostfxr_resolve_sdk2(string[] args)
159160
var data = new List<(hostfxr.hostfxr_resolve_sdk2_result_key_t, string)>();
160161
int rc = hostfxr.hostfxr_resolve_sdk2(
161162
exe_dir: args[0],
162-
working_dir: args[1],
163+
working_dir: args[1] == "<none>" ? string.Empty : args[1], // Empty string disables global.json look-up
163164
flags: Enum.Parse<hostfxr.hostfxr_resolve_sdk2_flags_t>(args[2]),
164165
result: (key, value) => data.Add((key, value)));
165166

src/installer/tests/HostActivation.Tests/DependencyResolution/ResolveComponentDependencies.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ public void ComponentWithCorruptedDepsJsonShouldFail()
365365
.Should().Fail()
366366
.And.HaveStdOutContaining($"corehost_resolve_component_dependencies:Fail[0x{Constants.ErrorCode.ResolverInitFailure.ToString("x")}]")
367367
.And.HaveStdOutContaining("corehost reported errors:")
368-
.And.HaveStdOutContaining($"A JSON parsing exception occurred in [{component.DepsJson}], offset 0 (line 1, column 1): Invalid value.")
368+
.And.HaveStdOutContaining($"Failed to parse file [{component.DepsJson}]. JSON parsing exception: Invalid value. [offset 0: line 1, column 1]")
369369
.And.HaveStdOutContaining($"Error initializing the dependency resolver: An error occurred while parsing: {component.DepsJson}");
370370
}
371371

@@ -426,7 +426,7 @@ public void MultiThreadedComponentDependencyResolutionWithFailures()
426426
.Should().Fail()
427427
.And.HaveStdOutContaining($"ComponentA: corehost_resolve_component_dependencies:Fail[0x{Constants.ErrorCode.ResolverInitFailure.ToString("x")}]")
428428
.And.HaveStdOutContaining($"ComponentA: corehost reported errors:")
429-
.And.HaveStdOutContaining($"ComponentA: A JSON parsing exception occurred in [{componentWithNoDependencies.DepsJson}], offset 0 (line 1, column 1): Invalid value.")
429+
.And.HaveStdOutContaining($"ComponentA: Failed to parse file [{componentWithNoDependencies.DepsJson}]. JSON parsing exception: Invalid value. [offset 0: line 1, column 1]")
430430
.And.HaveStdOutContaining($"ComponentA: Error initializing the dependency resolver: An error occurred while parsing: {componentWithNoDependencies.DepsJson}")
431431
.And.HaveStdOutContaining($"ComponentB: corehost_resolve_component_dependencies:Fail[0x{Constants.ErrorCode.LibHostInvalidArgs.ToString("x")}]")
432432
.And.HaveStdOutContaining($"ComponentB: corehost reported errors:")

src/installer/tests/HostActivation.Tests/HostCommands.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.DotNet.Cli.Build;
99
using Microsoft.DotNet.CoreSetup.Test;
1010
using Microsoft.DotNet.CoreSetup.Test.HostActivation;
11+
using Microsoft.DotNet.TestUtils;
1112
using Xunit;
1213

1314
namespace HostActivation.Tests
@@ -168,6 +169,65 @@ public void Info_ListEnvironment_LegacyPrefixDetection()
168169
.And.HaveStdOutContaining("Detected COMPlus_* environment variable(s). Consider transitioning to DOTNET_* equivalent.");
169170
}
170171

172+
[Fact]
173+
public void Info_GlobalJson_InvalidJson()
174+
{
175+
using (TestArtifact workingDir = TestArtifact.Create(nameof(Info_GlobalJson_InvalidJson)))
176+
{
177+
string globalJsonPath = GlobalJson.Write(workingDir.Location, "{ \"sdk\": { }");
178+
TestContext.BuiltDotNet.Exec("--info")
179+
.WorkingDirectory(workingDir.Location)
180+
.CaptureStdOut().CaptureStdErr()
181+
.Execute()
182+
.Should().Pass()
183+
.And.HaveStdOutContaining($"Invalid [{globalJsonPath}]")
184+
.And.HaveStdOutContaining("JSON parsing exception:")
185+
.And.NotHaveStdErr();
186+
}
187+
}
188+
189+
[Theory]
190+
[InlineData("9")]
191+
[InlineData("9.0")]
192+
[InlineData("9.0.x")]
193+
[InlineData("invalid")]
194+
public void Info_GlobalJson_InvalidData(string version)
195+
{
196+
using (TestArtifact workingDir = TestArtifact.Create(nameof(Info_GlobalJson_InvalidData)))
197+
{
198+
string globalJsonPath = GlobalJson.CreateWithVersion(workingDir.Location, version);
199+
TestContext.BuiltDotNet.Exec("--info")
200+
.WorkingDirectory(workingDir.Location)
201+
.CaptureStdOut().CaptureStdErr()
202+
.Execute()
203+
.Should().Pass()
204+
.And.HaveStdOutContaining($"Invalid [{globalJsonPath}]")
205+
.And.HaveStdOutContaining($"Version '{version}' is not valid for the 'sdk/version' value")
206+
.And.HaveStdOutContaining($"Invalid global.json is ignored for SDK resolution")
207+
.And.NotHaveStdErr();
208+
}
209+
}
210+
211+
[Theory]
212+
[InlineData("9.0.0")]
213+
[InlineData("9.1.99")]
214+
public void Info_GlobalJson_NonExistentFeatureBand(string version)
215+
{
216+
using (TestArtifact workingDir = TestArtifact.Create(nameof(Info_GlobalJson_NonExistentFeatureBand)))
217+
{
218+
string globalJsonPath = GlobalJson.CreateWithVersion(workingDir.Location, version);
219+
var result = TestContext.BuiltDotNet.Exec("--info")
220+
.WorkingDirectory(workingDir.Location)
221+
.CaptureStdOut().CaptureStdErr()
222+
.Execute()
223+
.Should().Pass()
224+
.And.HaveStdOutContaining($"Invalid [{globalJsonPath}]")
225+
.And.HaveStdOutContaining($"Version '{version}' is not valid for the 'sdk/version' value. SDK feature bands start at 1 - for example, {Version.Parse(version).ToString(2)}.100")
226+
.And.NotHaveStdOutContaining($"Invalid global.json is ignored for SDK resolution")
227+
.And.NotHaveStdErr();
228+
}
229+
}
230+
171231
[Fact]
172232
public void ListRuntimes()
173233
{

0 commit comments

Comments
 (0)