From d607ba585b7dfe74fa53d25f71031e660d71822f Mon Sep 17 00:00:00 2001 From: Charlie Poole Date: Mon, 21 Oct 2024 16:43:37 -0700 Subject: [PATCH 1/2] Implement an algorithm to find extensions --- GitVersion.yml | 2 +- NUnitConsole.sln | 10 +--- build.cake | 36 ++++++----- nuget/engine/nunit.agent.addins | 1 - nuget/engine/nunit.engine.nuget.addins | 4 -- nuget/engine/nunit.engine.nuspec | 6 -- nuget/runners/net8.0/DotnetToolSettings.xml | 6 -- .../runners/nunit.console-runner.net80.nuspec | 53 ----------------- .../nunit.console-runner.netcore.nuspec | 1 - nuget/runners/nunit.console-runner.nuspec | 6 -- nuget/runners/nunit.console.nuget.addins | 11 ---- .../runners/nunit.console.nuget.agent.addins | 11 ---- package-tests.cake | 2 +- .../Services/ExtensionManagerTests.cs | 4 +- .../Services/ExtensionManager.cs | 59 ++++++++++++++++--- .../Services/ExtensionService.cs | 14 ++++- .../Services/IExtensionManager.cs | 17 +++++- 17 files changed, 104 insertions(+), 139 deletions(-) delete mode 100644 nuget/engine/nunit.agent.addins delete mode 100644 nuget/engine/nunit.engine.nuget.addins delete mode 100644 nuget/runners/net8.0/DotnetToolSettings.xml delete mode 100644 nuget/runners/nunit.console-runner.net80.nuspec delete mode 100644 nuget/runners/nunit.console.nuget.addins delete mode 100644 nuget/runners/nunit.console.nuget.agent.addins diff --git a/GitVersion.yml b/GitVersion.yml index 19dfb1105..3b27dee15 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,4 +1,4 @@ -next-version: 3.18.0 +next-version: 3.19.0 mode: ContinuousDelivery legacy-semver-padding: 5 build-metadata-padding: 5 diff --git a/NUnitConsole.sln b/NUnitConsole.sln index 9b322fbb5..8702696b9 100644 --- a/NUnitConsole.sln +++ b/NUnitConsole.sln @@ -77,8 +77,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "choco", "choco", "{4FDF7BFA choco\nunit-agent-x86.exe.ignore = choco\nunit-agent-x86.exe.ignore choco\nunit-agent.exe.ignore = choco\nunit-agent.exe.ignore choco\nunit-console-runner.nuspec = choco\nunit-console-runner.nuspec - choco\nunit.console.choco.addins = choco\nunit.console.choco.addins - choco\nunit.console.choco.agent.addins = choco\nunit.console.choco.agent.addins choco\VERIFICATION.txt = choco\VERIFICATION.txt EndProjectSection EndProject @@ -147,14 +145,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InvalidTestNames", "src\Tes EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppContextTest", "src\TestData\AppContextTest\AppContextTest.csproj", "{E43A3E4B-B050-471B-B43C-0DF60FD44376}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net8.0", "net8.0", "{303CF83E-2A87-4882-8CAC-3EB59AAD81FC}" - ProjectSection(SolutionItems) = preProject - nuget\runners\net8.0\DotnetToolSettings.xml = nuget\runners\net8.0\DotnetToolSettings.xml - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mock-assembly-v2", "src\TestData\mock-assembly-v2\mock-assembly-v2.csproj", "{AD40CA55-35CC-41CA-85F5-8FDA4ECAFF78}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FakeExtensions", "src\TestData\FakeExtensions\FakeExtensions.csproj", "{D6C217E0-BFB7-4C80-8D50-C969F46EBC59}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FakeExtensions", "src\TestData\FakeExtensions\FakeExtensions.csproj", "{D6C217E0-BFB7-4C80-8D50-C969F46EBC59}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -276,7 +269,6 @@ Global {6B550F25-1CA5-4F3E-B631-1ECCD4CB94E4} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} {58E18ACC-1F7E-4395-817E-E7EF943E0C77} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} {E43A3E4B-B050-471B-B43C-0DF60FD44376} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} - {303CF83E-2A87-4882-8CAC-3EB59AAD81FC} = {F3E87D0F-6F06-4C0B-AE06-42C0834C3C6E} {AD40CA55-35CC-41CA-85F5-8FDA4ECAFF78} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} {D6C217E0-BFB7-4C80-8D50-C969F46EBC59} = {2ECE1CFB-9436-4149-B7E4-1FB1786FDE9F} EndGlobalSection diff --git a/build.cake b/build.cake index d6377ab16..9005688f2 100644 --- a/build.cake +++ b/build.cake @@ -19,7 +19,7 @@ BuildSettings.Initialize( FilePath[] ConsoleFiles = { "nunit3-console.dll", "nunit3-console.dll.config", "nunit3-console.exe", "nunit3-console.pdb", - "nunit3-console.deps.json", "nunit3-console.runtimeconfig.json", "nunit.console.nuget.addins" }; + "nunit3-console.deps.json", "nunit3-console.runtimeconfig.json" }; FilePath[] ENGINE_FILES = { "nunit.engine.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll" }; FilePath[] ENGINE_PDB_FILES = { @@ -61,12 +61,12 @@ BuildSettings.Packages.AddRange(new PackageDefinition[] { source: BuildSettings.NuGetDirectory + "runners/nunit.console-runner.nuspec", checks: new PackageCheck[] { HasFiles("LICENSE.txt", "NOTICES.txt"), - HasDirectory("tools").WithFiles("nunit3-console.exe", "nunit3-console.exe.config", "nunit.console.nuget.addins").AndFiles(ENGINE_FILES), - HasDirectory("tools/agents/net462").WithFiles(AGENT_FILES).AndFile("nunit.console.nuget.agent.addins"), - HasDirectory("tools/agents/netcoreapp3.1").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.nuget.agent.addins"), - HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.nuget.agent.addins"), - HasDirectory("tools/agents/net7.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.nuget.agent.addins"), - HasDirectory("tools/agents/net8.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.nuget.agent.addins") + HasDirectory("tools").WithFiles("nunit3-console.exe", "nunit3-console.exe.config").AndFiles(ENGINE_FILES), + HasDirectory("tools/agents/net462").WithFiles(AGENT_FILES), + HasDirectory("tools/agents/netcoreapp3.1").WithFiles(AGENT_FILES_NETCORE), + HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE), + HasDirectory("tools/agents/net7.0").WithFiles(AGENT_FILES_NETCORE), + HasDirectory("tools/agents/net8.0").WithFiles(AGENT_FILES_NETCORE) }, symbols: new PackageCheck[] { HasDirectory("tools").WithFiles(ENGINE_PDB_FILES).AndFile("nunit3-console.pdb"), @@ -103,12 +103,12 @@ BuildSettings.Packages.AddRange(new PackageDefinition[] { id: "nunit-console-runner", source: BuildSettings.ChocolateyDirectory + "nunit-console-runner.nuspec", checks: new PackageCheck[] { - HasDirectory("tools").WithFiles("LICENSE.txt", "NOTICES.txt", "VERIFICATION.txt", "nunit3-console.exe", "nunit3-console.exe.config", "nunit.console.choco.addins").AndFiles(ENGINE_FILES), - HasDirectory("tools/agents/net462").WithFiles(AGENT_FILES).AndFile("nunit.console.choco.agent.addins"), - HasDirectory("tools/agents/netcoreapp3.1").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.choco.agent.addins"), - HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.choco.agent.addins"), - HasDirectory("tools/agents/net7.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.choco.agent.addins"), - HasDirectory("tools/agents/net8.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.console.choco.agent.addins") + HasDirectory("tools").WithFiles("LICENSE.txt", "NOTICES.txt", "VERIFICATION.txt", "nunit3-console.exe", "nunit3-console.exe.config").AndFiles(ENGINE_FILES), + HasDirectory("tools/agents/net462").WithFiles(AGENT_FILES), + HasDirectory("tools/agents/netcoreapp3.1").WithFiles(AGENT_FILES_NETCORE), + HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE), + HasDirectory("tools/agents/net7.0").WithFiles(AGENT_FILES_NETCORE), + HasDirectory("tools/agents/net8.0").WithFiles(AGENT_FILES_NETCORE) }, testRunner: new ConsoleRunnerSelfTester(BuildSettings.ChocolateyTestDirectory + $"nunit-console-runner.{BuildSettings.PackageVersion}/tools/nunit3-console.exe"), @@ -151,9 +151,7 @@ BuildSettings.Packages.AddRange(new PackageDefinition[] { HasFiles("LICENSE.txt", "NOTICES.txt"), HasDirectory("lib/net462").WithFiles(ENGINE_FILES), HasDirectory("lib/net8.0").WithFiles(ENGINE_FILES).AndFile("Microsoft.Extensions.DependencyModel.dll"), - HasDirectory("contentFiles/any/lib/net462").WithFile("nunit.engine.nuget.addins"), - HasDirectory("contentFiles/any/lib/net8.0").WithFile("nunit.engine.nuget.addins"), - HasDirectory("contentFiles/any/agents/net462").WithFiles(AGENT_FILES).AndFile("nunit.agent.addins") + HasDirectory("contentFiles/any/agents/net462").WithFiles(AGENT_FILES) }, symbols: new PackageCheck[] { HasDirectory("lib/net462").WithFiles(ENGINE_PDB_FILES), @@ -201,6 +199,12 @@ Task("TestZipPackage") NUnitConsoleZipPackage.RunPackageTests(); }); +Task("TestNetCorePackage") + .Does(() => + { + NUnitConsoleRunnerNetCorePackage.RunPackageTests(); + }); + // Adhoc code to check content of a dotnet standalone executable // TODO: Incorporate this in the recipe itself diff --git a/nuget/engine/nunit.agent.addins b/nuget/engine/nunit.agent.addins deleted file mode 100644 index 1558d5f75..000000000 --- a/nuget/engine/nunit.agent.addins +++ /dev/null @@ -1 +0,0 @@ -../../ # refer to the directory containing the engine and runner diff --git a/nuget/engine/nunit.engine.nuget.addins b/nuget/engine/nunit.engine.nuget.addins deleted file mode 100644 index ffb7ae1b7..000000000 --- a/nuget/engine/nunit.engine.nuget.addins +++ /dev/null @@ -1,4 +0,0 @@ -../../../NUnit.Extension.*/**/tools/ # nuget v2 layout -../../../../NUnit.Extension.*/**/tools/ # nuget v3 layout -../../../nunit.extension.*/**/tools/ # nuget v2 layout -../../../../nunit.extension.*/**/tools/ # nuget v3 layout diff --git a/nuget/engine/nunit.engine.nuspec b/nuget/engine/nunit.engine.nuspec index e3eed7538..76dfd2651 100644 --- a/nuget/engine/nunit.engine.nuspec +++ b/nuget/engine/nunit.engine.nuspec @@ -66,11 +66,6 @@ - - - - - @@ -79,7 +74,6 @@ - diff --git a/nuget/runners/net8.0/DotnetToolSettings.xml b/nuget/runners/net8.0/DotnetToolSettings.xml deleted file mode 100644 index e49f98228..000000000 --- a/nuget/runners/net8.0/DotnetToolSettings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/nuget/runners/nunit.console-runner.net80.nuspec b/nuget/runners/nunit.console-runner.net80.nuspec deleted file mode 100644 index 00b997e5b..000000000 --- a/nuget/runners/nunit.console-runner.net80.nuspec +++ /dev/null @@ -1,53 +0,0 @@ - - - - NUnit.ConsoleRunner.Net80 - NUnit Console Runner (.NET 8.0) - $version$ - Charlie Poole, Rob Prouse - Charlie Poole, Rob Prouse - LICENSE.txt - https://nunit.org - - https://cdn.rawgit.com/nunit/resources/master/images/icon/nunit_256.png - images\nunit_256.png - false - .NET Core build of the console runner for the NUnit unit-testing framework. - - This package includes the .NET 8.0 build of the NUnit console runner and test engine. - - Any extensions, if needed, may be installed as separate packages. - - https://docs.nunit.org/articles/nunit/release-notes/console-and-engine.html - en-US - nunit test testing tdd runner - Copyright (c) 2021-2024 Charlie Poole, Rob Prouse - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/nuget/runners/nunit.console-runner.netcore.nuspec b/nuget/runners/nunit.console-runner.netcore.nuspec index a2005cdec..d1aa3df2b 100644 --- a/nuget/runners/nunit.console-runner.netcore.nuspec +++ b/nuget/runners/nunit.console-runner.netcore.nuspec @@ -45,7 +45,6 @@ - diff --git a/nuget/runners/nunit.console-runner.nuspec b/nuget/runners/nunit.console-runner.nuspec index 343dc1c81..3489e8a10 100644 --- a/nuget/runners/nunit.console-runner.nuspec +++ b/nuget/runners/nunit.console-runner.nuspec @@ -39,7 +39,6 @@ - @@ -53,7 +52,6 @@ - @@ -67,7 +65,6 @@ - @@ -81,7 +78,6 @@ - @@ -95,7 +91,6 @@ - @@ -108,7 +103,6 @@ - diff --git a/nuget/runners/nunit.console.nuget.addins b/nuget/runners/nunit.console.nuget.addins deleted file mode 100644 index f540c8540..000000000 --- a/nuget/runners/nunit.console.nuget.addins +++ /dev/null @@ -1,11 +0,0 @@ -# Extensions built for a single runtime target -../../NUnit.Extension.*/**/tools/ # nuget v2 layout -../../../NUnit.Extension.*/**/tools/ # nuget v3 layout -../../nunit.extension.*/**/tools/ # nuget v2 layout -../../../nunit.extension.*/**/tools/ # nuget v3 layout - -# Extensions built for multiple targets -../../NUnit.Extension.*/**/tools/*/ # nuget v2 layout -../../../NUnit.Extension.*/**/tools/*/ # nuget v3 layout -../../nunit.extension.*/**/tools/*/ # nuget v2 layout -../../../nunit.extension.*/**/tools/*/ # nuget v3 layout diff --git a/nuget/runners/nunit.console.nuget.agent.addins b/nuget/runners/nunit.console.nuget.agent.addins deleted file mode 100644 index ddfcb54ab..000000000 --- a/nuget/runners/nunit.console.nuget.agent.addins +++ /dev/null @@ -1,11 +0,0 @@ -# Extensions built for a single runtime target -../../../../NUnit.Extension.*/**/tools/ # nuget v2 layout -../../../../../NUnit.Extension.*/**/tools/ # nuget v3 layout -../../../../nunit.extension.*/**/tools/ # nuget v2 layout -../../../../../nunit.extension.*/**/tools/ # nuget v3 layout - -# Extensions built for multiple targets -../../../../NUnit.Extension.*/**/tools/*/ # nuget v2 layout -../../../../../NUnit.Extension.*/**/tools/*/ # nuget v3 layout -../../../../nunit.extension.*/**/tools/*/ # nuget v2 layout -../../../../../nunit.extension.*/**/tools/*/ # nuget v3 layout diff --git a/package-tests.cake b/package-tests.cake index 7c893672e..eab3b20c9 100644 --- a/package-tests.cake +++ b/package-tests.cake @@ -210,7 +210,7 @@ StandardRunnerTests.Add(new PackageTest( KnownExtensions.NUnitProjectLoader)); // V2 Result Writer Test -StandardRunnerTests.Add(new PackageTest( +AddToBothLists(new PackageTest( 1, "V2ResultWriterTest", "Run mock-assembly under .NET 6.0 and produce V2 output", "testdata/net6.0/mock-assembly.dll --result=TestResult.xml --result=NUnit2TestResult.xml;format=nunit2", diff --git a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs index eca71b122..dc3e8e12d 100644 --- a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs +++ b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs @@ -12,7 +12,7 @@ using NUnit.Engine.Internal.FileSystemAccess; using System.Diagnostics; -namespace NUnit.Engine.Services.Tests +namespace NUnit.Engine.Services { public class ExtensionManagerTests { @@ -58,7 +58,7 @@ public void CreateExtensionManager() // Find actual extension points. _extensionManager.FindExtensionPoints(typeof(CoreEngine).Assembly); _extensionManager.FindExtensionPoints(typeof(ITestEngine).Assembly); - // Find extensions. + // Find extensions directly in the their assemblies #if NETCOREAPP _extensionManager.FindExtensionsInAssembly(FakeExtensions("netstandard2.0")); #else diff --git a/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs b/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs index 8e9d6d449..731ec1ab7 100644 --- a/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs +++ b/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs @@ -15,8 +15,9 @@ namespace NUnit.Engine.Services { public class ExtensionManager : IExtensionManager { - static readonly Logger log = InternalTrace.GetLogger(typeof(ExtensionService)); - static readonly Version ENGINE_VERSION = typeof(ExtensionService).Assembly.GetName().Version; + static readonly Logger log = InternalTrace.GetLogger(typeof(ExtensionManager)); + static readonly Assembly THIS_ASSEMBLY = Assembly.GetExecutingAssembly(); + static readonly Version ENGINE_VERSION = THIS_ASSEMBLY.GetName().Version; private readonly IFileSystem _fileSystem; //private readonly IAddinsFileReader _addinsReader; @@ -120,6 +121,11 @@ public virtual void FindExtensionPoints(params Assembly[] targetAssemblies) } } + /// + /// Find and install extensions starting from a given base directory, + /// and using the contained '.addins' files to direct the search. + /// + /// public void FindExtensions(string startDir) { // Create the list of possible extension assemblies, @@ -131,6 +137,21 @@ public void FindExtensions(string startDir) FindExtensionsInAssembly(candidate); } + /// + /// Find and install extensions starting from a given base directory, + /// and using the provided list of patterns to direct the search using + /// a built-in algorithm. + /// + /// Path to the initial directory. + /// A list of patterns used to identify potential candidates. + public void FindExtensions(string startDir, string[] patterns) + { + FindExtensionAssemblies(_fileSystem.GetDirectory(startDir), patterns); + + foreach (var candidate in _assemblies) + FindExtensionsInAssembly(candidate); + } + /// /// Get an ExtensionPoint based on its unique identifying path. /// @@ -233,14 +254,36 @@ private ExtensionPoint DeduceExtensionPointFromType(TypeReference typeRef) } /// - /// Find candidate extension assemblies starting from a - /// given base directory. + /// Find candidate extension assemblies starting from a given base directory + /// and using the contained '.addins' files to direct the search. /// - /// - private void FindExtensionAssemblies(IDirectory startDir) + /// Path to the initial directory. + private void FindExtensionAssemblies(IDirectory initialDirectory) + { + // Since no patterns are provided, look for addins files + ProcessAddinsFiles(initialDirectory, false); + } + + /// + /// Find candidate extension assemblies starting from a given base directory + /// and using the provided list of patterns to direct the search using + /// a built-in algorithm. + /// + /// Path to the initial directory. + /// A list of patterns used to identify potential candidates. + private void FindExtensionAssemblies(IDirectory initialDirectory, string[] patterns) { - // First check the directory itself - ProcessAddinsFiles(startDir, false); + // Start looking two levels above initial directory + var startDir = initialDirectory.Parent.Parent; + + while (startDir != null) + { + foreach (var pattern in patterns) + foreach (var dir in _directoryFinder.GetDirectories(startDir, pattern)) + ProcessDirectory(dir, true); + + startDir = startDir.Parent; + } } /// diff --git a/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs b/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs index 74ef1abcf..d3dba41b4 100644 --- a/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs +++ b/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs @@ -8,6 +8,7 @@ using NUnit.Engine.Internal; using NUnit.Engine.Internal.FileSystemAccess; using NUnit.Engine.Internal.FileSystemAccess.Default; +using System.IO; namespace NUnit.Engine.Services { @@ -18,6 +19,13 @@ namespace NUnit.Engine.Services /// public class ExtensionService : Service, IExtensionService { + private static readonly Assembly THIS_ASSEMBLY = typeof(ExtensionService).Assembly; + + private static readonly string[] CHOCO_PATTERNS = new[] { + "nunit-extension-*/**/tools/", "nunit-extension-*/**/tools/*/" }; + private static readonly string[] NUGET_PATTERNS = new[] { + "NUnit.Extension.*/**/tools/", "NUnit.Extension.*/**/tools/*/" }; + private readonly IExtensionManager _extensionManager; public ExtensionService() @@ -81,8 +89,10 @@ public override void StartService() Assembly.GetExecutingAssembly(), typeof(ITestEngine).Assembly); - var thisAssembly = Assembly.GetExecutingAssembly(); - _extensionManager.FindExtensions(AssemblyHelper.GetDirectoryName(thisAssembly)); + var initialDirectory = AssemblyHelper.GetDirectoryName(THIS_ASSEMBLY); + bool isChocolateyPackage = System.IO.File.Exists(Path.Combine(THIS_ASSEMBLY.Location, "VERIFICATION.txt")); + + _extensionManager.FindExtensions(initialDirectory, isChocolateyPackage ? CHOCO_PATTERNS : NUGET_PATTERNS); Status = ServiceStatus.Started; } diff --git a/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs b/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs index c02704d5a..d688eb328 100644 --- a/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs +++ b/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs @@ -14,7 +14,22 @@ public interface IExtensionManager : IDisposable IEnumerable Extensions { get; } void FindExtensionPoints(params Assembly[] targetAssemblies); - void FindExtensions(string startDir); + + /// + /// Find and install extensions starting from a given base directory, + /// and using the contained '.addins' files to direct the search. + /// + /// Path to the initial directory. + void FindExtensions(string initialDirectory); + + /// + /// Find and install extensions starting from a given base directory, + /// and using the provided list of patterns to direct the search using + /// a built-in algorithm. + /// + /// Path to the initial directory. + /// A list of patterns used to identify potential candidates. + void FindExtensions(string initialDirectory, string[] patterns); IExtensionPoint GetExtensionPoint(string path); From 2945f31e9cd34095359a769bab44285f87d8f175 Mon Sep 17 00:00:00 2001 From: Charlie Poole Date: Fri, 1 Nov 2024 12:07:11 -0700 Subject: [PATCH 2/2] Revise api in response to comments --- choco/nunit-console-runner.nuspec | 6 -- choco/nunit.console.choco.addins | 7 --- choco/nunit.console.choco.agent.addins | 7 --- .../Services/ExtensionManagerTests.cs | 2 +- .../Services/ExtensionServiceTests.cs | 5 +- .../Services/ExtensionManager.cs | 63 +++++++++++-------- .../Services/ExtensionService.cs | 20 ++---- .../Services/IExtensionManager.cs | 10 ++- 8 files changed, 50 insertions(+), 70 deletions(-) delete mode 100644 choco/nunit.console.choco.addins delete mode 100644 choco/nunit.console.choco.agent.addins diff --git a/choco/nunit-console-runner.nuspec b/choco/nunit-console-runner.nuspec index a1c687367..d5eededcc 100644 --- a/choco/nunit-console-runner.nuspec +++ b/choco/nunit-console-runner.nuspec @@ -29,7 +29,6 @@ - @@ -49,7 +48,6 @@ - @@ -60,7 +58,6 @@ - @@ -71,7 +68,6 @@ - @@ -82,7 +78,6 @@ - @@ -93,6 +88,5 @@ - diff --git a/choco/nunit.console.choco.addins b/choco/nunit.console.choco.addins deleted file mode 100644 index d07fb7a21..000000000 --- a/choco/nunit.console.choco.addins +++ /dev/null @@ -1,7 +0,0 @@ -# Extensions built for a single runtime target -../../nunit-extension-*/**/tools/ # nuget v2 layout -../../../nunit-extension-*/**/tools/ # nuget v3 layout - -# Extensions built for multiple targets -../../nunit-extension-*/**/tools/*/ # nuget v2 layout -../../../nunit-extension-*/**/tools/*/ # nuget v3 layout diff --git a/choco/nunit.console.choco.agent.addins b/choco/nunit.console.choco.agent.addins deleted file mode 100644 index d326d241b..000000000 --- a/choco/nunit.console.choco.agent.addins +++ /dev/null @@ -1,7 +0,0 @@ -# Extensions built for a single runtime target -../../../../nunit-extension-*/tools/ # find extensions installed under chocolatey -../../../../../nunit-extension-*/tools/ # find extensions installed under chocolatey - -# Extensions built for multiple targets -../../../../nunit-extension-*/tools/*/ # find extensions installed under chocolatey -../../../../../nunit-extension-*/tools/*/ # find extensions installed under chocolatey diff --git a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs index dc3e8e12d..ccf1382dd 100644 --- a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs +++ b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs @@ -12,7 +12,7 @@ using NUnit.Engine.Internal.FileSystemAccess; using System.Diagnostics; -namespace NUnit.Engine.Services +namespace NUnit.Engine.Services.Tests { public class ExtensionManagerTests { diff --git a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionServiceTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionServiceTests.cs index 3f6a5664f..9b8f3bc21 100644 --- a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionServiceTests.cs +++ b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionServiceTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -51,12 +52,12 @@ public void CreateService() [Test] public void StartServiceInitializesExtensionManager() { - var workingDir = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly); + Assembly hostAssembly = typeof(ExtensionService).Assembly; _extensionService.StartService(); _extensionManager.ReceivedWithAnyArgs().FindExtensionPoints(typeof(ExtensionService).Assembly, typeof(ITestEngine).Assembly); - _extensionManager.Received().FindExtensions(workingDir); + _extensionManager.Received().FindStandardExtensions(hostAssembly); Assert.That(_extensionService.Status, Is.EqualTo(ServiceStatus.Started)); } diff --git a/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs b/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs index 731ec1ab7..5becf2a7d 100644 --- a/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs +++ b/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs @@ -16,8 +16,6 @@ namespace NUnit.Engine.Services public class ExtensionManager : IExtensionManager { static readonly Logger log = InternalTrace.GetLogger(typeof(ExtensionManager)); - static readonly Assembly THIS_ASSEMBLY = Assembly.GetExecutingAssembly(); - static readonly Version ENGINE_VERSION = THIS_ASSEMBLY.GetName().Version; private readonly IFileSystem _fileSystem; //private readonly IAddinsFileReader _addinsReader; @@ -138,15 +136,18 @@ public void FindExtensions(string startDir) } /// - /// Find and install extensions starting from a given base directory, - /// and using the provided list of patterns to direct the search using - /// a built-in algorithm. + /// Find and install standard extensions for a host assembly using + /// a built-in algorithm that searches in certain known locations. /// - /// Path to the initial directory. - /// A list of patterns used to identify potential candidates. - public void FindExtensions(string startDir, string[] patterns) + /// An assembly that supports extensions. + public void FindStandardExtensions(Assembly hostAssembly) { - FindExtensionAssemblies(_fileSystem.GetDirectory(startDir), patterns); + bool isChocolateyPackage = System.IO.File.Exists(Path.Combine(hostAssembly.Location, "VERIFICATION.txt")); + string[] extensionPatterns = isChocolateyPackage + ? new[] { "nunit-extension-*/**/tools/", "nunit-extension-*/**/tools/*/" } + : new[] { "NUnit.Extension.*/**/tools/", "NUnit.Extension.*/**/tools/*/" }; + + FindExtensionAssemblies(hostAssembly, extensionPatterns); foreach (var candidate in _assemblies) FindExtensionsInAssembly(candidate); @@ -265,16 +266,15 @@ private void FindExtensionAssemblies(IDirectory initialDirectory) } /// - /// Find candidate extension assemblies starting from a given base directory - /// and using the provided list of patterns to direct the search using + /// Find candidate extension assemblies for a given host assembly, + /// using the provided list of patterns to direct the search using /// a built-in algorithm. /// - /// Path to the initial directory. + /// An assembly that supports extensions /// A list of patterns used to identify potential candidates. - private void FindExtensionAssemblies(IDirectory initialDirectory, string[] patterns) + private void FindExtensionAssemblies(Assembly hostAssembly, string[] patterns) { - // Start looking two levels above initial directory - var startDir = initialDirectory.Parent.Parent; + IDirectory startDir = _fileSystem.GetDirectory(AssemblyHelper.GetDirectoryName(hostAssembly)); while (startDir != null) { @@ -459,18 +459,29 @@ internal void FindExtensionsInAssembly(ExtensionAssembly assembly) } #endif - foreach (var type in assembly.MainModule.GetTypes()) + foreach (var extensionType in assembly.MainModule.GetTypes()) { - CustomAttribute extensionAttr = type.GetAttribute("NUnit.Engine.Extensibility.ExtensionAttribute"); + CustomAttribute extensionAttr = extensionType.GetAttribute("NUnit.Engine.Extensibility.ExtensionAttribute"); if (extensionAttr == null) continue; - object versionArg = extensionAttr.GetNamedArgument("EngineVersion"); - if (versionArg != null && new Version((string)versionArg) > ENGINE_VERSION) - continue; + // TODO: This is a remnant of older code. In principle, this should be generalized + // to something like "HostVersion". However, this can safely remain until + // we separate ExtensionManager into its own assembly. + string versionArg = extensionAttr.GetNamedArgument("EngineVersion") as string; + if (versionArg != null) + { + Assembly THIS_ASSEMBLY = Assembly.GetExecutingAssembly(); + Version ENGINE_VERSION = THIS_ASSEMBLY.GetName().Version; + if (new Version(versionArg) > ENGINE_VERSION) + { + log.Warning($" Ignoring {extensionType.Name}. It requires version {versionArg}."); + continue; + } + } - var node = new ExtensionNode(assembly.FilePath, assembly.AssemblyVersion, type.FullName, assemblyTargetFramework) + var node = new ExtensionNode(assembly.FilePath, assembly.AssemblyVersion, extensionType.FullName, assemblyTargetFramework) { Path = extensionAttr.GetNamedArgument("Path") as string, Description = extensionAttr.GetNamedArgument("Description") as string @@ -479,9 +490,9 @@ internal void FindExtensionsInAssembly(ExtensionAssembly assembly) object enabledArg = extensionAttr.GetNamedArgument("Enabled"); node.Enabled = enabledArg == null || (bool)enabledArg; - log.Info(" Found ExtensionAttribute on Type " + type.Name); + log.Info(" Found ExtensionAttribute on Type " + extensionType.Name); - foreach (var attr in type.GetAttributes("NUnit.Engine.Extensibility.ExtensionPropertyAttribute")) + foreach (var attr in extensionType.GetAttributes("NUnit.Engine.Extensibility.ExtensionPropertyAttribute")) { string name = attr.ConstructorArguments[0].Value as string; string value = attr.ConstructorArguments[1].Value as string; @@ -498,12 +509,12 @@ internal void FindExtensionsInAssembly(ExtensionAssembly assembly) ExtensionPoint ep; if (node.Path == null) { - ep = DeduceExtensionPointFromType(type); + ep = DeduceExtensionPointFromType(extensionType); if (ep == null) { string msg = string.Format( "Unable to deduce ExtensionPoint for Type {0}. Specify Path on ExtensionAttribute to resolve.", - type.FullName); + extensionType.FullName); throw new NUnitEngineException(msg); } @@ -517,7 +528,7 @@ internal void FindExtensionsInAssembly(ExtensionAssembly assembly) { string msg = string.Format( "Unable to locate ExtensionPoint for Type {0}. The Path {1} cannot be found.", - type.FullName, + extensionType.FullName, node.Path); throw new NUnitEngineException(msg); } diff --git a/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs b/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs index d3dba41b4..7459ed8ca 100644 --- a/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs +++ b/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs @@ -19,13 +19,6 @@ namespace NUnit.Engine.Services /// public class ExtensionService : Service, IExtensionService { - private static readonly Assembly THIS_ASSEMBLY = typeof(ExtensionService).Assembly; - - private static readonly string[] CHOCO_PATTERNS = new[] { - "nunit-extension-*/**/tools/", "nunit-extension-*/**/tools/*/" }; - private static readonly string[] NUGET_PATTERNS = new[] { - "NUnit.Extension.*/**/tools/", "NUnit.Extension.*/**/tools/*/" }; - private readonly IExtensionManager _extensionManager; public ExtensionService() @@ -83,16 +76,13 @@ public void EnableExtension(string typeName, bool enabled) public override void StartService() { + Assembly thisAssembly = Assembly.GetExecutingAssembly(); + Assembly apiAssembly = typeof(ITestEngine).Assembly; + try { - _extensionManager.FindExtensionPoints( - Assembly.GetExecutingAssembly(), - typeof(ITestEngine).Assembly); - - var initialDirectory = AssemblyHelper.GetDirectoryName(THIS_ASSEMBLY); - bool isChocolateyPackage = System.IO.File.Exists(Path.Combine(THIS_ASSEMBLY.Location, "VERIFICATION.txt")); - - _extensionManager.FindExtensions(initialDirectory, isChocolateyPackage ? CHOCO_PATTERNS : NUGET_PATTERNS); + _extensionManager.FindExtensionPoints(thisAssembly, apiAssembly); + _extensionManager.FindStandardExtensions(thisAssembly); Status = ServiceStatus.Started; } diff --git a/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs b/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs index d688eb328..c6e9ebd63 100644 --- a/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs +++ b/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs @@ -23,13 +23,11 @@ public interface IExtensionManager : IDisposable void FindExtensions(string initialDirectory); /// - /// Find and install extensions starting from a given base directory, - /// and using the provided list of patterns to direct the search using - /// a built-in algorithm. + /// Find and install standard extensions for a host assembly using + /// a built-in algorithm that searches in certain known locations. /// - /// Path to the initial directory. - /// A list of patterns used to identify potential candidates. - void FindExtensions(string initialDirectory, string[] patterns); + /// An assembly that supports NUnit extensions. + void FindStandardExtensions(Assembly hostAssembly); IExtensionPoint GetExtensionPoint(string path);