-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[System.Runtime.Loader] Add hot reload test infrastructure #51144
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
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
a29f09c
[System.Runtime.Loader] Add hot reload test infrastructure
lambdageek 11c9512
Make a proper task for computing hotreload-delta-gen output files
lambdageek 690b98b
Don't need DeltaCount property, compute from json
lambdageek 717afef
Add dependency on hotreload-delta-gen tool
lambdageek e15aa8d
use 'dotnet tool run hotreload-delta-gen' to generate EnC deltas
lambdageek 1159924
Use remote executor if DOTNET_MODIFIABLE_ASSEMBLIES is not set
lambdageek cf3e448
Use DotNetTool property to run hotreload-delta-gen
lambdageek 7812159
Don't run on Mono for now
lambdageek 0f29dd0
bump hotreload-delta-gen package version
lambdageek ab5e519
Install the CLI tools in CI
lambdageek 15f757b
Run tests on Mono if feature enabled and interp is used
lambdageek 2d9549a
fix remote executor detection
lambdageek 5942faf
remove unneeded DefineConstants
lambdageek c82877a
Use `$(TargetPath)` as input to ComputeDeltaOutputNames
lambdageek 5a98a17
drop "BuildingProject" property check
lambdageek ecb9362
Use Microsoft.DotNet.HotReload.Utils.Generator.BuildTool instead of h…
lambdageek 321000c
Use well known version for Generator BuiltTool version
lambdageek e816211
Revert "Install the CLI tools in CI"
lambdageek 2992e23
Use published Generator.BuildTool package
lambdageek 003b3dc
fix typos, indentantion; add copyright headers
lambdageek b5b2b81
Remove ComputeDeltaFileOutputNames use nuget version
lambdageek b3347f2
Fix style nits; add more copyright headers
lambdageek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| <Project> | ||
| <Import Project="..\..\Directory.Build.props" /> | ||
|
|
||
| <ItemGroup> | ||
| <!-- This package from https://github.com/dotnet/hotreload-utils provides | ||
| targets that read the json delta script and generates deltas based on the baseline assembly and the modified sources. | ||
|
|
||
| Projects must define the DeltaScript property that specifies the (relative) path to the json script. | ||
| Deltas will be emitted next to the output assembly. Deltas will be copied when the current | ||
| project is referenced from other other projects. | ||
| --> | ||
| <PackageReference Include="Microsoft.DotNet.HotReload.Utils.Generator.BuildTool" Version="$(MicrosoftDotNetHotReloadUtilsGeneratorBuildToolVersion)" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
3 changes: 3 additions & 0 deletions
3
src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.targets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| <Project> | ||
| <Import Project="..\..\..\Directory.Build.targets" /> | ||
| </Project> |
11 changes: 11 additions & 0 deletions
11
.../tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| namespace System.Reflection.Metadata.ApplyUpdate.Test | ||
| { | ||
| public class MethodBody1 { | ||
| public static string StaticMethod1 () { | ||
| return "OLD STRING"; | ||
| } | ||
| } | ||
| } | ||
11 changes: 11 additions & 0 deletions
11
...sts/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v1.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
lambdageek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| namespace System.Reflection.Metadata.ApplyUpdate.Test | ||
| { | ||
| public class MethodBody1 { | ||
| public static string StaticMethod1 () { | ||
| return "NEW STRING"; | ||
| } | ||
| } | ||
| } | ||
11 changes: 11 additions & 0 deletions
11
...sts/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v2.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
lambdageek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| namespace System.Reflection.Metadata.ApplyUpdate.Test | ||
| { | ||
| public class MethodBody1 { | ||
| public static string StaticMethod1 () { | ||
| return "NEWEST STRING"; | ||
| } | ||
| } | ||
| } | ||
11 changes: 11 additions & 0 deletions
11
...plyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <RootNamespace>System.Runtime.Loader.Tests</RootNamespace> | ||
| <TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks> | ||
| <TestRuntime>true</TestRuntime> | ||
| <DeltaScript>deltascript.json</DeltaScript> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <Compile Include="MethodBody1.cs" /> | ||
| </ItemGroup> | ||
| </Project> |
7 changes: 7 additions & 0 deletions
7
...ests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/deltascript.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "changes": [ | ||
| {"document": "MethodBody1.cs", "update": "MethodBody1_v1.cs"}, | ||
| {"document": "MethodBody1.cs", "update": "MethodBody1_v2.cs"}, | ||
| ] | ||
| } | ||
|
|
42 changes: 42 additions & 0 deletions
42
src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using Xunit; | ||
|
|
||
| namespace System.Reflection.Metadata | ||
| { | ||
| /// | ||
| /// The general setup for ApplyUpdate tests is: | ||
| /// | ||
| /// Each test Foo has a corresponding assembly under | ||
| /// System.Reflection.Metadata.ApplyUpate.Test.Foo The Foo.csproj has a delta | ||
| /// script that applies one or more updates to Foo.dll The ApplyUpdateTest | ||
| /// testsuite runs each test in sequence, loading the corresponding | ||
| /// assembly, applying an update to it and observing the results. | ||
| [Collection(nameof(ApplyUpdateUtil.NoParallelTests))] | ||
| [ConditionalClass(typeof(ApplyUpdateUtil), nameof (ApplyUpdateUtil.IsSupported))] | ||
| public class ApplyUpdateTest | ||
| { | ||
| [Fact] | ||
| void StaticMethodBodyUpdate() | ||
| { | ||
| ApplyUpdateUtil.TestCase(static () => | ||
| { | ||
| var assm = typeof (ApplyUpdate.Test.MethodBody1).Assembly; | ||
|
|
||
| var r = ApplyUpdate.Test.MethodBody1.StaticMethod1(); | ||
| Assert.Equal("OLD STRING", r); | ||
|
|
||
| ApplyUpdateUtil.ApplyUpdate(assm); | ||
|
|
||
| r = ApplyUpdate.Test.MethodBody1.StaticMethod1(); | ||
| Assert.Equal("NEW STRING", r); | ||
|
|
||
| ApplyUpdateUtil.ApplyUpdate(assm); | ||
|
|
||
| r = ApplyUpdate.Test.MethodBody1.StaticMethod1 (); | ||
| Assert.Equal ("NEWEST STRING", r); | ||
| }); | ||
| } | ||
| } | ||
| } |
148 changes: 148 additions & 0 deletions
148
src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Runtime.CompilerServices; | ||
| using System.Runtime.InteropServices; | ||
| using Xunit; | ||
| using Microsoft.DotNet.RemoteExecutor; | ||
|
|
||
| namespace System.Reflection.Metadata | ||
| { | ||
| public class ApplyUpdateUtil { | ||
| internal const string DotNetModifiableAssembliesSwitch = "DOTNET_MODIFIABLE_ASSEMBLIES"; | ||
| internal const string DotNetModifiableAssembliesValue = "debug"; | ||
|
|
||
lambdageek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| [CollectionDefinition("NoParallelTests", DisableParallelization = true)] | ||
| public class NoParallelTests { } | ||
|
|
||
| /// Whether ApplyUpdate is supported by the environment, test configuration, and runtime. | ||
| /// | ||
| /// We need: | ||
| /// 1. Either DOTNET_MODIFIABLE_ASSEMBLIES=debug is set, or we can use the RemoteExecutor to run a child process with that environment; and, | ||
| /// 2. Either Mono in a supported configuration (interpreter as the execution engine, and the hot reload feature enabled), or CoreCLR; and, | ||
| /// 3. The test assemblies are compiled in the Debug configuration. | ||
| public static bool IsSupported => (IsModifiableAssembliesSet || IsRemoteExecutorSupported) && | ||
| (!IsMonoRuntime || IsSupportedMonoConfiguration) && | ||
| IsSupportedTestConfiguration(); | ||
|
|
||
| public static bool IsModifiableAssembliesSet => | ||
| String.Equals(DotNetModifiableAssembliesValue, Environment.GetEnvironmentVariable(DotNetModifiableAssembliesSwitch), StringComparison.InvariantCultureIgnoreCase); | ||
|
|
||
| // static cctor for RemoteExecutor throws on wasm. | ||
| public static bool IsRemoteExecutorSupported => !RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")) && RemoteExecutor.IsSupported; | ||
|
|
||
| // copied from https://github.com/dotnet/arcade/blob/6cc4c1e9e23d5e65e88a8a57216b3d91e9b3d8db/src/Microsoft.DotNet.XUnitExtensions/src/DiscovererHelpers.cs#L16-L17 | ||
| private static readonly Lazy<bool> s_isMonoRuntime = new Lazy<bool>(() => Type.GetType("Mono.RuntimeStructs") != null); | ||
| public static bool IsMonoRuntime => s_isMonoRuntime.Value; | ||
|
|
||
| private static readonly Lazy<bool> s_isSupportedMonoConfiguration = new Lazy<bool>(CheckSupportedMonoConfiguration); | ||
|
|
||
| public static bool IsSupportedMonoConfiguration => s_isSupportedMonoConfiguration.Value; | ||
|
|
||
| // Not every build of Mono supports ApplyUpdate | ||
| internal static bool CheckSupportedMonoConfiguration() | ||
| { | ||
| // check that interpreter is enabled, and the build has hot reload capabilities enabled. | ||
| var isInterp = RuntimeFeature.IsDynamicCodeSupported && !RuntimeFeature.IsDynamicCodeCompiled; | ||
| return isInterp && HasApplyUpdateCapabilities(); | ||
| } | ||
|
|
||
| internal static bool HasApplyUpdateCapabilities() | ||
| { | ||
| var ty = typeof(AssemblyExtensions); | ||
| var mi = ty.GetMethod("GetApplyUpdateCapabilities", BindingFlags.NonPublic | BindingFlags.Static, Array.Empty<Type>()); | ||
|
|
||
| if (mi == null) | ||
| return false; | ||
|
|
||
| var caps = mi.Invoke(null, null); | ||
|
|
||
| // any non-empty string, assumed to be at least "baseline" | ||
| return caps is string {Length: > 0}; | ||
| } | ||
|
|
||
| // Only Debug assemblies are editable | ||
| internal static bool IsSupportedTestConfiguration() | ||
| { | ||
| #if DEBUG | ||
| return true; | ||
| #else | ||
| return false; | ||
| #endif | ||
| } | ||
|
|
||
| private static System.Collections.Generic.Dictionary<Assembly, int> assembly_count = new(); | ||
|
|
||
| internal static void ApplyUpdate (System.Reflection.Assembly assm) | ||
| { | ||
| int count; | ||
| if (!assembly_count.TryGetValue(assm, out count)) | ||
| count = 1; | ||
| else | ||
| count++; | ||
| assembly_count [assm] = count; | ||
|
|
||
| /* FIXME WASM: Location is empty on wasm. Make up a name based on Name */ | ||
| string basename = assm.Location; | ||
| if (basename == "") | ||
| basename = assm.GetName().Name + ".dll"; | ||
| Console.Error.WriteLine($"Apply Delta Update for {basename}, revision {count}"); | ||
|
|
||
| string dmeta_name = $"{basename}.{count}.dmeta"; | ||
| string dil_name = $"{basename}.{count}.dil"; | ||
| byte[] dmeta_data = System.IO.File.ReadAllBytes(dmeta_name); | ||
| byte[] dil_data = System.IO.File.ReadAllBytes(dil_name); | ||
| byte[] dpdb_data = null; // TODO also use the dpdb data | ||
|
|
||
| AssemblyExtensions.ApplyUpdate(assm, dmeta_data, dil_data, dpdb_data); | ||
| } | ||
|
|
||
| internal static bool UseRemoteExecutor => !IsModifiableAssembliesSet; | ||
|
|
||
| internal static void AddRemoteInvokeOptions (ref RemoteInvokeOptions options) | ||
| { | ||
| options = options ?? new RemoteInvokeOptions(); | ||
| options.StartInfo.EnvironmentVariables.Add(DotNetModifiableAssembliesSwitch, DotNetModifiableAssembliesValue); | ||
| } | ||
|
|
||
| /// Run the given test case, which applies updates to the given assembly. | ||
| /// | ||
| /// Note that the testBody should be a static delegate or a static | ||
| /// lambda - it must not use state from the enclosing method. | ||
| public static void TestCase(Action testBody, | ||
| RemoteInvokeOptions options = null) | ||
| { | ||
| if (UseRemoteExecutor) | ||
| { | ||
| Console.Error.WriteLine ($"Running test using RemoteExecutor"); | ||
| AddRemoteInvokeOptions(ref options); | ||
| RemoteExecutor.Invoke(testBody, options).Dispose(); | ||
| } | ||
| else | ||
| { | ||
| Console.Error.WriteLine($"Running test using direct invoke"); | ||
| testBody(); | ||
| } | ||
| } | ||
|
|
||
| /// Run the given test case, which applies updates to the given | ||
| /// assembly, and has 1 additional argument. | ||
| /// | ||
| /// Note that the testBody should be a static delegate or a static | ||
| /// lambda - it must not use state from the enclosing method. | ||
| public static void TestCase(Action<string> testBody, | ||
| string arg1, | ||
| RemoteInvokeOptions options = null) | ||
| { | ||
| if (UseRemoteExecutor) | ||
| { | ||
| AddRemoteInvokeOptions(ref options); | ||
| RemoteExecutor.Invoke(testBody, arg1, options).Dispose(); | ||
| } | ||
| else | ||
| { | ||
| testBody(arg1); | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.