From 14b1e85bd62e6d2c083263ee3c3205184f37b977 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 1 Aug 2024 22:43:43 -0400 Subject: [PATCH 01/13] fix: Don't fail metadata updates on missing assemblies --- .../DotNetDeltaApplier/HotReloadAgent.cs | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs b/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs index 62182db3b0bd..f11b430386d9 100644 --- a/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs +++ b/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs @@ -82,24 +82,36 @@ private UpdateHandlerActions GetMetadataUpdateHandlerActions() var handlerActions = new UpdateHandlerActions(); foreach (var assembly in sortedAssemblies) { - foreach (var attr in assembly.GetCustomAttributesData()) + try { - // Look up the attribute by name rather than by type. This would allow netstandard targeting libraries to - // define their own copy without having to cross-compile. - if (attr.AttributeType.FullName != "System.Reflection.Metadata.MetadataUpdateHandlerAttribute") + foreach (var attr in assembly.GetCustomAttributesData()) { - continue; + // Look up the attribute by name rather than by type. This would allow netstandard targeting libraries to + // define their own copy without having to cross-compile. + if (attr.AttributeType.FullName != "System.Reflection.Metadata.MetadataUpdateHandlerAttribute") + { + continue; + } + + IList ctorArgs = attr.ConstructorArguments; + if (ctorArgs.Count != 1 || + ctorArgs[0].Value is not Type handlerType) + { + _log($"'{attr}' found with invalid arguments."); + continue; + } + + GetHandlerActions(handlerActions, handlerType); } - - IList ctorArgs = attr.ConstructorArguments; - if (ctorArgs.Count != 1 || - ctorArgs[0].Value is not Type handlerType) - { - _log($"'{attr}' found with invalid arguments."); - continue; - } - - GetHandlerActions(handlerActions, handlerType); + } + catch (Exception e) + { + // In cross-platform scenarios, such as debugging in VS through WSL, Roslyn + // runs on Windows, and the agent runs on Linux. Assemblies accessible to Windows + // may not be available or loaded on linux (such as WPF's assemblies). + // In such case, we can ignore the assemblies and continue enumerating handlers for + // the rest of the assemblies of current domain. + _log($"'{assembly.FullName}' is not loaded ({e.Message})"); } } From 1e42eaf4cc8f102f953f6b0291ce5033d9159d0b Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 1 Aug 2024 22:45:10 -0400 Subject: [PATCH 02/13] tests: Add tests for assembly load failure --- .../App/App.csproj | 13 +++++++ .../App/Program.cs | 33 ++++++++++++++++ .../App/Update.cs | 13 +++++++ .../WatchAppMissingAssemblyFailure/Dep/Dep.cs | 7 ++++ .../Dep/Dep.csproj | 8 ++++ .../HotReload/ApplyDeltaTests.cs | 39 ++++++++++++++++++- 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/App.csproj create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/App.csproj b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/App.csproj new file mode 100644 index 000000000000..4505e48191a6 --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/App.csproj @@ -0,0 +1,13 @@ + + + + Exe + $(CurrentTargetFramework) + enable + + + + + + + diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs new file mode 100644 index 000000000000..be686c646820 --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs @@ -0,0 +1,33 @@ +using System.Diagnostics; +using System.Reflection.Metadata; + +[assembly: MetadataUpdateHandler(typeof(UpdateHandler))] + +// delete the dependency dll to cause load failure of DepSubType +var depPath = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location!)!, "Dep.dll"); +File.Delete(depPath); +Console.WriteLine($"File deleted: {depPath}"); + +while (true) +{ + lock (UpdateHandler.Guard) + { + Printer.Print(); + } + + Thread.Sleep(100); +} + +static class UpdateHandler +{ + // Lock to avoid the updated Print method executing concurrently with the update handler. + public static object Guard = new object(); + + public static void UpdateApplication(Type[] types) + { + lock (Guard) + { + Console.WriteLine($"Updated types: {(types == null ? "" : types.Length == 0 ? "" : string.Join(",", types.Select(t => t.Name)))}"); + } + } +} diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs new file mode 100644 index 000000000000..5df8d231b148 --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs @@ -0,0 +1,13 @@ +using System; + +class DepSubType : Dep +{ + int F() => 1; +} + +class Printer +{ + public static void Print() + => Console.WriteLine("Hello!"); +} + diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs new file mode 100644 index 000000000000..b2db74fcbb3c --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs @@ -0,0 +1,7 @@ +public class Dep +{ + void F() + { + Console.WriteLine(1); + } +} diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj new file mode 100644 index 000000000000..78589723776a --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj @@ -0,0 +1,8 @@ + + + + $(CurrentTargetFramework) + enable + + + diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index 8d0a41b9024f..1e97b8ed8427 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -78,7 +78,7 @@ public async Task HandleTypeLoadFailure() await App.AssertWaitingForChanges(); - var newSrc = """ + var newSrc = /* lang=c#-test */""" class DepSubType : Dep { int F() => 2; @@ -120,5 +120,42 @@ public async Task BlazorWasm() //UpdateSourceFile(Path.Combine(testAsset.Path, "Pages", "Index.razor"), newSource); //await App.AssertOutputLineStartsWith(MessageDescriptor.HotReloadSucceeded); } + + // Test is timing out on .NET Framework: https://github.com/dotnet/sdk/issues/41669 + [CoreMSBuildOnlyFact] + public async Task HandleMissingAssemblyFailure() + { + var testAsset = TestAssets.CopyTestAsset("WatchAppMissingAssemblyFailure") + .WithSource(); + + await App.StartWatcherAsync(testAsset, "App"); + + await App.WaitForSessionStarted(); + + var newSrc = /* lang=c#-test */""" + class DepSubType : Dep + { + int F() => 2; + } + + class Printer + { + public static void Print() + { + Console.WriteLine("Changed!"); + } + } + """; + + // Delete all files in testAsset.Path named Dep.dll + foreach (var depDll in Directory.GetFiles(testAsset.Path, "Dep.dll", SearchOption.AllDirectories)) + { + File.Delete(depDll); + } + + File.WriteAllText(Path.Combine(testAsset.Path, "App", "Update.cs"), newSrc); + + await App.AssertOutputLineStartsWith("Updated types: Printer"); + } } } From 1639483936b4616939b245aadad15c7be65504f0 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Fri, 2 Aug 2024 10:57:50 -0400 Subject: [PATCH 03/13] test: Add handler validation --- .../App/Program.cs | 1 + .../App/Update.cs | 2 +- .../WatchAppMissingAssemblyFailure/Dep/Dep.cs | 18 +++++++++++++++++- .../HotReload/ApplyDeltaTests.cs | 14 ++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs index be686c646820..627d78708d6e 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs @@ -2,6 +2,7 @@ using System.Reflection.Metadata; [assembly: MetadataUpdateHandler(typeof(UpdateHandler))] +[assembly: MetadataUpdateHandler(typeof(Dep.UpdateHandler))] // delete the dependency dll to cause load failure of DepSubType var depPath = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location!)!, "Dep.dll"); diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs index 5df8d231b148..a589b9f27b7a 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs @@ -1,6 +1,6 @@ using System; -class DepSubType : Dep +class DepSubType : Dep.DepType { int F() => 1; } diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs index b2db74fcbb3c..7419d12485af 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs @@ -1,7 +1,23 @@ -public class Dep +namespace Dep; + +public class DepType { void F() { Console.WriteLine(1); } } + +static class UpdateHandler +{ + // Lock to avoid the updated Print method executing concurrently with the update handler. + public static object Guard = new object(); + + public static void UpdateApplication(Type[] types) + { + lock (Guard) + { + Console.WriteLine($"Dep Updated types: {(types == null ? "" : types.Length == 0 ? "" : string.Join(",", types.Select(t => t.Name)))}"); + } + } +} diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index 1e97b8ed8427..5911cb605de6 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -145,6 +145,20 @@ public static void Print() Console.WriteLine("Changed!"); } } + + static class UpdateHandler + { + // Lock to avoid the updated Print method executing concurrently with the update handler. + public static object Guard = new object(); + + public static void UpdateApplication(Type[] types) + { + lock (Guard) + { + Console.WriteLine($"Dep Updated types: {(types == null ? "" : types.Length == 0 ? "" : string.Join(",", types.Select(t => t.Name)))}"); + } + } + } """; // Delete all files in testAsset.Path named Dep.dll From d01aeede4374c348f301fee08c9551c7c410b43b Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Fri, 2 Aug 2024 11:47:12 -0400 Subject: [PATCH 04/13] choe: Make update handler public --- .../TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs | 2 +- test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs index 7419d12485af..527201d3ef32 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs @@ -8,7 +8,7 @@ void F() } } -static class UpdateHandler +public static class UpdateHandler { // Lock to avoid the updated Print method executing concurrently with the update handler. public static object Guard = new object(); diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index 5911cb605de6..e3d91d25523c 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -146,7 +146,7 @@ public static void Print() } } - static class UpdateHandler + public static class UpdateHandler { // Lock to avoid the updated Print method executing concurrently with the update handler. public static object Guard = new object(); From 4f11fd808ee2b5bf50153526b1d0f5cbdecf0a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Laban?= Date: Fri, 2 Aug 2024 15:18:40 -0400 Subject: [PATCH 05/13] chore: adjust update content --- test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index e3d91d25523c..c44b34db7710 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -133,7 +133,7 @@ public async Task HandleMissingAssemblyFailure() await App.WaitForSessionStarted(); var newSrc = /* lang=c#-test */""" - class DepSubType : Dep + class DepSubType : Dep.DepType { int F() => 2; } From 31458e9a858e7d8f421baea2bc2584d6ed290dd2 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Tue, 27 Aug 2024 13:45:50 -0400 Subject: [PATCH 06/13] chore: Adjust for newer APIs --- test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index c44b34db7710..dd753b1caca3 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -78,7 +78,7 @@ public async Task HandleTypeLoadFailure() await App.AssertWaitingForChanges(); - var newSrc = /* lang=c#-test */""" + var newSrc = """ class DepSubType : Dep { int F() => 2; @@ -128,9 +128,9 @@ public async Task HandleMissingAssemblyFailure() var testAsset = TestAssets.CopyTestAsset("WatchAppMissingAssemblyFailure") .WithSource(); - await App.StartWatcherAsync(testAsset, "App"); + App.Start(testAsset, [], "App"); - await App.WaitForSessionStarted(); + await App.AssertWaitingForChanges(); var newSrc = /* lang=c#-test */""" class DepSubType : Dep.DepType From 99cf50de298d164d23b6ffeb62b49c1db6b80985 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Tue, 10 Sep 2024 09:08:44 -0400 Subject: [PATCH 07/13] chore: Adjust for disabled test https://github.com/dotnet/sdk/issues/42850 --- test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index dd753b1caca3..0eaf3ed90b97 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -122,7 +122,7 @@ public async Task BlazorWasm() } // Test is timing out on .NET Framework: https://github.com/dotnet/sdk/issues/41669 - [CoreMSBuildOnlyFact] + [CoreMSBuildOnlyFact(Skip = "https://github.com/dotnet/sdk/issues/42850")] public async Task HandleMissingAssemblyFailure() { var testAsset = TestAssets.CopyTestAsset("WatchAppMissingAssemblyFailure") From 13c8c3ac6639ac7dff5f3283934d29f88118745b Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 12 Sep 2024 16:58:44 -0400 Subject: [PATCH 08/13] chore: Move GetCustomAttributesData to separate method --- .../DotNetDeltaApplier/HotReloadAgent.cs | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs b/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs index f11b430386d9..50301fdbf15c 100644 --- a/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs +++ b/src/BuiltInTools/DotNetDeltaApplier/HotReloadAgent.cs @@ -82,42 +82,49 @@ private UpdateHandlerActions GetMetadataUpdateHandlerActions() var handlerActions = new UpdateHandlerActions(); foreach (var assembly in sortedAssemblies) { - try + foreach (var attr in TryGetCustomAttributesData(assembly)) { - foreach (var attr in assembly.GetCustomAttributesData()) + // Look up the attribute by name rather than by type. This would allow netstandard targeting libraries to + // define their own copy without having to cross-compile. + if (attr.AttributeType.FullName != "System.Reflection.Metadata.MetadataUpdateHandlerAttribute") { - // Look up the attribute by name rather than by type. This would allow netstandard targeting libraries to - // define their own copy without having to cross-compile. - if (attr.AttributeType.FullName != "System.Reflection.Metadata.MetadataUpdateHandlerAttribute") - { - continue; - } - - IList ctorArgs = attr.ConstructorArguments; - if (ctorArgs.Count != 1 || - ctorArgs[0].Value is not Type handlerType) - { - _log($"'{attr}' found with invalid arguments."); - continue; - } - - GetHandlerActions(handlerActions, handlerType); + continue; } - } - catch (Exception e) - { - // In cross-platform scenarios, such as debugging in VS through WSL, Roslyn - // runs on Windows, and the agent runs on Linux. Assemblies accessible to Windows - // may not be available or loaded on linux (such as WPF's assemblies). - // In such case, we can ignore the assemblies and continue enumerating handlers for - // the rest of the assemblies of current domain. - _log($"'{assembly.FullName}' is not loaded ({e.Message})"); + + IList ctorArgs = attr.ConstructorArguments; + if (ctorArgs.Count != 1 || + ctorArgs[0].Value is not Type handlerType) + { + _log($"'{attr}' found with invalid arguments."); + continue; + } + + GetHandlerActions(handlerActions, handlerType); } } return handlerActions; } + private IList TryGetCustomAttributesData(Assembly assembly) + { + try + { + return assembly.GetCustomAttributesData(); + } + catch (Exception e) + { + // In cross-platform scenarios, such as debugging in VS through WSL, Roslyn + // runs on Windows, and the agent runs on Linux. Assemblies accessible to Windows + // may not be available or loaded on linux (such as WPF's assemblies). + // In such case, we can ignore the assemblies and continue enumerating handlers for + // the rest of the assemblies of current domain. + _log($"'{assembly.FullName}' is not loaded ({e.Message})"); + + return new List(); + } + } + internal void GetHandlerActions(UpdateHandlerActions handlerActions, Type handlerType) { bool methodFound = false; From b18ebc853bb9d61e2fe33b789d838812ddb759db Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 12 Sep 2024 17:00:15 -0400 Subject: [PATCH 09/13] chore: Restore test --- test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index 0eaf3ed90b97..dd753b1caca3 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -122,7 +122,7 @@ public async Task BlazorWasm() } // Test is timing out on .NET Framework: https://github.com/dotnet/sdk/issues/41669 - [CoreMSBuildOnlyFact(Skip = "https://github.com/dotnet/sdk/issues/42850")] + [CoreMSBuildOnlyFact] public async Task HandleMissingAssemblyFailure() { var testAsset = TestAssets.CopyTestAsset("WatchAppMissingAssemblyFailure") From 6dc00ca3ea0167b5144dba6690b2c2e588483911 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 12 Sep 2024 20:54:55 -0400 Subject: [PATCH 10/13] chore: Adjust test --- .../WatchAppMissingAssemblyFailure/App/Program.cs | 1 + test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs index 627d78708d6e..7998dd17ee92 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs @@ -14,6 +14,7 @@ lock (UpdateHandler.Guard) { Printer.Print(); + Dep.Printer.Print(); } Thread.Sleep(100); diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index dd753b1caca3..0e6edd22ec7e 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -133,12 +133,14 @@ public async Task HandleMissingAssemblyFailure() await App.AssertWaitingForChanges(); var newSrc = /* lang=c#-test */""" - class DepSubType : Dep.DepType + namespace Dep; + + public class DepType { int F() => 2; } - class Printer + public class Printer { public static void Print() { From 3abced94475af766c5b727c5cf71df9631de9821 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 12 Sep 2024 23:05:22 -0400 Subject: [PATCH 11/13] chore: Adjust for missing repro attribute --- .../App/Program.cs | 6 +++-- .../App/Update.cs | 5 ++-- .../WatchAppMissingAssemblyFailure/Dep/Dep.cs | 16 +------------ .../Dep/TestAttribute.cs | 8 +++++++ .../HotReload/ApplyDeltaTests.cs | 24 ++++--------------- 5 files changed, 19 insertions(+), 40 deletions(-) create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/TestAttribute.cs diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs index 7998dd17ee92..b8c821b783ea 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs @@ -2,7 +2,10 @@ using System.Reflection.Metadata; [assembly: MetadataUpdateHandler(typeof(UpdateHandler))] -[assembly: MetadataUpdateHandler(typeof(Dep.UpdateHandler))] + +// This attribute is not causing Dep.dll to be loaded, but enough +// to cause the HotReloadAgent to fail on getting custom attributes. +[assembly: Dep2.Test()] // delete the dependency dll to cause load failure of DepSubType var depPath = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location!)!, "Dep.dll"); @@ -14,7 +17,6 @@ lock (UpdateHandler.Guard) { Printer.Print(); - Dep.Printer.Print(); } Thread.Sleep(100); diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs index a589b9f27b7a..e804655e9da4 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs @@ -1,13 +1,12 @@ using System; -class DepSubType : Dep.DepType +public class Dep { int F() => 1; } -class Printer +public class Printer { public static void Print() => Console.WriteLine("Hello!"); } - diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs index 527201d3ef32..2dab04bd3d09 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs @@ -1,23 +1,9 @@ namespace Dep; -public class DepType +public class DepLib { void F() { Console.WriteLine(1); } } - -public static class UpdateHandler -{ - // Lock to avoid the updated Print method executing concurrently with the update handler. - public static object Guard = new object(); - - public static void UpdateApplication(Type[] types) - { - lock (Guard) - { - Console.WriteLine($"Dep Updated types: {(types == null ? "" : types.Length == 0 ? "" : string.Join(",", types.Select(t => t.Name)))}"); - } - } -} diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/TestAttribute.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/TestAttribute.cs new file mode 100644 index 000000000000..c2f2a9b52c12 --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/TestAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Dep2; + +[AttributeUsage(AttributeTargets.Assembly)] +public class TestAttribute : Attribute +{ +} diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index 0e6edd22ec7e..be781758365c 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -133,33 +133,17 @@ public async Task HandleMissingAssemblyFailure() await App.AssertWaitingForChanges(); var newSrc = /* lang=c#-test */""" - namespace Dep; + using System; - public class DepType + public class Dep { - int F() => 2; + int F() => 1; } public class Printer { public static void Print() - { - Console.WriteLine("Changed!"); - } - } - - public static class UpdateHandler - { - // Lock to avoid the updated Print method executing concurrently with the update handler. - public static object Guard = new object(); - - public static void UpdateApplication(Type[] types) - { - lock (Guard) - { - Console.WriteLine($"Dep Updated types: {(types == null ? "" : types.Length == 0 ? "" : string.Join(",", types.Select(t => t.Name)))}"); - } - } + => Console.WriteLine("Updated!"); } """; From d3191e25b04e43b55fe4d355dab9263e14702969 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Fri, 13 Sep 2024 07:58:07 -0400 Subject: [PATCH 12/13] chore: Move additional attribute to separate assembly --- .../WatchAppMissingAssemblyFailure/App/Program.cs | 7 ++----- .../WatchAppMissingAssemblyFailure/App/Update.cs | 2 +- .../WatchAppMissingAssemblyFailure/Dep/Dep.cs | 8 ++++++-- .../WatchAppMissingAssemblyFailure/Dep/Dep.csproj | 6 +++++- .../WatchAppMissingAssemblyFailure/Dep2/Dep2.cs | 9 +++++++++ .../WatchAppMissingAssemblyFailure/Dep2/Dep2.csproj | 8 ++++++++ .../{Dep => Dep2}/TestAttribute.cs | 0 test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 2 +- 8 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.cs create mode 100644 test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.csproj rename test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/{Dep => Dep2}/TestAttribute.cs (100%) diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs index b8c821b783ea..d81245d92af9 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Program.cs @@ -3,12 +3,8 @@ [assembly: MetadataUpdateHandler(typeof(UpdateHandler))] -// This attribute is not causing Dep.dll to be loaded, but enough -// to cause the HotReloadAgent to fail on getting custom attributes. -[assembly: Dep2.Test()] - // delete the dependency dll to cause load failure of DepSubType -var depPath = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location!)!, "Dep.dll"); +var depPath = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location!)!, "Dep2.dll"); File.Delete(depPath); Console.WriteLine($"File deleted: {depPath}"); @@ -17,6 +13,7 @@ lock (UpdateHandler.Guard) { Printer.Print(); + Dep.DepLib.F(); } Thread.Sleep(100); diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs index e804655e9da4..9ef906a439f0 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/App/Update.cs @@ -1,6 +1,6 @@ using System; -public class Dep +public class DepType { int F() => 1; } diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs index 2dab04bd3d09..404a726ae4f4 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.cs @@ -1,8 +1,12 @@ -namespace Dep; +// This attribute is not causing Dep.dll to be loaded, but enough +// to cause the HotReloadAgent to fail on getting custom attributes. +[assembly: Dep2.Test()] + +namespace Dep; public class DepLib { - void F() + public static void F() { Console.WriteLine(1); } diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj index 78589723776a..2776c7abc57d 100644 --- a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/Dep.csproj @@ -1,8 +1,12 @@ - + $(CurrentTargetFramework) enable + + + + diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.cs new file mode 100644 index 000000000000..548f61133dc7 --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.cs @@ -0,0 +1,9 @@ +namespace Dep2; + +public class Dep2Lib +{ + void F() + { + Console.WriteLine(1); + } +} diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.csproj b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.csproj new file mode 100644 index 000000000000..78589723776a --- /dev/null +++ b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/Dep2.csproj @@ -0,0 +1,8 @@ + + + + $(CurrentTargetFramework) + enable + + + diff --git a/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/TestAttribute.cs b/test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/TestAttribute.cs similarity index 100% rename from test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep/TestAttribute.cs rename to test/TestAssets/TestProjects/WatchAppMissingAssemblyFailure/Dep2/TestAttribute.cs diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index be781758365c..09ac86a83e62 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -135,7 +135,7 @@ public async Task HandleMissingAssemblyFailure() var newSrc = /* lang=c#-test */""" using System; - public class Dep + public class DepType { int F() => 1; } From daa5747dda242cd332b6890110d443e0c0690ddb Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Fri, 13 Sep 2024 09:26:09 -0400 Subject: [PATCH 13/13] chore: Adjust file deletion --- test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index 09ac86a83e62..b98819b8993c 100644 --- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -148,7 +148,7 @@ public static void Print() """; // Delete all files in testAsset.Path named Dep.dll - foreach (var depDll in Directory.GetFiles(testAsset.Path, "Dep.dll", SearchOption.AllDirectories)) + foreach (var depDll in Directory.GetFiles(testAsset.Path, "Dep2.dll", SearchOption.AllDirectories)) { File.Delete(depDll); }