From eca975c8ece699d610fa28d0b1239b0b1dd09b26 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Fri, 4 Nov 2022 13:20:16 -0700 Subject: [PATCH 01/31] Added in preliminary test that ensures the correct exception is thrown when the extension isn't found. --- .../EgressExtensibilityTests.cs | 57 +++++++++++++++++++ .../TestHostHelper.cs | 4 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs new file mode 100644 index 00000000000..0ed6a688021 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Monitoring.TestCommon; +using Microsoft.Diagnostics.Tools.Monitor; +using Microsoft.Diagnostics.Tools.Monitor.Extensibility; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests +{ + public sealed class EgressExtensibilityTests + { + private ITestOutputHelper _outputHelper; + + public EgressExtensibilityTests(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + } + + /* Test Coverage + * + * Successfully finding extension in each location + * Proper resolution if conflict in terms of priority + * Fails properly if extension is not found + * Extension.json file is properly found and parsed to find extension and DisplayName + * Fails properly if Extension.json is not found / doesn't contain correct contents + * Logs from extension are properly passed through to dotnet monitor + * + */ + + [Fact] + public void FoundExtension_Failure() + { + using TemporaryDirectory sharedConfigDir = new(_outputHelper); + using TemporaryDirectory userConfigDir = new(_outputHelper); + + // Set up the initial settings used to create the host builder. + HostBuilderSettings settings = new() + { + SharedConfigDirectory = sharedConfigDir.FullName, + UserConfigDirectory = userConfigDir.FullName + }; + + IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); + + var extensionDiscoverer = host.Services.GetService(); + + const string extensionDisplayName = "AzureBlobStorage"; + + Assert.Throws(() => extensionDiscoverer.FindExtension(extensionDisplayName)); + } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs index 1f8ef348e3d..aab7dc8ca38 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs @@ -62,7 +62,8 @@ public static IHost CreateHost( Action setup, Action servicesCallback, Action loggingCallback = null, - List overrideSource = null) + List overrideSource = null, + HostBuilderSettings settings = null) { return new HostBuilder() .ConfigureAppConfiguration(builder => @@ -100,6 +101,7 @@ public static IHost CreateHost( services.ConfigureTemplates(context.Configuration); services.AddSingleton(); services.ConfigureCollectionRules(); + services.ConfigureExtensions(settings); // settings could be null...how do we want to protect against this? services.ConfigureEgress(); services.ConfigureDiagnosticPort(context.Configuration); From 7843e555a79545b4fe59f53e8bf0e638fd9651b9 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Fri, 4 Nov 2022 13:48:29 -0700 Subject: [PATCH 02/31] Added in basic test that checks that an extension.json file is found for the extension. Note that this currently uses the existing mechanism for checking against names (where the extension's name is the same as the way it's represented in configuration) - this will likely need to be tweaked when new changes go in. --- .../EgressExtensibilityTests.cs | 39 +++++++++++++++++++ .../EgressExtensionResources/extension.json | 9 +++++ ...agnostics.Monitoring.Tool.UnitTests.csproj | 3 ++ 3 files changed, 51 insertions(+) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 0ed6a688021..8a1b4e9bf97 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -7,6 +7,10 @@ using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.Json; using Xunit; using Xunit.Abstractions; @@ -15,6 +19,9 @@ namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests public sealed class EgressExtensibilityTests { private ITestOutputHelper _outputHelper; + private const string ExtensionsFolder = "extensions"; + private const string ExtensionDefinitionFile = "extension.json"; + private const string EgressExtensionsDirectory = "EgressExtensionResources"; public EgressExtensibilityTests(ITestOutputHelper outputHelper) { @@ -53,5 +60,37 @@ public void FoundExtension_Failure() Assert.Throws(() => extensionDiscoverer.FindExtension(extensionDisplayName)); } + + // This only verifies that the Extension.json file is found for the user's extension, + // not that there is a suitable executable file. + [Fact] + public void FoundExtension_Success() + { + //const string extensionDisplayName = "AzureBlobStorage"; // This has to be the same as the display name within the Extension.json file + const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; + + using TemporaryDirectory sharedConfigDir = new(_outputHelper); + using TemporaryDirectory userConfigDir = new(_outputHelper); + + // Set up the initial settings used to create the host builder. + HostBuilderSettings settings = new() + { + SharedConfigDirectory = sharedConfigDir.FullName, + UserConfigDirectory = userConfigDir.FullName + }; + + string destPath = Path.Combine(userConfigDir.FullName, ExtensionsFolder, extensionDirectoryName); + + Directory.CreateDirectory(destPath); + + File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), + Path.Combine(destPath, ExtensionDefinitionFile)); + + IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); + + var extensionDiscoverer = host.Services.GetService(); + + _ = extensionDiscoverer.FindExtension(extensionDirectoryName); + } } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json new file mode 100644 index 00000000000..ad42e3163b3 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json @@ -0,0 +1,9 @@ +{ + "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", + "Version": "1.0.0", + "Program": "dotnet-monitor-egress-azureblobstorage.exe", + "DisplayName": "AzureBlobStorage", + "SupportedExtensionTypes": [ + "Egress" + ] +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index d24a1a1d003..26342751e8e 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -114,6 +114,9 @@ Always + + Always + Always From 1b5ad1215340ec0060a0fcae936b9ddd1d8a58b8 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 7 Nov 2022 08:32:09 -0800 Subject: [PATCH 03/31] Expanded success case to check against other paths --- .../EgressExtensibilityTests.cs | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 8a1b4e9bf97..48493367428 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -7,12 +7,14 @@ using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text.Json; using Xunit; using Xunit.Abstractions; +using static Microsoft.Diagnostics.Monitoring.Tool.UnitTests.ConfigurationTests; namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests { @@ -63,23 +65,50 @@ public void FoundExtension_Failure() // This only verifies that the Extension.json file is found for the user's extension, // not that there is a suitable executable file. - [Fact] - public void FoundExtension_Success() + [Theory] + [InlineData(ConfigDirectory.UserConfigDirectory)] + [InlineData(ConfigDirectory.SharedConfigDirectory)] + //[InlineData(ConfigDirectory.DotnetToolsDirectory)] + //[InlineData(ConfigDirectory.NextToMeDirectory)] + public void FoundExtension_Success(ConfigDirectory configDirectory) { //const string extensionDisplayName = "AzureBlobStorage"; // This has to be the same as the display name within the Extension.json file const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; using TemporaryDirectory sharedConfigDir = new(_outputHelper); using TemporaryDirectory userConfigDir = new(_outputHelper); + using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); // Set up the initial settings used to create the host builder. HostBuilderSettings settings = new() { SharedConfigDirectory = sharedConfigDir.FullName, - UserConfigDirectory = userConfigDir.FullName + UserConfigDirectory = userConfigDir.FullName, + //DotnetToolsExtensionDirectory = dotnetToolsConfigDir }; - string destPath = Path.Combine(userConfigDir.FullName, ExtensionsFolder, extensionDirectoryName); + string directoryName = string.Empty; + + switch (configDirectory) + { + case ConfigDirectory.UserConfigDirectory: + directoryName = userConfigDir.FullName; + break; + case ConfigDirectory.SharedConfigDirectory: + directoryName = sharedConfigDir.FullName; + break; + case ConfigDirectory.DotnetToolsDirectory: + directoryName = dotnetToolsConfigDir.FullName; + break; + case ConfigDirectory.NextToMeDirectory: + //directoryName = .FullName; + // NOT HANDLING THIS YET + break; + default: + throw new Exception("Config Directory not found."); + } + + string destPath = Path.Combine(directoryName, ExtensionsFolder, extensionDirectoryName); Directory.CreateDirectory(destPath); @@ -92,5 +121,15 @@ public void FoundExtension_Success() _ = extensionDiscoverer.FindExtension(extensionDirectoryName); } + + /// This is the order of configuration sources where a name with a lower + /// enum value has a lower precedence in configuration. + public enum ConfigDirectory + { + NextToMeDirectory, + SharedConfigDirectory, + UserConfigDirectory, + DotnetToolsDirectory + } } } From fb7e3268f8f2c11269774d24e5f8ce6a6ab9aec2 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 7 Nov 2022 11:53:33 -0800 Subject: [PATCH 04/31] Added in test extension app; not being integrated yet. --- ...s.Monitoring.EgressExtensibilityApp.csproj | 19 +++ .../Program.cs | 108 ++++++++++++++++++ .../TestEgressProviderOptions.cs | 14 +++ .../EgressExtensibilityTests.cs | 20 +++- .../dotnet-monitor/dotnet-monitor.csproj | 1 + 5 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj new file mode 100644 index 00000000000..73eb8d81d74 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -0,0 +1,19 @@ + + + Exe + net6.0 + + + + + + + + + + + + + + + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs new file mode 100644 index 00000000000..8c1aa25b6e1 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Tools.Monitor.Egress; +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.IO; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp +{ + internal class Program + { + static async Task Main(string[] args) + { + // Expected command line format is: dotnet-monitor-egress-azureblobstorage.exe Egress + RootCommand rootCommand = new RootCommand("Egresses an artifact to Azure Storage."); + + Command egressCmd = new Command("Egress", "The class of extension being invoked; Egress is for egressing an artifact."); + + egressCmd.SetHandler(Egress); + + rootCommand.Add(egressCmd); + + return await rootCommand.InvokeAsync(args); + } + + private static async Task Egress() + { + EgressArtifactResult result = new(); + try + { + string jsonConfig = Console.ReadLine(); + ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); + + Stream outputStream = new MemoryStream(); // might not be a good stream type + + TimeSpan timeout = new TimeSpan(0, 0, 30); // Should do something real here + CancellationTokenSource timeoutSource = new(timeout); + + await GetStream(outputStream, timeoutSource.Token); + + Assert.NotEqual(outputStream.Length, 0); // could potentially check that it's the right length if we know it + + TestEgressProviderOptions options = BuildOptions(configPayload); + + if (options.ShouldSucceed) + { + result.Succeeded = true; + result.ArtifactPath = "/test/artifactPath"; // do something real here + } + else + { + result.Succeeded = false; + result.FailureMessage = "The egress operation failed."; // do something real here + } + } + catch (Exception ex) + { + result.Succeeded = false; + result.FailureMessage = ex.Message; + } + + string jsonBlob = JsonSerializer.Serialize(result); + Console.Write(jsonBlob); + + await Task.Delay(1); // TEMPORARY + + // return non-zero exit code when failed + return result.Succeeded ? 0 : 1; + } + + private static TestEgressProviderOptions BuildOptions(ExtensionEgressPayload configPayload) + { + TestEgressProviderOptions options = new TestEgressProviderOptions() + { + ShouldSucceed = GetConfig(configPayload.Configuration, nameof(TestEgressProviderOptions.ShouldSucceed)), + }; + + return options; + } + + private static async Task GetStream(Stream outputStream, CancellationToken cancellationToken) + { + const int DefaultBufferSize = 0x10000; + + await Console.OpenStandardInput().CopyToAsync(outputStream, DefaultBufferSize, cancellationToken); + } + + private static bool GetConfig(IDictionary configDict, string propKey) + { + if (configDict.ContainsKey(propKey)) + { + return bool.Parse(configDict[propKey]); + } + + // throw? + + return false; + } + } + +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs new file mode 100644 index 00000000000..ac0963a53fa --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp +{ + /// + /// Egress provider options for Azure blob storage. + /// + internal sealed partial class TestEgressProviderOptions + { + public bool ShouldSucceed { get; set; } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 48493367428..dedb3794171 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.TestCommon; using Microsoft.Diagnostics.Tools.Monitor; +using Microsoft.Diagnostics.Tools.Monitor.Egress; using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -12,6 +13,7 @@ using System.IO; using System.Reflection; using System.Text.Json; +using System.Threading; using Xunit; using Xunit.Abstractions; using static Microsoft.Diagnostics.Monitoring.Tool.UnitTests.ConfigurationTests; @@ -119,7 +121,23 @@ public void FoundExtension_Success(ConfigDirectory configDirectory) var extensionDiscoverer = host.Services.GetService(); - _ = extensionDiscoverer.FindExtension(extensionDirectoryName); + var extension = extensionDiscoverer.FindExtension(extensionDirectoryName); + + ExtensionEgressPayload payload = new() + { + }; + + TimeSpan timeout = new(0, 0, 30); // do something real + CancellationTokenSource tokenSource = new(timeout); + + extension.EgressArtifact(payload, null, tokenSource.Token); + } + + [Fact] + public static void ExtensionResponse_Success() + { + string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", TargetFrameworkMoniker.Net60); + } /// This is the order of configuration sources where a name with a lower diff --git a/src/Tools/dotnet-monitor/dotnet-monitor.csproj b/src/Tools/dotnet-monitor/dotnet-monitor.csproj index 26681e53083..2d601e3f4bd 100644 --- a/src/Tools/dotnet-monitor/dotnet-monitor.csproj +++ b/src/Tools/dotnet-monitor/dotnet-monitor.csproj @@ -44,6 +44,7 @@ + From 897592735cdd6c79953c2ccb3c0c046dcf50953c Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 8 Nov 2022 07:19:26 -0800 Subject: [PATCH 05/31] In progress --- ...ics.Monitoring.EgressExtensibilityApp.csproj | 6 ++++++ .../extension.json | 9 +++++++++ .../EgressExtensibilityTests.cs | 17 +++++++++++++---- .../EgressExtensionResources/extension.json | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj index 73eb8d81d74..7714a93eeb0 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -16,4 +16,10 @@ + + + Always + + + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json new file mode 100644 index 00000000000..5b1d377704c --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -0,0 +1,9 @@ +{ + "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", + "Version": "1.0.0", + "Program": "dotnet-monitor-egress-azureblobstorage.exe", + "Name": "AzureBlobStorage", + "SupportedExtensionTypes": [ + "Egress" + ] +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index dedb3794171..e4defb79ac2 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -9,14 +9,11 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; -using System.Collections.Generic; using System.IO; using System.Reflection; -using System.Text.Json; using System.Threading; using Xunit; using Xunit.Abstractions; -using static Microsoft.Diagnostics.Monitoring.Tool.UnitTests.ConfigurationTests; namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests { @@ -114,8 +111,20 @@ public void FoundExtension_Success(ConfigDirectory configDirectory) Directory.CreateDirectory(destPath); + string appName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + + string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), appName, TargetFrameworkMoniker.Net60); + File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath, ExtensionDefinitionFile)); + Path.Combine(destPath)); + + + /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), + Path.Combine(destPath, ExtensionDefinitionFile));*/ + + + File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), + destPath); // This won't work for special dotnet tools case IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json index ad42e3163b3..5b1d377704c 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json @@ -2,7 +2,7 @@ "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", "Version": "1.0.0", "Program": "dotnet-monitor-egress-azureblobstorage.exe", - "DisplayName": "AzureBlobStorage", + "Name": "AzureBlobStorage", "SupportedExtensionTypes": [ "Egress" ] From d4fd59e661cb7437e4f180a39820b7684e85def0 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 8 Nov 2022 14:54:46 -0800 Subject: [PATCH 06/31] Integration working with egress test app --- .../Program.cs | 17 +++-- .../extension.json | 2 +- .../EgressExtensibilityTests.cs | 68 ++++++++++++++----- .../Options/TestEgressProviderOptions.cs | 14 ++++ .../Extensibility/ProgramExtension.cs | 2 + 5 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index 8c1aa25b6e1..2514e4befbb 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -3,10 +3,12 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Tools.Monitor.Egress; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.CommandLine; using System.IO; +using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -16,6 +18,8 @@ namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp { internal class Program { + const int DefaultBufferSize = 4000; + static async Task Main(string[] args) { // Expected command line format is: dotnet-monitor-egress-azureblobstorage.exe Egress @@ -36,6 +40,7 @@ private static async Task Egress() try { string jsonConfig = Console.ReadLine(); + Console.WriteLine("JSONCONFIG: " + jsonConfig); ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); Stream outputStream = new MemoryStream(); // might not be a good stream type @@ -43,9 +48,9 @@ private static async Task Egress() TimeSpan timeout = new TimeSpan(0, 0, 30); // Should do something real here CancellationTokenSource timeoutSource = new(timeout); - await GetStream(outputStream, timeoutSource.Token); + outputStream = GetStream(); - Assert.NotEqual(outputStream.Length, 0); // could potentially check that it's the right length if we know it + Assert.Equal(outputStream.Length, DefaultBufferSize); TestEgressProviderOptions options = BuildOptions(configPayload); @@ -85,11 +90,13 @@ private static TestEgressProviderOptions BuildOptions(ExtensionEgressPayload con return options; } - private static async Task GetStream(Stream outputStream, CancellationToken cancellationToken) + private static Stream GetStream() { - const int DefaultBufferSize = 0x10000; + byte[] buffer = new byte[DefaultBufferSize]; + + Console.OpenStandardInput().Read(buffer, 0, DefaultBufferSize); - await Console.OpenStandardInput().CopyToAsync(outputStream, DefaultBufferSize, cancellationToken); + return new MemoryStream(buffer); } private static bool GetConfig(IDictionary configDict, string propKey) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json index 5b1d377704c..b04276a9410 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -1,7 +1,7 @@ { "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", "Version": "1.0.0", - "Program": "dotnet-monitor-egress-azureblobstorage.exe", + "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.exe", "Name": "AzureBlobStorage", "SupportedExtensionTypes": [ "Egress" diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index e4defb79ac2..02f68f22915 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -3,15 +3,23 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.TestCommon; +using Microsoft.Diagnostics.Monitoring.TestCommon.Options; using Microsoft.Diagnostics.Tools.Monitor; using Microsoft.Diagnostics.Tools.Monitor.Egress; using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; +using System.Collections.Generic; +using System.CommandLine.Parsing; using System.IO; +using System.Linq; using System.Reflection; +using System.Text; +using System.Text.Json; using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; using Xunit; using Xunit.Abstractions; @@ -21,8 +29,8 @@ public sealed class EgressExtensibilityTests { private ITestOutputHelper _outputHelper; private const string ExtensionsFolder = "extensions"; - private const string ExtensionDefinitionFile = "extension.json"; - private const string EgressExtensionsDirectory = "EgressExtensionResources"; + //private const string ExtensionDefinitionFile = "extension.json"; + //private const string EgressExtensionsDirectory = "EgressExtensionResources"; public EgressExtensibilityTests(ITestOutputHelper outputHelper) { @@ -69,10 +77,10 @@ public void FoundExtension_Failure() [InlineData(ConfigDirectory.SharedConfigDirectory)] //[InlineData(ConfigDirectory.DotnetToolsDirectory)] //[InlineData(ConfigDirectory.NextToMeDirectory)] - public void FoundExtension_Success(ConfigDirectory configDirectory) + public async Task FoundExtension_Success(ConfigDirectory configDirectory) { //const string extensionDisplayName = "AzureBlobStorage"; // This has to be the same as the display name within the Extension.json file - const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; + //const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; using TemporaryDirectory sharedConfigDir = new(_outputHelper); using TemporaryDirectory userConfigDir = new(_outputHelper); @@ -107,39 +115,57 @@ public void FoundExtension_Success(ConfigDirectory configDirectory) throw new Exception("Config Directory not found."); } - string destPath = Path.Combine(directoryName, ExtensionsFolder, extensionDirectoryName); + string appName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; - Directory.CreateDirectory(destPath); + string destPath = Path.Combine(directoryName, ExtensionsFolder, appName); - string appName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + Directory.CreateDirectory(destPath); string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), appName, TargetFrameworkMoniker.Net60); - File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath)); + string sourcePath = Path.GetDirectoryName(testAppPath); + + + //string sourcePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory); + + foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + { + string newFilePath = newPath.Replace(sourcePath, destPath); + string newDirPath = Path.GetDirectoryName(newFilePath); + + Directory.CreateDirectory(newDirPath); + + File.Copy(newPath, newFilePath, true); + } + + /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), + Path.Combine(destPath));*/ /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), Path.Combine(destPath, ExtensionDefinitionFile));*/ - File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), - destPath); // This won't work for special dotnet tools case + /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), + destPath); // This won't work for special dotnet tools case*/ IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); var extensionDiscoverer = host.Services.GetService(); - var extension = extensionDiscoverer.FindExtension(extensionDirectoryName); + var extension = extensionDiscoverer.FindExtension(appName); - ExtensionEgressPayload payload = new() - { - }; + ExtensionEgressPayload payload = new(); + + payload.Configuration = new Dictionary(); + payload.Configuration.Add("ShouldSucceed", "true"); TimeSpan timeout = new(0, 0, 30); // do something real CancellationTokenSource tokenSource = new(timeout); - extension.EgressArtifact(payload, null, tokenSource.Token); + var result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + + _outputHelper.WriteLine("Succeeded? " + result.Succeeded); } [Fact] @@ -149,6 +175,16 @@ public static void ExtensionResponse_Success() } + private static async Task GetStream(Stream stream, CancellationToken cancellationToken) + { + byte[] byteArray = Enumerable.Repeat((byte)0xDE, 2000).ToArray(); + + MemoryStream tempStream = new MemoryStream(byteArray); + + await tempStream.CopyToAsync(stream); + } + + /// This is the order of configuration sources where a name with a lower /// enum value has a lower precedence in configuration. public enum ConfigDirectory diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs new file mode 100644 index 00000000000..02540321690 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Diagnostics.Monitoring.TestCommon.Options +{ + /// + /// Egress provider options for Azure blob storage. + /// + internal sealed partial class TestEgressProviderOptions + { + public bool ShouldSucceed { get; set; } + } +} diff --git a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs index ad31de4d8bc..1b2f9e9c0d6 100644 --- a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs +++ b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs @@ -104,7 +104,9 @@ public async Task EgressArtifact(ExtensionEgressPayload co _logger.ExtensionConfigured(pStart.FileName, p.Id); await getStreamAction(p.StandardInput.BaseStream, token); + await p.StandardInput.WriteAsync(NewLine, token); await p.StandardInput.BaseStream.FlushAsync(token); + p.StandardInput.Close(); _logger.ExtensionEgressPayloadCompleted(p.Id); From a88ac6f18e70b663399984e243e7f39ff9476465 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Thu, 10 Nov 2022 07:46:13 -0800 Subject: [PATCH 07/31] Doing some refactoring --- ...s.Monitoring.EgressExtensibilityApp.csproj | 1 + .../Program.cs | 8 +- .../EgressExtensibilityTests.cs | 82 +++++++++++++------ 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj index 7714a93eeb0..900b546e03d 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index 2514e4befbb..0be1c3b8db1 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -2,13 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Diagnostics.Monitoring.Tool.UnitTests; using Microsoft.Diagnostics.Tools.Monitor.Egress; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.CommandLine; using System.IO; -using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -40,7 +39,6 @@ private static async Task Egress() try { string jsonConfig = Console.ReadLine(); - Console.WriteLine("JSONCONFIG: " + jsonConfig); ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); Stream outputStream = new MemoryStream(); // might not be a good stream type @@ -57,12 +55,12 @@ private static async Task Egress() if (options.ShouldSucceed) { result.Succeeded = true; - result.ArtifactPath = "/test/artifactPath"; // do something real here + result.ArtifactPath = EgressExtensibilityTests.SampleArtifactPath; } else { result.Succeeded = false; - result.FailureMessage = "The egress operation failed."; // do something real here + result.FailureMessage = EgressExtensibilityTests.SampleFailureMessage; } } catch (Exception ex) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 02f68f22915..bc68c2c9e51 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.TestCommon; -using Microsoft.Diagnostics.Monitoring.TestCommon.Options; using Microsoft.Diagnostics.Tools.Monitor; using Microsoft.Diagnostics.Tools.Monitor.Egress; using Microsoft.Diagnostics.Tools.Monitor.Extensibility; @@ -11,15 +10,11 @@ using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; -using System.CommandLine.Parsing; using System.IO; using System.Linq; using System.Reflection; -using System.Text; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using System.Xml.Linq; using Xunit; using Xunit.Abstractions; @@ -29,6 +24,10 @@ public sealed class EgressExtensibilityTests { private ITestOutputHelper _outputHelper; private const string ExtensionsFolder = "extensions"; + public const string SampleArtifactPath = "my/sample/path"; + public const string SampleFailureMessage = "the extension failed"; + private const string TestAppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + //private const string ExtensionDefinitionFile = "extension.json"; //private const string EgressExtensionsDirectory = "EgressExtensionResources"; @@ -125,9 +124,6 @@ public async Task FoundExtension_Success(ConfigDirectory configDirectory) string sourcePath = Path.GetDirectoryName(testAppPath); - - //string sourcePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory); - foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) { string newFilePath = newPath.Replace(sourcePath, destPath); @@ -138,17 +134,6 @@ public async Task FoundExtension_Success(ConfigDirectory configDirectory) File.Copy(newPath, newFilePath, true); } - /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath));*/ - - - /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath, ExtensionDefinitionFile));*/ - - - /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), - destPath); // This won't work for special dotnet tools case*/ - IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); var extensionDiscoverer = host.Services.GetService(); @@ -163,16 +148,47 @@ public async Task FoundExtension_Success(ConfigDirectory configDirectory) TimeSpan timeout = new(0, 0, 30); // do something real CancellationTokenSource tokenSource = new(timeout); - var result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); - _outputHelper.WriteLine("Succeeded? " + result.Succeeded); + Assert.True(result.Succeeded); + Assert.Equal(SampleArtifactPath, result.ArtifactPath); } [Fact] - public static void ExtensionResponse_Success() + public async Task ExtensionResponse_Success() { - string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", TargetFrameworkMoniker.Net60); + using TemporaryDirectory sharedConfigDir = new(_outputHelper); + using TemporaryDirectory userConfigDir = new(_outputHelper); + using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); + + // Set up the initial settings used to create the host builder. + HostBuilderSettings settings = new() + { + SharedConfigDirectory = sharedConfigDir.FullName, + UserConfigDirectory = userConfigDir.FullName, + //DotnetToolsExtensionDirectory = dotnetToolsConfigDir + }; + + CopyExtensionFiles(userConfigDir.FullName); + IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); + + var extensionDiscoverer = host.Services.GetService(); + + var extension = extensionDiscoverer.FindExtension(TestAppName); + + ExtensionEgressPayload payload = new(); + + payload.Configuration = new Dictionary(); + payload.Configuration.Add("ShouldSucceed", "true"); + + TimeSpan timeout = new(0, 0, 30); // do something real + CancellationTokenSource tokenSource = new(timeout); + + EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + + Assert.True(result.Succeeded); + Assert.Equal(SampleArtifactPath, result.ArtifactPath); } private static async Task GetStream(Stream stream, CancellationToken cancellationToken) @@ -184,6 +200,26 @@ private static async Task GetStream(Stream stream, CancellationToken cancellatio await tempStream.CopyToAsync(stream); } + private static void CopyExtensionFiles(string directoryName) + { + string destPath = Path.Combine(directoryName, ExtensionsFolder, TestAppName); + + Directory.CreateDirectory(destPath); + + string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), TestAppName, TargetFrameworkMoniker.Net60); // set this? + + string sourcePath = Path.GetDirectoryName(testAppPath); + + foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + { + string newFilePath = newPath.Replace(sourcePath, destPath); + string newDirPath = Path.GetDirectoryName(newFilePath); + + Directory.CreateDirectory(newDirPath); + + File.Copy(newPath, newFilePath, true); + } + } /// This is the order of configuration sources where a name with a lower /// enum value has a lower precedence in configuration. From ff131db497cf17989ea178208b9e321de63a0263 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Fri, 4 Nov 2022 13:20:16 -0700 Subject: [PATCH 08/31] Added in preliminary test that ensures the correct exception is thrown when the extension isn't found. --- .../EgressExtensibilityTests.cs | 57 +++++++++++++++++++ .../TestHostHelper.cs | 4 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs new file mode 100644 index 00000000000..0ed6a688021 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Monitoring.TestCommon; +using Microsoft.Diagnostics.Tools.Monitor; +using Microsoft.Diagnostics.Tools.Monitor.Extensibility; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests +{ + public sealed class EgressExtensibilityTests + { + private ITestOutputHelper _outputHelper; + + public EgressExtensibilityTests(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + } + + /* Test Coverage + * + * Successfully finding extension in each location + * Proper resolution if conflict in terms of priority + * Fails properly if extension is not found + * Extension.json file is properly found and parsed to find extension and DisplayName + * Fails properly if Extension.json is not found / doesn't contain correct contents + * Logs from extension are properly passed through to dotnet monitor + * + */ + + [Fact] + public void FoundExtension_Failure() + { + using TemporaryDirectory sharedConfigDir = new(_outputHelper); + using TemporaryDirectory userConfigDir = new(_outputHelper); + + // Set up the initial settings used to create the host builder. + HostBuilderSettings settings = new() + { + SharedConfigDirectory = sharedConfigDir.FullName, + UserConfigDirectory = userConfigDir.FullName + }; + + IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); + + var extensionDiscoverer = host.Services.GetService(); + + const string extensionDisplayName = "AzureBlobStorage"; + + Assert.Throws(() => extensionDiscoverer.FindExtension(extensionDisplayName)); + } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs index 1f8ef348e3d..aab7dc8ca38 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs @@ -62,7 +62,8 @@ public static IHost CreateHost( Action setup, Action servicesCallback, Action loggingCallback = null, - List overrideSource = null) + List overrideSource = null, + HostBuilderSettings settings = null) { return new HostBuilder() .ConfigureAppConfiguration(builder => @@ -100,6 +101,7 @@ public static IHost CreateHost( services.ConfigureTemplates(context.Configuration); services.AddSingleton(); services.ConfigureCollectionRules(); + services.ConfigureExtensions(settings); // settings could be null...how do we want to protect against this? services.ConfigureEgress(); services.ConfigureDiagnosticPort(context.Configuration); From cb4a9c091cd105594089b6d87ecc513f082f2c1b Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Fri, 4 Nov 2022 13:48:29 -0700 Subject: [PATCH 09/31] Added in basic test that checks that an extension.json file is found for the extension. Note that this currently uses the existing mechanism for checking against names (where the extension's name is the same as the way it's represented in configuration) - this will likely need to be tweaked when new changes go in. --- .../EgressExtensibilityTests.cs | 39 +++++++++++++++++++ .../EgressExtensionResources/extension.json | 9 +++++ ...agnostics.Monitoring.Tool.UnitTests.csproj | 3 ++ 3 files changed, 51 insertions(+) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 0ed6a688021..8a1b4e9bf97 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -7,6 +7,10 @@ using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.Json; using Xunit; using Xunit.Abstractions; @@ -15,6 +19,9 @@ namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests public sealed class EgressExtensibilityTests { private ITestOutputHelper _outputHelper; + private const string ExtensionsFolder = "extensions"; + private const string ExtensionDefinitionFile = "extension.json"; + private const string EgressExtensionsDirectory = "EgressExtensionResources"; public EgressExtensibilityTests(ITestOutputHelper outputHelper) { @@ -53,5 +60,37 @@ public void FoundExtension_Failure() Assert.Throws(() => extensionDiscoverer.FindExtension(extensionDisplayName)); } + + // This only verifies that the Extension.json file is found for the user's extension, + // not that there is a suitable executable file. + [Fact] + public void FoundExtension_Success() + { + //const string extensionDisplayName = "AzureBlobStorage"; // This has to be the same as the display name within the Extension.json file + const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; + + using TemporaryDirectory sharedConfigDir = new(_outputHelper); + using TemporaryDirectory userConfigDir = new(_outputHelper); + + // Set up the initial settings used to create the host builder. + HostBuilderSettings settings = new() + { + SharedConfigDirectory = sharedConfigDir.FullName, + UserConfigDirectory = userConfigDir.FullName + }; + + string destPath = Path.Combine(userConfigDir.FullName, ExtensionsFolder, extensionDirectoryName); + + Directory.CreateDirectory(destPath); + + File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), + Path.Combine(destPath, ExtensionDefinitionFile)); + + IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); + + var extensionDiscoverer = host.Services.GetService(); + + _ = extensionDiscoverer.FindExtension(extensionDirectoryName); + } } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json new file mode 100644 index 00000000000..ad42e3163b3 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json @@ -0,0 +1,9 @@ +{ + "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", + "Version": "1.0.0", + "Program": "dotnet-monitor-egress-azureblobstorage.exe", + "DisplayName": "AzureBlobStorage", + "SupportedExtensionTypes": [ + "Egress" + ] +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index d24a1a1d003..26342751e8e 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -114,6 +114,9 @@ Always + + Always + Always From 092d7648643a9b6882774fb39d856f59c425f256 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 7 Nov 2022 08:32:09 -0800 Subject: [PATCH 10/31] Expanded success case to check against other paths --- .../EgressExtensibilityTests.cs | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 8a1b4e9bf97..48493367428 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -7,12 +7,14 @@ using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text.Json; using Xunit; using Xunit.Abstractions; +using static Microsoft.Diagnostics.Monitoring.Tool.UnitTests.ConfigurationTests; namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests { @@ -63,23 +65,50 @@ public void FoundExtension_Failure() // This only verifies that the Extension.json file is found for the user's extension, // not that there is a suitable executable file. - [Fact] - public void FoundExtension_Success() + [Theory] + [InlineData(ConfigDirectory.UserConfigDirectory)] + [InlineData(ConfigDirectory.SharedConfigDirectory)] + //[InlineData(ConfigDirectory.DotnetToolsDirectory)] + //[InlineData(ConfigDirectory.NextToMeDirectory)] + public void FoundExtension_Success(ConfigDirectory configDirectory) { //const string extensionDisplayName = "AzureBlobStorage"; // This has to be the same as the display name within the Extension.json file const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; using TemporaryDirectory sharedConfigDir = new(_outputHelper); using TemporaryDirectory userConfigDir = new(_outputHelper); + using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); // Set up the initial settings used to create the host builder. HostBuilderSettings settings = new() { SharedConfigDirectory = sharedConfigDir.FullName, - UserConfigDirectory = userConfigDir.FullName + UserConfigDirectory = userConfigDir.FullName, + //DotnetToolsExtensionDirectory = dotnetToolsConfigDir }; - string destPath = Path.Combine(userConfigDir.FullName, ExtensionsFolder, extensionDirectoryName); + string directoryName = string.Empty; + + switch (configDirectory) + { + case ConfigDirectory.UserConfigDirectory: + directoryName = userConfigDir.FullName; + break; + case ConfigDirectory.SharedConfigDirectory: + directoryName = sharedConfigDir.FullName; + break; + case ConfigDirectory.DotnetToolsDirectory: + directoryName = dotnetToolsConfigDir.FullName; + break; + case ConfigDirectory.NextToMeDirectory: + //directoryName = .FullName; + // NOT HANDLING THIS YET + break; + default: + throw new Exception("Config Directory not found."); + } + + string destPath = Path.Combine(directoryName, ExtensionsFolder, extensionDirectoryName); Directory.CreateDirectory(destPath); @@ -92,5 +121,15 @@ public void FoundExtension_Success() _ = extensionDiscoverer.FindExtension(extensionDirectoryName); } + + /// This is the order of configuration sources where a name with a lower + /// enum value has a lower precedence in configuration. + public enum ConfigDirectory + { + NextToMeDirectory, + SharedConfigDirectory, + UserConfigDirectory, + DotnetToolsDirectory + } } } From e26eb36f6adbb17c19a923adf26cb97099cc8b9d Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 7 Nov 2022 11:53:33 -0800 Subject: [PATCH 11/31] Added in test extension app; not being integrated yet. --- ...s.Monitoring.EgressExtensibilityApp.csproj | 19 +++ .../Program.cs | 108 ++++++++++++++++++ .../TestEgressProviderOptions.cs | 14 +++ .../EgressExtensibilityTests.cs | 20 +++- .../dotnet-monitor/dotnet-monitor.csproj | 1 + 5 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj new file mode 100644 index 00000000000..73eb8d81d74 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -0,0 +1,19 @@ + + + Exe + net6.0 + + + + + + + + + + + + + + + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs new file mode 100644 index 00000000000..8c1aa25b6e1 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Tools.Monitor.Egress; +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.IO; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp +{ + internal class Program + { + static async Task Main(string[] args) + { + // Expected command line format is: dotnet-monitor-egress-azureblobstorage.exe Egress + RootCommand rootCommand = new RootCommand("Egresses an artifact to Azure Storage."); + + Command egressCmd = new Command("Egress", "The class of extension being invoked; Egress is for egressing an artifact."); + + egressCmd.SetHandler(Egress); + + rootCommand.Add(egressCmd); + + return await rootCommand.InvokeAsync(args); + } + + private static async Task Egress() + { + EgressArtifactResult result = new(); + try + { + string jsonConfig = Console.ReadLine(); + ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); + + Stream outputStream = new MemoryStream(); // might not be a good stream type + + TimeSpan timeout = new TimeSpan(0, 0, 30); // Should do something real here + CancellationTokenSource timeoutSource = new(timeout); + + await GetStream(outputStream, timeoutSource.Token); + + Assert.NotEqual(outputStream.Length, 0); // could potentially check that it's the right length if we know it + + TestEgressProviderOptions options = BuildOptions(configPayload); + + if (options.ShouldSucceed) + { + result.Succeeded = true; + result.ArtifactPath = "/test/artifactPath"; // do something real here + } + else + { + result.Succeeded = false; + result.FailureMessage = "The egress operation failed."; // do something real here + } + } + catch (Exception ex) + { + result.Succeeded = false; + result.FailureMessage = ex.Message; + } + + string jsonBlob = JsonSerializer.Serialize(result); + Console.Write(jsonBlob); + + await Task.Delay(1); // TEMPORARY + + // return non-zero exit code when failed + return result.Succeeded ? 0 : 1; + } + + private static TestEgressProviderOptions BuildOptions(ExtensionEgressPayload configPayload) + { + TestEgressProviderOptions options = new TestEgressProviderOptions() + { + ShouldSucceed = GetConfig(configPayload.Configuration, nameof(TestEgressProviderOptions.ShouldSucceed)), + }; + + return options; + } + + private static async Task GetStream(Stream outputStream, CancellationToken cancellationToken) + { + const int DefaultBufferSize = 0x10000; + + await Console.OpenStandardInput().CopyToAsync(outputStream, DefaultBufferSize, cancellationToken); + } + + private static bool GetConfig(IDictionary configDict, string propKey) + { + if (configDict.ContainsKey(propKey)) + { + return bool.Parse(configDict[propKey]); + } + + // throw? + + return false; + } + } + +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs new file mode 100644 index 00000000000..ac0963a53fa --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp +{ + /// + /// Egress provider options for Azure blob storage. + /// + internal sealed partial class TestEgressProviderOptions + { + public bool ShouldSucceed { get; set; } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 48493367428..dedb3794171 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.TestCommon; using Microsoft.Diagnostics.Tools.Monitor; +using Microsoft.Diagnostics.Tools.Monitor.Egress; using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -12,6 +13,7 @@ using System.IO; using System.Reflection; using System.Text.Json; +using System.Threading; using Xunit; using Xunit.Abstractions; using static Microsoft.Diagnostics.Monitoring.Tool.UnitTests.ConfigurationTests; @@ -119,7 +121,23 @@ public void FoundExtension_Success(ConfigDirectory configDirectory) var extensionDiscoverer = host.Services.GetService(); - _ = extensionDiscoverer.FindExtension(extensionDirectoryName); + var extension = extensionDiscoverer.FindExtension(extensionDirectoryName); + + ExtensionEgressPayload payload = new() + { + }; + + TimeSpan timeout = new(0, 0, 30); // do something real + CancellationTokenSource tokenSource = new(timeout); + + extension.EgressArtifact(payload, null, tokenSource.Token); + } + + [Fact] + public static void ExtensionResponse_Success() + { + string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", TargetFrameworkMoniker.Net60); + } /// This is the order of configuration sources where a name with a lower diff --git a/src/Tools/dotnet-monitor/dotnet-monitor.csproj b/src/Tools/dotnet-monitor/dotnet-monitor.csproj index 26681e53083..2d601e3f4bd 100644 --- a/src/Tools/dotnet-monitor/dotnet-monitor.csproj +++ b/src/Tools/dotnet-monitor/dotnet-monitor.csproj @@ -44,6 +44,7 @@ + From d77641052a8e48db8280a0380d366cf07f70f72b Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 8 Nov 2022 07:19:26 -0800 Subject: [PATCH 12/31] In progress --- ...ics.Monitoring.EgressExtensibilityApp.csproj | 6 ++++++ .../extension.json | 9 +++++++++ .../EgressExtensibilityTests.cs | 17 +++++++++++++---- .../EgressExtensionResources/extension.json | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj index 73eb8d81d74..7714a93eeb0 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -16,4 +16,10 @@ + + + Always + + + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json new file mode 100644 index 00000000000..5b1d377704c --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -0,0 +1,9 @@ +{ + "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", + "Version": "1.0.0", + "Program": "dotnet-monitor-egress-azureblobstorage.exe", + "Name": "AzureBlobStorage", + "SupportedExtensionTypes": [ + "Egress" + ] +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index dedb3794171..e4defb79ac2 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -9,14 +9,11 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; -using System.Collections.Generic; using System.IO; using System.Reflection; -using System.Text.Json; using System.Threading; using Xunit; using Xunit.Abstractions; -using static Microsoft.Diagnostics.Monitoring.Tool.UnitTests.ConfigurationTests; namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests { @@ -114,8 +111,20 @@ public void FoundExtension_Success(ConfigDirectory configDirectory) Directory.CreateDirectory(destPath); + string appName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + + string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), appName, TargetFrameworkMoniker.Net60); + File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath, ExtensionDefinitionFile)); + Path.Combine(destPath)); + + + /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), + Path.Combine(destPath, ExtensionDefinitionFile));*/ + + + File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), + destPath); // This won't work for special dotnet tools case IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json index ad42e3163b3..5b1d377704c 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json @@ -2,7 +2,7 @@ "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", "Version": "1.0.0", "Program": "dotnet-monitor-egress-azureblobstorage.exe", - "DisplayName": "AzureBlobStorage", + "Name": "AzureBlobStorage", "SupportedExtensionTypes": [ "Egress" ] From fd3566a953bd06260aaae8956bdf4a494d042783 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 8 Nov 2022 14:54:46 -0800 Subject: [PATCH 13/31] Integration working with egress test app --- .../Program.cs | 17 +++-- .../extension.json | 2 +- .../EgressExtensibilityTests.cs | 68 ++++++++++++++----- .../Options/TestEgressProviderOptions.cs | 14 ++++ .../Extensibility/ProgramExtension.cs | 2 + 5 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index 8c1aa25b6e1..2514e4befbb 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -3,10 +3,12 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Tools.Monitor.Egress; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.CommandLine; using System.IO; +using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -16,6 +18,8 @@ namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp { internal class Program { + const int DefaultBufferSize = 4000; + static async Task Main(string[] args) { // Expected command line format is: dotnet-monitor-egress-azureblobstorage.exe Egress @@ -36,6 +40,7 @@ private static async Task Egress() try { string jsonConfig = Console.ReadLine(); + Console.WriteLine("JSONCONFIG: " + jsonConfig); ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); Stream outputStream = new MemoryStream(); // might not be a good stream type @@ -43,9 +48,9 @@ private static async Task Egress() TimeSpan timeout = new TimeSpan(0, 0, 30); // Should do something real here CancellationTokenSource timeoutSource = new(timeout); - await GetStream(outputStream, timeoutSource.Token); + outputStream = GetStream(); - Assert.NotEqual(outputStream.Length, 0); // could potentially check that it's the right length if we know it + Assert.Equal(outputStream.Length, DefaultBufferSize); TestEgressProviderOptions options = BuildOptions(configPayload); @@ -85,11 +90,13 @@ private static TestEgressProviderOptions BuildOptions(ExtensionEgressPayload con return options; } - private static async Task GetStream(Stream outputStream, CancellationToken cancellationToken) + private static Stream GetStream() { - const int DefaultBufferSize = 0x10000; + byte[] buffer = new byte[DefaultBufferSize]; + + Console.OpenStandardInput().Read(buffer, 0, DefaultBufferSize); - await Console.OpenStandardInput().CopyToAsync(outputStream, DefaultBufferSize, cancellationToken); + return new MemoryStream(buffer); } private static bool GetConfig(IDictionary configDict, string propKey) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json index 5b1d377704c..b04276a9410 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -1,7 +1,7 @@ { "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", "Version": "1.0.0", - "Program": "dotnet-monitor-egress-azureblobstorage.exe", + "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.exe", "Name": "AzureBlobStorage", "SupportedExtensionTypes": [ "Egress" diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index e4defb79ac2..02f68f22915 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -3,15 +3,23 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.TestCommon; +using Microsoft.Diagnostics.Monitoring.TestCommon.Options; using Microsoft.Diagnostics.Tools.Monitor; using Microsoft.Diagnostics.Tools.Monitor.Egress; using Microsoft.Diagnostics.Tools.Monitor.Extensibility; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; +using System.Collections.Generic; +using System.CommandLine.Parsing; using System.IO; +using System.Linq; using System.Reflection; +using System.Text; +using System.Text.Json; using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; using Xunit; using Xunit.Abstractions; @@ -21,8 +29,8 @@ public sealed class EgressExtensibilityTests { private ITestOutputHelper _outputHelper; private const string ExtensionsFolder = "extensions"; - private const string ExtensionDefinitionFile = "extension.json"; - private const string EgressExtensionsDirectory = "EgressExtensionResources"; + //private const string ExtensionDefinitionFile = "extension.json"; + //private const string EgressExtensionsDirectory = "EgressExtensionResources"; public EgressExtensibilityTests(ITestOutputHelper outputHelper) { @@ -69,10 +77,10 @@ public void FoundExtension_Failure() [InlineData(ConfigDirectory.SharedConfigDirectory)] //[InlineData(ConfigDirectory.DotnetToolsDirectory)] //[InlineData(ConfigDirectory.NextToMeDirectory)] - public void FoundExtension_Success(ConfigDirectory configDirectory) + public async Task FoundExtension_Success(ConfigDirectory configDirectory) { //const string extensionDisplayName = "AzureBlobStorage"; // This has to be the same as the display name within the Extension.json file - const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; + //const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; using TemporaryDirectory sharedConfigDir = new(_outputHelper); using TemporaryDirectory userConfigDir = new(_outputHelper); @@ -107,39 +115,57 @@ public void FoundExtension_Success(ConfigDirectory configDirectory) throw new Exception("Config Directory not found."); } - string destPath = Path.Combine(directoryName, ExtensionsFolder, extensionDirectoryName); + string appName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; - Directory.CreateDirectory(destPath); + string destPath = Path.Combine(directoryName, ExtensionsFolder, appName); - string appName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + Directory.CreateDirectory(destPath); string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), appName, TargetFrameworkMoniker.Net60); - File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath)); + string sourcePath = Path.GetDirectoryName(testAppPath); + + + //string sourcePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory); + + foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + { + string newFilePath = newPath.Replace(sourcePath, destPath); + string newDirPath = Path.GetDirectoryName(newFilePath); + + Directory.CreateDirectory(newDirPath); + + File.Copy(newPath, newFilePath, true); + } + + /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), + Path.Combine(destPath));*/ /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), Path.Combine(destPath, ExtensionDefinitionFile));*/ - File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), - destPath); // This won't work for special dotnet tools case + /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), + destPath); // This won't work for special dotnet tools case*/ IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); var extensionDiscoverer = host.Services.GetService(); - var extension = extensionDiscoverer.FindExtension(extensionDirectoryName); + var extension = extensionDiscoverer.FindExtension(appName); - ExtensionEgressPayload payload = new() - { - }; + ExtensionEgressPayload payload = new(); + + payload.Configuration = new Dictionary(); + payload.Configuration.Add("ShouldSucceed", "true"); TimeSpan timeout = new(0, 0, 30); // do something real CancellationTokenSource tokenSource = new(timeout); - extension.EgressArtifact(payload, null, tokenSource.Token); + var result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + + _outputHelper.WriteLine("Succeeded? " + result.Succeeded); } [Fact] @@ -149,6 +175,16 @@ public static void ExtensionResponse_Success() } + private static async Task GetStream(Stream stream, CancellationToken cancellationToken) + { + byte[] byteArray = Enumerable.Repeat((byte)0xDE, 2000).ToArray(); + + MemoryStream tempStream = new MemoryStream(byteArray); + + await tempStream.CopyToAsync(stream); + } + + /// This is the order of configuration sources where a name with a lower /// enum value has a lower precedence in configuration. public enum ConfigDirectory diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs new file mode 100644 index 00000000000..02540321690 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Diagnostics.Monitoring.TestCommon.Options +{ + /// + /// Egress provider options for Azure blob storage. + /// + internal sealed partial class TestEgressProviderOptions + { + public bool ShouldSucceed { get; set; } + } +} diff --git a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs index 3c1f7165c66..db4579dde41 100644 --- a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs +++ b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs @@ -112,7 +112,9 @@ public async Task EgressArtifact(ExtensionEgressPayload co _logger.ExtensionConfigured(pStart.FileName, p.Id); await getStreamAction(p.StandardInput.BaseStream, token); + await p.StandardInput.WriteAsync(NewLine, token); await p.StandardInput.BaseStream.FlushAsync(token); + p.StandardInput.Close(); _logger.ExtensionEgressPayloadCompleted(p.Id); From 740f9919b19df2f4a62e3681782fa253b57bb60d Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Thu, 10 Nov 2022 07:46:13 -0800 Subject: [PATCH 14/31] Doing some refactoring --- ...s.Monitoring.EgressExtensibilityApp.csproj | 1 + .../Program.cs | 8 +- .../EgressExtensibilityTests.cs | 82 +++++++++++++------ 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj index 7714a93eeb0..900b546e03d 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index 2514e4befbb..0be1c3b8db1 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -2,13 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Diagnostics.Monitoring.Tool.UnitTests; using Microsoft.Diagnostics.Tools.Monitor.Egress; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.CommandLine; using System.IO; -using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -40,7 +39,6 @@ private static async Task Egress() try { string jsonConfig = Console.ReadLine(); - Console.WriteLine("JSONCONFIG: " + jsonConfig); ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); Stream outputStream = new MemoryStream(); // might not be a good stream type @@ -57,12 +55,12 @@ private static async Task Egress() if (options.ShouldSucceed) { result.Succeeded = true; - result.ArtifactPath = "/test/artifactPath"; // do something real here + result.ArtifactPath = EgressExtensibilityTests.SampleArtifactPath; } else { result.Succeeded = false; - result.FailureMessage = "The egress operation failed."; // do something real here + result.FailureMessage = EgressExtensibilityTests.SampleFailureMessage; } } catch (Exception ex) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 02f68f22915..bc68c2c9e51 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.TestCommon; -using Microsoft.Diagnostics.Monitoring.TestCommon.Options; using Microsoft.Diagnostics.Tools.Monitor; using Microsoft.Diagnostics.Tools.Monitor.Egress; using Microsoft.Diagnostics.Tools.Monitor.Extensibility; @@ -11,15 +10,11 @@ using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; -using System.CommandLine.Parsing; using System.IO; using System.Linq; using System.Reflection; -using System.Text; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using System.Xml.Linq; using Xunit; using Xunit.Abstractions; @@ -29,6 +24,10 @@ public sealed class EgressExtensibilityTests { private ITestOutputHelper _outputHelper; private const string ExtensionsFolder = "extensions"; + public const string SampleArtifactPath = "my/sample/path"; + public const string SampleFailureMessage = "the extension failed"; + private const string TestAppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + //private const string ExtensionDefinitionFile = "extension.json"; //private const string EgressExtensionsDirectory = "EgressExtensionResources"; @@ -125,9 +124,6 @@ public async Task FoundExtension_Success(ConfigDirectory configDirectory) string sourcePath = Path.GetDirectoryName(testAppPath); - - //string sourcePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory); - foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) { string newFilePath = newPath.Replace(sourcePath, destPath); @@ -138,17 +134,6 @@ public async Task FoundExtension_Success(ConfigDirectory configDirectory) File.Copy(newPath, newFilePath, true); } - /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath));*/ - - - /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory, ExtensionDefinitionFile), - Path.Combine(destPath, ExtensionDefinitionFile));*/ - - - /*File.Copy(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), EgressExtensionsDirectory), - destPath); // This won't work for special dotnet tools case*/ - IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); var extensionDiscoverer = host.Services.GetService(); @@ -163,16 +148,47 @@ public async Task FoundExtension_Success(ConfigDirectory configDirectory) TimeSpan timeout = new(0, 0, 30); // do something real CancellationTokenSource tokenSource = new(timeout); - var result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); - _outputHelper.WriteLine("Succeeded? " + result.Succeeded); + Assert.True(result.Succeeded); + Assert.Equal(SampleArtifactPath, result.ArtifactPath); } [Fact] - public static void ExtensionResponse_Success() + public async Task ExtensionResponse_Success() { - string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", TargetFrameworkMoniker.Net60); + using TemporaryDirectory sharedConfigDir = new(_outputHelper); + using TemporaryDirectory userConfigDir = new(_outputHelper); + using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); + + // Set up the initial settings used to create the host builder. + HostBuilderSettings settings = new() + { + SharedConfigDirectory = sharedConfigDir.FullName, + UserConfigDirectory = userConfigDir.FullName, + //DotnetToolsExtensionDirectory = dotnetToolsConfigDir + }; + + CopyExtensionFiles(userConfigDir.FullName); + IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); + + var extensionDiscoverer = host.Services.GetService(); + + var extension = extensionDiscoverer.FindExtension(TestAppName); + + ExtensionEgressPayload payload = new(); + + payload.Configuration = new Dictionary(); + payload.Configuration.Add("ShouldSucceed", "true"); + + TimeSpan timeout = new(0, 0, 30); // do something real + CancellationTokenSource tokenSource = new(timeout); + + EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + + Assert.True(result.Succeeded); + Assert.Equal(SampleArtifactPath, result.ArtifactPath); } private static async Task GetStream(Stream stream, CancellationToken cancellationToken) @@ -184,6 +200,26 @@ private static async Task GetStream(Stream stream, CancellationToken cancellatio await tempStream.CopyToAsync(stream); } + private static void CopyExtensionFiles(string directoryName) + { + string destPath = Path.Combine(directoryName, ExtensionsFolder, TestAppName); + + Directory.CreateDirectory(destPath); + + string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), TestAppName, TargetFrameworkMoniker.Net60); // set this? + + string sourcePath = Path.GetDirectoryName(testAppPath); + + foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + { + string newFilePath = newPath.Replace(sourcePath, destPath); + string newDirPath = Path.GetDirectoryName(newFilePath); + + Directory.CreateDirectory(newDirPath); + + File.Copy(newPath, newFilePath, true); + } + } /// This is the order of configuration sources where a name with a lower /// enum value has a lower precedence in configuration. From a003ad475d7768ff8e8e21e0e98340344f0653ea Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Fri, 18 Nov 2022 08:32:57 -0800 Subject: [PATCH 15/31] Updated testing to work with latest changes --- .../extension.json | 2 +- .../Runners/MonitorRunner.cs | 6 + .../EgressExtensibilityTests.cs | 132 +++++++----------- .../Extensibility/ToolsExtensionRepository.cs | 11 -- .../HostBuilder/HostBuilderSettings.cs | 22 ++- .../ServiceCollectionExtensions.cs | 2 +- 6 files changed, 80 insertions(+), 95 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json index b04276a9410..934ca77c989 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -2,7 +2,7 @@ "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", "Version": "1.0.0", "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.exe", - "Name": "AzureBlobStorage", + "Name": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", "SupportedExtensionTypes": [ "Egress" ] diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs index 7322f0c0bbf..0d933f6b8ef 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs @@ -81,6 +81,9 @@ internal class MonitorRunner : IAsyncDisposable private string UserConfigDirectoryPath => Path.Combine(TempPath, "UserConfig"); + private string DotnetToolsExtensionDirectoryPath => + Path.Combine(TempPath, "DotnetToolsExtension"); + private string UserSettingsFilePath => Path.Combine(UserConfigDirectoryPath, "settings.json"); @@ -96,6 +99,7 @@ public MonitorRunner(ITestOutputHelper outputHelper) Directory.CreateDirectory(SharedConfigDirectoryPath); Directory.CreateDirectory(UserConfigDirectoryPath); + Directory.CreateDirectory(DotnetToolsExtensionDirectoryPath); } public virtual async ValueTask DisposeAsync() @@ -154,6 +158,8 @@ public virtual async Task StartAsync(string command, string[] args, Cancellation _adapter.Environment.Add("DotnetMonitorTestSettings__SharedConfigDirectoryOverride", SharedConfigDirectoryPath); // Override the user config directory _adapter.Environment.Add("DotnetMonitorTestSettings__UserConfigDirectoryOverride", UserConfigDirectoryPath); + // Override the dotnet tools extension directory + _adapter.Environment.Add("DotnetMonitorTestSettings__DotnetToolsExtensionDirectoryOverride", DotnetToolsExtensionDirectoryPath); // Enable experimental stacks feature if (EnableCallStacksFeature) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index bc68c2c9e51..ebc1de81630 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -52,12 +52,14 @@ public void FoundExtension_Failure() { using TemporaryDirectory sharedConfigDir = new(_outputHelper); using TemporaryDirectory userConfigDir = new(_outputHelper); + using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); // Set up the initial settings used to create the host builder. HostBuilderSettings settings = new() { SharedConfigDirectory = sharedConfigDir.FullName, - UserConfigDirectory = userConfigDir.FullName + UserConfigDirectory = userConfigDir.FullName, + DotnetToolsExtensionDirectory = dotnetToolsConfigDir.FullName }; IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); @@ -76,100 +78,32 @@ public void FoundExtension_Failure() [InlineData(ConfigDirectory.SharedConfigDirectory)] //[InlineData(ConfigDirectory.DotnetToolsDirectory)] //[InlineData(ConfigDirectory.NextToMeDirectory)] - public async Task FoundExtension_Success(ConfigDirectory configDirectory) + public void FoundExtension_Success(ConfigDirectory configDirectory) { - //const string extensionDisplayName = "AzureBlobStorage"; // This has to be the same as the display name within the Extension.json file - //const string extensionDirectoryName = "dotnet-monitor-egress-azureblobstorage"; + HostBuilderSettings settings = CreateHostBuilderSettings(); - using TemporaryDirectory sharedConfigDir = new(_outputHelper); - using TemporaryDirectory userConfigDir = new(_outputHelper); - using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); + string directoryName = GetExtensionDirectoryName(settings, configDirectory); - // Set up the initial settings used to create the host builder. - HostBuilderSettings settings = new() - { - SharedConfigDirectory = sharedConfigDir.FullName, - UserConfigDirectory = userConfigDir.FullName, - //DotnetToolsExtensionDirectory = dotnetToolsConfigDir - }; - - string directoryName = string.Empty; - - switch (configDirectory) - { - case ConfigDirectory.UserConfigDirectory: - directoryName = userConfigDir.FullName; - break; - case ConfigDirectory.SharedConfigDirectory: - directoryName = sharedConfigDir.FullName; - break; - case ConfigDirectory.DotnetToolsDirectory: - directoryName = dotnetToolsConfigDir.FullName; - break; - case ConfigDirectory.NextToMeDirectory: - //directoryName = .FullName; - // NOT HANDLING THIS YET - break; - default: - throw new Exception("Config Directory not found."); - } - - string appName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; - - string destPath = Path.Combine(directoryName, ExtensionsFolder, appName); - - Directory.CreateDirectory(destPath); - - string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), appName, TargetFrameworkMoniker.Net60); - - string sourcePath = Path.GetDirectoryName(testAppPath); - - foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) - { - string newFilePath = newPath.Replace(sourcePath, destPath); - string newDirPath = Path.GetDirectoryName(newFilePath); - - Directory.CreateDirectory(newDirPath); - - File.Copy(newPath, newFilePath, true); - } + CopyExtensionFiles(directoryName); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); var extensionDiscoverer = host.Services.GetService(); - var extension = extensionDiscoverer.FindExtension(appName); - - ExtensionEgressPayload payload = new(); - - payload.Configuration = new Dictionary(); - payload.Configuration.Add("ShouldSucceed", "true"); - - TimeSpan timeout = new(0, 0, 30); // do something real - CancellationTokenSource tokenSource = new(timeout); - - EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + var extension = extensionDiscoverer.FindExtension(TestAppName); - Assert.True(result.Succeeded); - Assert.Equal(SampleArtifactPath, result.ArtifactPath); + Assert.NotNull(extension); } - [Fact] - public async Task ExtensionResponse_Success() + [Theory] + [InlineData(ConfigDirectory.UserConfigDirectory)] + public async Task ExtensionResponse_Success(ConfigDirectory configDirectory) { - using TemporaryDirectory sharedConfigDir = new(_outputHelper); - using TemporaryDirectory userConfigDir = new(_outputHelper); - using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); + HostBuilderSettings settings = CreateHostBuilderSettings(); - // Set up the initial settings used to create the host builder. - HostBuilderSettings settings = new() - { - SharedConfigDirectory = sharedConfigDir.FullName, - UserConfigDirectory = userConfigDir.FullName, - //DotnetToolsExtensionDirectory = dotnetToolsConfigDir - }; + string directoryName = GetExtensionDirectoryName(settings, configDirectory); - CopyExtensionFiles(userConfigDir.FullName); + CopyExtensionFiles(directoryName); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); @@ -221,6 +155,42 @@ private static void CopyExtensionFiles(string directoryName) } } + private HostBuilderSettings CreateHostBuilderSettings() + { + using TemporaryDirectory sharedConfigDir = new(_outputHelper); + using TemporaryDirectory userConfigDir = new(_outputHelper); + using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); + + // Set up the initial settings used to create the host builder. + return new() + { + SharedConfigDirectory = sharedConfigDir.FullName, + UserConfigDirectory = userConfigDir.FullName, + DotnetToolsExtensionDirectory = dotnetToolsConfigDir.FullName + }; + } + + private string GetExtensionDirectoryName(HostBuilderSettings settings, ConfigDirectory configDirectory) + { + switch (configDirectory) + { + case ConfigDirectory.UserConfigDirectory: + return settings.UserConfigDirectory; + case ConfigDirectory.SharedConfigDirectory: + return settings.SharedConfigDirectory; + case ConfigDirectory.DotnetToolsDirectory: + return settings.DotnetToolsExtensionDirectory; + case ConfigDirectory.NextToMeDirectory: + //directoryName = .FullName; + // NOT HANDLING THIS YET + break; + default: + throw new Exception("Config Directory not found."); + } + + return null; + } + /// This is the order of configuration sources where a name with a lower /// enum value has a lower precedence in configuration. public enum ConfigDirectory diff --git a/src/Tools/dotnet-monitor/Extensibility/ToolsExtensionRepository.cs b/src/Tools/dotnet-monitor/Extensibility/ToolsExtensionRepository.cs index 7ba880284bf..81d85f59dde 100644 --- a/src/Tools/dotnet-monitor/Extensibility/ToolsExtensionRepository.cs +++ b/src/Tools/dotnet-monitor/Extensibility/ToolsExtensionRepository.cs @@ -18,17 +18,6 @@ internal class ToolsExtensionRepository : ExtensionRepository private readonly IFileProvider _fileSystem; private readonly ILogger _logger; - private const string DotnetFolderName = "dotnet"; - private const string ToolsFolderName = "tools"; - - // Location where extensions are stored by default. - // Windows: "%USERPROFILE%\.dotnet\Tools" - // Other: "%XDG_CONFIG_HOME%/.dotnet/tools" OR "%HOME%/.dotnet/tools" -> THIS HAS NOT BEEN TESTED YET ON LINUX - public static readonly string DotnetToolsExtensionDirectoryPath = - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "." + DotnetFolderName, ToolsFolderName) : - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "." + DotnetFolderName, ToolsFolderName); - public ToolsExtensionRepository(IFileProvider fileSystem, ILogger logger, string targetFolder) : base(string.Format(CultureInfo.CurrentCulture, Strings.Message_FolderExtensionRepoName, targetFolder)) { diff --git a/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs b/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs index f56d4deee5e..359dbc4faf9 100644 --- a/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs +++ b/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs @@ -11,6 +11,8 @@ namespace Microsoft.Diagnostics.Tools.Monitor internal sealed class HostBuilderSettings { private const string ProductFolderName = "dotnet-monitor"; + private const string DotnetFolderName = "dotnet"; + private const string ToolsFolderName = "tools"; // Allows tests to override the shared configuration directory so there // is better control and access of what is visible during test. @@ -22,6 +24,11 @@ private const string SharedConfigDirectoryOverrideEnvironmentVariable private const string UserConfigDirectoryOverrideEnvironmentVariable = "DotnetMonitorTestSettings__UserConfigDirectoryOverride"; + // Allows tests to override the user configuration directory so there + // is better control and access of what is visible during test. + private const string DotnetToolsExtensionDirectoryOverrideEnvironmentVariable + = "DotnetMonitorTestSettings__DotnetToolsExtensionDirectoryOverride"; + // Location where shared dotnet-monitor configuration is stored. // Windows: "%ProgramData%\dotnet-monitor // Other: /etc/dotnet-monitor @@ -42,6 +49,16 @@ private const string UserConfigDirectoryOverrideEnvironmentVariable Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "." + ProductFolderName) : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ProductFolderName)); + // Location where extensions are stored by default. + // Windows: "%USERPROFILE%\.dotnet\Tools" + // Other: "%XDG_CONFIG_HOME%/.dotnet/tools" OR "%HOME%/.dotnet/tools" -> THIS HAS NOT BEEN TESTED YET ON LINUX + public static readonly string DotnetToolsExtensionDirectoryPath = + GetEnvironmentOverrideOrValue( + DotnetToolsExtensionDirectoryOverrideEnvironmentVariable, + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "." + DotnetFolderName, ToolsFolderName) : + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "." + DotnetFolderName, ToolsFolderName)); + public string[] Urls { get; set; } public string[] MetricsUrls { get; set; } @@ -58,6 +75,8 @@ private const string UserConfigDirectoryOverrideEnvironmentVariable public string UserConfigDirectory { get; set; } + public string DotnetToolsExtensionDirectory { get; set; } + public FileInfo UserProvidedConfigFilePath { get; set; } /// @@ -81,7 +100,8 @@ public static HostBuilderSettings CreateMonitor( ContentRootDirectory = AppContext.BaseDirectory, SharedConfigDirectory = SharedConfigDirectoryPath, UserConfigDirectory = UserConfigDirectoryPath, - UserProvidedConfigFilePath = userProvidedConfigFilePath + UserProvidedConfigFilePath = userProvidedConfigFilePath, + DotnetToolsExtensionDirectory = DotnetToolsExtensionDirectoryPath }; } diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index c160654d08f..3461cba7cdd 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -220,7 +220,7 @@ public static IServiceCollection ConfigureExtensions(this IServiceCollection ser string nextToMeFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string progDataFolder = settings.SharedConfigDirectory; string settingsFolder = settings.UserConfigDirectory; - string dotnetToolsFolder = ToolsExtensionRepository.DotnetToolsExtensionDirectoryPath; + string dotnetToolsFolder = settings.DotnetToolsExtensionDirectory; if (string.IsNullOrWhiteSpace(progDataFolder) || string.IsNullOrWhiteSpace(settingsFolder) From 773c4ca56b6bd49b00f9c6eb07181af6280d11ef Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 22 Nov 2022 11:45:24 -0800 Subject: [PATCH 16/31] Fixes for tests --- .../EgressExtensibilityTests.cs | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 51242574a48..c75fbc3f820 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -27,6 +27,9 @@ public sealed class EgressExtensibilityTests public const string SampleArtifactPath = "my/sample/path"; public const string SampleFailureMessage = "the extension failed"; private const string TestAppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + private const string TestAppExe = TestAppName + ".exe"; + private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; + private const string DotnetToolsExeDir = ""; //private const string ExtensionDefinitionFile = "extension.json"; //private const string EgressExtensionsDirectory = "EgressExtensionResources"; @@ -61,20 +64,19 @@ public void FoundExtension_Failure() Assert.Throws(() => extensionDiscoverer.FindExtension(extensionDisplayName)); } - // This only verifies that the Extension.json file is found for the user's extension, - // not that there is a suitable executable file. [Theory] - [InlineData(ConfigDirectory.UserConfigDirectory)] - [InlineData(ConfigDirectory.SharedConfigDirectory)] - //[InlineData(ConfigDirectory.DotnetToolsDirectory)] - //[InlineData(ConfigDirectory.NextToMeDirectory)] - public void FoundExtension_Success(ConfigDirectory configDirectory) + [InlineData(ConfigDirectory.UserConfigDirectory, null, null)] + [InlineData(ConfigDirectory.SharedConfigDirectory, null, null)] + [InlineData(ConfigDirectory.DotnetToolsDirectory, DotnetToolsExeDir, TestAppExe)] + public void FoundExtensionFile_Success(ConfigDirectory configDirectory, string exePath, string exeName) { HostBuilderSettings settings = CreateHostBuilderSettings(); string directoryName = GetExtensionDirectoryName(settings, configDirectory); - CopyExtensionFiles(directoryName); + string destinationPath = configDirectory != ConfigDirectory.DotnetToolsDirectory ? Path.Combine(directoryName, ExtensionsFolder, TestAppName) : Path.Combine(directoryName, DotnetToolsExtensionDir); + + CopyExtensionFiles(directoryName, destinationPath, exePath, exeName); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); @@ -93,7 +95,9 @@ public async Task ExtensionResponse_Success(ConfigDirectory configDirectory) string directoryName = GetExtensionDirectoryName(settings, configDirectory); - CopyExtensionFiles(directoryName); + string destinationPath = Path.Combine(directoryName, ExtensionsFolder, TestAppName); + + CopyExtensionFiles(directoryName, destinationPath); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); @@ -124,24 +128,33 @@ private static async Task GetStream(Stream stream, CancellationToken cancellatio await tempStream.CopyToAsync(stream); } - private static void CopyExtensionFiles(string directoryName) + private static void CopyExtensionFiles(string directoryName, string destinationPath, string exePath = null, string exeName = null) { - string destPath = Path.Combine(directoryName, ExtensionsFolder, TestAppName); + Directory.CreateDirectory(destinationPath); - Directory.CreateDirectory(destPath); + bool separateExe = HasSeparateExe(exePath, exeName); + if (separateExe) + { + Directory.CreateDirectory(exePath); + } string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), TestAppName, TargetFrameworkMoniker.Net60); // set this? string sourcePath = Path.GetDirectoryName(testAppPath); - foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + foreach (string sourceFilePath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) { - string newFilePath = newPath.Replace(sourcePath, destPath); - string newDirPath = Path.GetDirectoryName(newFilePath); + string fileName = Path.GetFileName(sourceFilePath); + + string replacementPath = separateExe && fileName == exeName ? exePath : destinationPath; - Directory.CreateDirectory(newDirPath); + string destinationFilePath = sourceFilePath.Replace(sourcePath, replacementPath); - File.Copy(newPath, newFilePath, true); + string destinationDirPath = Path.GetDirectoryName(destinationFilePath); + + Directory.CreateDirectory(destinationDirPath); + + File.Copy(sourceFilePath, destinationFilePath, true); } } @@ -160,6 +173,11 @@ private HostBuilderSettings CreateHostBuilderSettings() }; } + private static bool HasSeparateExe(string directory, string exe) + { + return !string.IsNullOrEmpty(directory) && !string.IsNullOrEmpty(exe); + } + private string GetExtensionDirectoryName(HostBuilderSettings settings, ConfigDirectory configDirectory) { switch (configDirectory) From 63a444988f01a5a77e5ffdd65f9ee7bb42941ee9 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 22 Nov 2022 13:42:13 -0800 Subject: [PATCH 17/31] More testing work --- .../Program.cs | 17 +++++++ .../EgressExtensibilityTests.cs | 47 ++++++++----------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index 0be1c3b8db1..9478f72ed02 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.Tool.UnitTests; using Microsoft.Diagnostics.Tools.Monitor.Egress; +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.CommandLine; @@ -52,6 +53,8 @@ private static async Task Egress() TestEgressProviderOptions options = BuildOptions(configPayload); + EmitLogs(); + if (options.ShouldSucceed) { result.Succeeded = true; @@ -78,6 +81,20 @@ private static async Task Egress() return result.Succeeded ? 0 : 1; } + private static void EmitLogs() + { + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddConsole(); + }); + + ILogger logger = loggerFactory.CreateLogger(); + + logger.LogInformation("INFORMATION"); // Not using these yet. + logger.LogWarning("WARNING"); + + } + private static TestEgressProviderOptions BuildOptions(ExtensionEgressPayload configPayload) { TestEgressProviderOptions options = new TestEgressProviderOptions() diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index c75fbc3f820..dbd150a1468 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -15,6 +15,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using System.Xml.Linq; using Xunit; using Xunit.Abstractions; @@ -70,53 +71,45 @@ public void FoundExtension_Failure() [InlineData(ConfigDirectory.DotnetToolsDirectory, DotnetToolsExeDir, TestAppExe)] public void FoundExtensionFile_Success(ConfigDirectory configDirectory, string exePath, string exeName) { - HostBuilderSettings settings = CreateHostBuilderSettings(); + IEgressExtension extension = FindEgressExtension(configDirectory, exePath, exeName); - string directoryName = GetExtensionDirectoryName(settings, configDirectory); + Assert.NotNull(extension); + } - string destinationPath = configDirectory != ConfigDirectory.DotnetToolsDirectory ? Path.Combine(directoryName, ExtensionsFolder, TestAppName) : Path.Combine(directoryName, DotnetToolsExtensionDir); + [Fact] + public async Task ExtensionResponse_Success() + { + var extension = FindEgressExtension(ConfigDirectory.UserConfigDirectory, null, null); - CopyExtensionFiles(directoryName, destinationPath, exePath, exeName); + ExtensionEgressPayload payload = new(); - IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); + payload.Configuration = new Dictionary(); + payload.Configuration.Add("ShouldSucceed", "true"); - var extensionDiscoverer = host.Services.GetService(); + TimeSpan timeout = new(0, 0, 30); // do something real + CancellationTokenSource tokenSource = new(timeout); - var extension = extensionDiscoverer.FindExtension(TestAppName); + EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); - Assert.NotNull(extension); + Assert.True(result.Succeeded); + Assert.Equal(SampleArtifactPath, result.ArtifactPath); } - [Theory] - [InlineData(ConfigDirectory.UserConfigDirectory)] - public async Task ExtensionResponse_Success(ConfigDirectory configDirectory) + private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, string exePath, string exeName) { HostBuilderSettings settings = CreateHostBuilderSettings(); string directoryName = GetExtensionDirectoryName(settings, configDirectory); - string destinationPath = Path.Combine(directoryName, ExtensionsFolder, TestAppName); + string destinationPath = configDirectory != ConfigDirectory.DotnetToolsDirectory ? Path.Combine(directoryName, ExtensionsFolder, TestAppName) : Path.Combine(directoryName, DotnetToolsExtensionDir); - CopyExtensionFiles(directoryName, destinationPath); + CopyExtensionFiles(directoryName, destinationPath, exePath, exeName); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); var extensionDiscoverer = host.Services.GetService(); - var extension = extensionDiscoverer.FindExtension(TestAppName); - - ExtensionEgressPayload payload = new(); - - payload.Configuration = new Dictionary(); - payload.Configuration.Add("ShouldSucceed", "true"); - - TimeSpan timeout = new(0, 0, 30); // do something real - CancellationTokenSource tokenSource = new(timeout); - - EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); - - Assert.True(result.Succeeded); - Assert.Equal(SampleArtifactPath, result.ArtifactPath); + return extensionDiscoverer.FindExtension(TestAppName); } private static async Task GetStream(Stream stream, CancellationToken cancellationToken) From d3f2e3d803fc690a53a8e6fbd07bdf6e10cd991c Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 28 Nov 2022 08:44:13 -0800 Subject: [PATCH 18/31] Some cleanup --- .../Program.cs | 34 +++---------------- .../EgressExtensibilityTests.cs | 10 ++---- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index 9478f72ed02..b66f597327a 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -4,14 +4,11 @@ using Microsoft.Diagnostics.Monitoring.Tool.UnitTests; using Microsoft.Diagnostics.Tools.Monitor.Egress; -using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.CommandLine; using System.IO; using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; using Xunit; namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp @@ -20,21 +17,21 @@ internal class Program { const int DefaultBufferSize = 4000; - static async Task Main(string[] args) + static int Main(string[] args) { // Expected command line format is: dotnet-monitor-egress-azureblobstorage.exe Egress RootCommand rootCommand = new RootCommand("Egresses an artifact to Azure Storage."); Command egressCmd = new Command("Egress", "The class of extension being invoked; Egress is for egressing an artifact."); - egressCmd.SetHandler(Egress); + egressCmd.SetHandler(() => Egress()); rootCommand.Add(egressCmd); - return await rootCommand.InvokeAsync(args); + return rootCommand.Invoke(args); } - private static async Task Egress() + private static int Egress() { EgressArtifactResult result = new(); try @@ -42,10 +39,7 @@ private static async Task Egress() string jsonConfig = Console.ReadLine(); ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); - Stream outputStream = new MemoryStream(); // might not be a good stream type - - TimeSpan timeout = new TimeSpan(0, 0, 30); // Should do something real here - CancellationTokenSource timeoutSource = new(timeout); + Stream outputStream = new MemoryStream(); outputStream = GetStream(); @@ -53,8 +47,6 @@ private static async Task Egress() TestEgressProviderOptions options = BuildOptions(configPayload); - EmitLogs(); - if (options.ShouldSucceed) { result.Succeeded = true; @@ -75,26 +67,10 @@ private static async Task Egress() string jsonBlob = JsonSerializer.Serialize(result); Console.Write(jsonBlob); - await Task.Delay(1); // TEMPORARY - // return non-zero exit code when failed return result.Succeeded ? 0 : 1; } - private static void EmitLogs() - { - using var loggerFactory = LoggerFactory.Create(builder => - { - builder.AddConsole(); - }); - - ILogger logger = loggerFactory.CreateLogger(); - - logger.LogInformation("INFORMATION"); // Not using these yet. - logger.LogWarning("WARNING"); - - } - private static TestEgressProviderOptions BuildOptions(ExtensionEgressPayload configPayload) { TestEgressProviderOptions options = new TestEgressProviderOptions() diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index dbd150a1468..eaf674cd162 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -15,7 +15,6 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; -using System.Xml.Linq; using Xunit; using Xunit.Abstractions; @@ -43,7 +42,6 @@ public EgressExtensibilityTests(ITestOutputHelper outputHelper) /* Test Coverage * * Successfully finding extension in each location - * Proper resolution if conflict in terms of priority * Fails properly if extension is not found * Extension.json file is properly found and parsed to find extension and DisplayName * Fails properly if Extension.json is not found / doesn't contain correct contents @@ -103,7 +101,7 @@ private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, st string destinationPath = configDirectory != ConfigDirectory.DotnetToolsDirectory ? Path.Combine(directoryName, ExtensionsFolder, TestAppName) : Path.Combine(directoryName, DotnetToolsExtensionDir); - CopyExtensionFiles(directoryName, destinationPath, exePath, exeName); + CopyExtensionFiles(destinationPath, exePath, exeName); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); @@ -121,7 +119,7 @@ private static async Task GetStream(Stream stream, CancellationToken cancellatio await tempStream.CopyToAsync(stream); } - private static void CopyExtensionFiles(string directoryName, string destinationPath, string exePath = null, string exeName = null) + private static void CopyExtensionFiles(string destinationPath, string exePath = null, string exeName = null) { Directory.CreateDirectory(destinationPath); @@ -137,9 +135,7 @@ private static void CopyExtensionFiles(string directoryName, string destinationP foreach (string sourceFilePath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) { - string fileName = Path.GetFileName(sourceFilePath); - - string replacementPath = separateExe && fileName == exeName ? exePath : destinationPath; + string replacementPath = separateExe && Path.GetFileName(sourceFilePath) == exeName ? exePath : destinationPath; string destinationFilePath = sourceFilePath.Replace(sourcePath, replacementPath); From 44a71ad097fd34eb481d879b5ca8f5f3c2dfc3e7 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 28 Nov 2022 09:19:05 -0800 Subject: [PATCH 19/31] Cleanup, added failure test --- ...s.Monitoring.EgressExtensibilityApp.csproj | 1 + .../TestEgressProviderOptions.cs | 3 -- .../extension.json | 4 +- .../EgressExtensibilityTests.cs | 41 +++++++++++-------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj index 900b546e03d..475739836e8 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -1,4 +1,5 @@  + Exe net6.0 diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs index ac0963a53fa..1d5c1068d66 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/TestEgressProviderOptions.cs @@ -4,9 +4,6 @@ namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp { - /// - /// Egress provider options for Azure blob storage. - /// internal sealed partial class TestEgressProviderOptions { public bool ShouldSucceed { get; set; } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json index 934ca77c989..3dd069032b3 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -1,8 +1,8 @@ { - "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", + "Id": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", "Version": "1.0.0", "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.exe", - "Name": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", + "Name": "TestingProvider", "SupportedExtensionTypes": [ "Egress" ] diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index eaf674cd162..be33d51d2fe 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -22,33 +22,23 @@ namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests { public sealed class EgressExtensibilityTests { + private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30); + private ITestOutputHelper _outputHelper; private const string ExtensionsFolder = "extensions"; public const string SampleArtifactPath = "my/sample/path"; public const string SampleFailureMessage = "the extension failed"; + private const string TestProviderName = "TestingProvider"; private const string TestAppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; private const string TestAppExe = TestAppName + ".exe"; private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; private const string DotnetToolsExeDir = ""; - //private const string ExtensionDefinitionFile = "extension.json"; - //private const string EgressExtensionsDirectory = "EgressExtensionResources"; - public EgressExtensibilityTests(ITestOutputHelper outputHelper) { _outputHelper = outputHelper; } - /* Test Coverage - * - * Successfully finding extension in each location - * Fails properly if extension is not found - * Extension.json file is properly found and parsed to find extension and DisplayName - * Fails properly if Extension.json is not found / doesn't contain correct contents - * Logs from extension are properly passed through to dotnet monitor - * - */ - [Fact] public void FoundExtension_Failure() { @@ -58,7 +48,7 @@ public void FoundExtension_Failure() var extensionDiscoverer = host.Services.GetService(); - const string extensionDisplayName = "AzureBlobStorage"; + const string extensionDisplayName = "InvalidProviderName"; Assert.Throws(() => extensionDiscoverer.FindExtension(extensionDisplayName)); } @@ -84,8 +74,7 @@ public async Task ExtensionResponse_Success() payload.Configuration = new Dictionary(); payload.Configuration.Add("ShouldSucceed", "true"); - TimeSpan timeout = new(0, 0, 30); // do something real - CancellationTokenSource tokenSource = new(timeout); + CancellationTokenSource tokenSource = new(DefaultTimeout); EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); @@ -93,6 +82,24 @@ public async Task ExtensionResponse_Success() Assert.Equal(SampleArtifactPath, result.ArtifactPath); } + [Fact] + public async Task ExtensionResponse_Failure() + { + var extension = FindEgressExtension(ConfigDirectory.UserConfigDirectory, null, null); + + ExtensionEgressPayload payload = new(); + + payload.Configuration = new Dictionary(); + payload.Configuration.Add("ShouldSucceed", "false"); + + CancellationTokenSource tokenSource = new(DefaultTimeout); + + EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + + Assert.False(result.Succeeded); + Assert.Equal(SampleFailureMessage, result.FailureMessage); + } + private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, string exePath, string exeName) { HostBuilderSettings settings = CreateHostBuilderSettings(); @@ -107,7 +114,7 @@ private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, st var extensionDiscoverer = host.Services.GetService(); - return extensionDiscoverer.FindExtension(TestAppName); + return extensionDiscoverer.FindExtension(TestProviderName); } private static async Task GetStream(Stream stream, CancellationToken cancellationToken) From cd34fe9ae09442eb16a404de02618118772c1ab5 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 28 Nov 2022 12:42:27 -0800 Subject: [PATCH 20/31] Removing hte notion of passing byte array --- ...s.Monitoring.EgressExtensibilityApp.csproj | 2 - .../Program.cs | 37 ++++++------------- .../EgressExtensibilityTests.cs | 10 ++--- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj index 475739836e8..fe024f38eff 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -6,8 +6,6 @@ - - diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index b66f597327a..afaefdc42c7 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -7,46 +7,40 @@ using System; using System.Collections.Generic; using System.CommandLine; -using System.IO; using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp { internal class Program { - const int DefaultBufferSize = 4000; - - static int Main(string[] args) + static async Task Main(string[] args) { - // Expected command line format is: dotnet-monitor-egress-azureblobstorage.exe Egress - RootCommand rootCommand = new RootCommand("Egresses an artifact to Azure Storage."); + RootCommand rootCommand = new RootCommand(); - Command egressCmd = new Command("Egress", "The class of extension being invoked; Egress is for egressing an artifact."); + Command egressCmd = new Command("Egress"); - egressCmd.SetHandler(() => Egress()); + egressCmd.SetHandler(Egress); rootCommand.Add(egressCmd); - return rootCommand.Invoke(args); + return await rootCommand.InvokeAsync(args); } - private static int Egress() + private static async Task Egress() { EgressArtifactResult result = new(); try { string jsonConfig = Console.ReadLine(); - ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); - - Stream outputStream = new MemoryStream(); - - outputStream = GetStream(); - - Assert.Equal(outputStream.Length, DefaultBufferSize); + ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); TestEgressProviderOptions options = BuildOptions(configPayload); + await Task.Delay(1000); + if (options.ShouldSucceed) { result.Succeeded = true; @@ -81,15 +75,6 @@ private static TestEgressProviderOptions BuildOptions(ExtensionEgressPayload con return options; } - private static Stream GetStream() - { - byte[] buffer = new byte[DefaultBufferSize]; - - Console.OpenStandardInput().Read(buffer, 0, DefaultBufferSize); - - return new MemoryStream(buffer); - } - private static bool GetConfig(IDictionary configDict, string propKey) { if (configDict.ContainsKey(propKey)) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index be33d51d2fe..8010f911304 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -13,6 +13,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -34,6 +35,9 @@ public sealed class EgressExtensibilityTests private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; private const string DotnetToolsExeDir = ""; + public const int PayloadSize = 2000; + public static byte[] ByteArray = Encoding.ASCII.GetBytes(string.Empty); + public EgressExtensibilityTests(ITestOutputHelper outputHelper) { _outputHelper = outputHelper; @@ -119,11 +123,7 @@ private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, st private static async Task GetStream(Stream stream, CancellationToken cancellationToken) { - byte[] byteArray = Enumerable.Repeat((byte)0xDE, 2000).ToArray(); - - MemoryStream tempStream = new MemoryStream(byteArray); - - await tempStream.CopyToAsync(stream); + await stream.WriteAsync(ByteArray); } private static void CopyExtensionFiles(string destinationPath, string exePath = null, string exeName = null) From cc5d702f908f213bf477599490599b27b5846f21 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 29 Nov 2022 11:48:59 -0800 Subject: [PATCH 21/31] Some cleanup --- dotnet-monitor.sln | 6 ++++++ .../Program.cs | 15 +++++---------- .../EgressExtensibilityTests.cs | 2 -- .../TestHostHelper.cs | 7 ++++++- .../Extensibility/ProgramExtension.cs | 2 -- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/dotnet-monitor.sln b/dotnet-monitor.sln index b2baf1b022f..10efeabdeba 100644 --- a/dotnet-monitor.sln +++ b/dotnet-monitor.sln @@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monit EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.ExecuteActionApp", "src\Tests\Microsoft.Diagnostics.Monitoring.ExecuteActionApp\Microsoft.Diagnostics.Monitoring.ExecuteActionApp.csproj", "{A5A0CAAB-C200-44D2-BC93-8445C6E748AD}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", "src\Tests\Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp\Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj", "{8f8a9a15-24d5-496c-b769-3caed25d1ba8}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureBlobStorage", "src\Extensions\AzureBlobStorage\AzureBlobStorage.csproj", "{5ED61A7B-F0AA-45F2-9E9A-8972FF7F7278}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.Profiler.UnitTests", "src\Tests\Microsoft.Diagnostics.Monitoring.Profiler.UnitTests\Microsoft.Diagnostics.Monitoring.Profiler.UnitTests.csproj", "{A25AC517-F7C6-43C6-B892-4A447914C42C}" @@ -108,6 +110,10 @@ Global {A5A0CAAB-C200-44D2-BC93-8445C6E748AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {A5A0CAAB-C200-44D2-BC93-8445C6E748AD}.Release|Any CPU.ActiveCfg = Release|Any CPU {A5A0CAAB-C200-44D2-BC93-8445C6E748AD}.Release|Any CPU.Build.0 = Release|Any CPU + {8f8a9a15-24d5-496c-b769-3caed25d1ba8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8f8a9a15-24d5-496c-b769-3caed25d1ba8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8f8a9a15-24d5-496c-b769-3caed25d1ba8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8f8a9a15-24d5-496c-b769-3caed25d1ba8}.Release|Any CPU.Build.0 = Release|Any CPU {5ED61A7B-F0AA-45F2-9E9A-8972FF7F7278}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5ED61A7B-F0AA-45F2-9E9A-8972FF7F7278}.Debug|Any CPU.Build.0 = Debug|Any CPU {5ED61A7B-F0AA-45F2-9E9A-8972FF7F7278}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index afaefdc42c7..2300b00aed0 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -8,28 +8,25 @@ using System.Collections.Generic; using System.CommandLine; using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using Xunit; namespace Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp { internal class Program { - static async Task Main(string[] args) + static int Main(string[] args) { RootCommand rootCommand = new RootCommand(); Command egressCmd = new Command("Egress"); - egressCmd.SetHandler(Egress); + egressCmd.SetHandler(() => Egress()); rootCommand.Add(egressCmd); - return await rootCommand.InvokeAsync(args); + return rootCommand.Invoke(args); } - private static async Task Egress() + private static int Egress() { EgressArtifactResult result = new(); try @@ -39,8 +36,6 @@ private static async Task Egress() ExtensionEgressPayload configPayload = JsonSerializer.Deserialize(jsonConfig); TestEgressProviderOptions options = BuildOptions(configPayload); - await Task.Delay(1000); - if (options.ShouldSucceed) { result.Succeeded = true; @@ -58,7 +53,7 @@ private static async Task Egress() result.FailureMessage = ex.Message; } - string jsonBlob = JsonSerializer.Serialize(result); + string jsonBlob = JsonSerializer.Serialize(result); Console.Write(jsonBlob); // return non-zero exit code when failed diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 8010f911304..cfd9ac01347 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; using System.Text; using System.Threading; @@ -35,7 +34,6 @@ public sealed class EgressExtensibilityTests private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; private const string DotnetToolsExeDir = ""; - public const int PayloadSize = 2000; public static byte[] ByteArray = Encoding.ASCII.GetBytes(string.Empty); public EgressExtensibilityTests(ITestOutputHelper outputHelper) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs index aab7dc8ca38..618743be5a9 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestHostHelper.cs @@ -101,7 +101,12 @@ public static IHost CreateHost( services.ConfigureTemplates(context.Configuration); services.AddSingleton(); services.ConfigureCollectionRules(); - services.ConfigureExtensions(settings); // settings could be null...how do we want to protect against this? + + if (settings != null) + { + services.ConfigureExtensions(settings); + } + services.ConfigureEgress(); services.ConfigureDiagnosticPort(context.Configuration); diff --git a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs index db4579dde41..3c1f7165c66 100644 --- a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs +++ b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs @@ -112,9 +112,7 @@ public async Task EgressArtifact(ExtensionEgressPayload co _logger.ExtensionConfigured(pStart.FileName, p.Id); await getStreamAction(p.StandardInput.BaseStream, token); - await p.StandardInput.WriteAsync(NewLine, token); await p.StandardInput.BaseStream.FlushAsync(token); - p.StandardInput.Close(); _logger.ExtensionEgressPayloadCompleted(p.Id); From a21b920b41a560cfaae8da8bce26cd3a6c6af5c4 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 5 Dec 2022 09:27:55 -0800 Subject: [PATCH 22/31] Added in executing assembly location for tests, some cleanup --- ...cs.Monitoring.EgressExtensibilityApp.csproj | 2 +- .../Program.cs | 2 -- .../Runners/MonitorRunner.cs | 6 ++++++ .../EgressExtensibilityTests.cs | 18 +++++++++--------- .../HostBuilder/HostBuilderSettings.cs | 17 ++++++++++++++++- .../ServiceCollectionExtensions.cs | 4 ++-- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj index fe024f38eff..f25e58f42db 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + $(ToolTargetFrameworks) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index 2300b00aed0..eed65df0ee9 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -77,8 +77,6 @@ private static bool GetConfig(IDictionary configDict, string pro return bool.Parse(configDict[propKey]); } - // throw? - return false; } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs index 0d933f6b8ef..bbe4e328f20 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs @@ -84,6 +84,9 @@ internal class MonitorRunner : IAsyncDisposable private string DotnetToolsExtensionDirectoryPath => Path.Combine(TempPath, "DotnetToolsExtension"); + private string ExecutingAssemblyDirectoryPath => + Path.Combine(TempPath, "ExecutingAssembly"); + private string UserSettingsFilePath => Path.Combine(UserConfigDirectoryPath, "settings.json"); @@ -100,6 +103,7 @@ public MonitorRunner(ITestOutputHelper outputHelper) Directory.CreateDirectory(SharedConfigDirectoryPath); Directory.CreateDirectory(UserConfigDirectoryPath); Directory.CreateDirectory(DotnetToolsExtensionDirectoryPath); + Directory.CreateDirectory(ExecutingAssemblyDirectoryPath); } public virtual async ValueTask DisposeAsync() @@ -160,6 +164,8 @@ public virtual async Task StartAsync(string command, string[] args, Cancellation _adapter.Environment.Add("DotnetMonitorTestSettings__UserConfigDirectoryOverride", UserConfigDirectoryPath); // Override the dotnet tools extension directory _adapter.Environment.Add("DotnetMonitorTestSettings__DotnetToolsExtensionDirectoryOverride", DotnetToolsExtensionDirectoryPath); + // Override the "next to me" executing assembly directory + _adapter.Environment.Add("DotnetMonitorTestSettings__ExecutingAssemblyDirectoryOverride", ExecutingAssemblyDirectoryPath); // Enable experimental stacks feature if (EnableCallStacksFeature) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index cfd9ac01347..1d532cdde93 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests { public sealed class EgressExtensibilityTests { - private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30); + private static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(3); private ITestOutputHelper _outputHelper; private const string ExtensionsFolder = "extensions"; @@ -56,6 +56,7 @@ public void FoundExtension_Failure() } [Theory] + [InlineData(ConfigDirectory.ExecutingAssemblyDirectory, null, null)] [InlineData(ConfigDirectory.UserConfigDirectory, null, null)] [InlineData(ConfigDirectory.SharedConfigDirectory, null, null)] [InlineData(ConfigDirectory.DotnetToolsDirectory, DotnetToolsExeDir, TestAppExe)] @@ -121,6 +122,7 @@ private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, st private static async Task GetStream(Stream stream, CancellationToken cancellationToken) { + // The test extension currently does not do anything with this stream. await stream.WriteAsync(ByteArray); } @@ -134,7 +136,7 @@ private static void CopyExtensionFiles(string destinationPath, string exePath = Directory.CreateDirectory(exePath); } - string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), TestAppName, TargetFrameworkMoniker.Net60); // set this? + string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), TestAppName); string sourcePath = Path.GetDirectoryName(testAppPath); @@ -154,6 +156,7 @@ private static void CopyExtensionFiles(string destinationPath, string exePath = private HostBuilderSettings CreateHostBuilderSettings() { + using TemporaryDirectory executingAssemblyDir = new(_outputHelper); using TemporaryDirectory sharedConfigDir = new(_outputHelper); using TemporaryDirectory userConfigDir = new(_outputHelper); using TemporaryDirectory dotnetToolsConfigDir = new(_outputHelper); @@ -161,6 +164,7 @@ private HostBuilderSettings CreateHostBuilderSettings() // Set up the initial settings used to create the host builder. return new() { + ExecutingAssemblyDirectory = executingAssemblyDir.FullName, SharedConfigDirectory = sharedConfigDir.FullName, UserConfigDirectory = userConfigDir.FullName, DotnetToolsExtensionDirectory = dotnetToolsConfigDir.FullName @@ -182,22 +186,18 @@ private string GetExtensionDirectoryName(HostBuilderSettings settings, ConfigDir return settings.SharedConfigDirectory; case ConfigDirectory.DotnetToolsDirectory: return settings.DotnetToolsExtensionDirectory; - case ConfigDirectory.NextToMeDirectory: - //directoryName = .FullName; - // NOT HANDLING THIS YET - break; + case ConfigDirectory.ExecutingAssemblyDirectory: + return settings.ExecutingAssemblyDirectory; default: throw new Exception("Config Directory not found."); } - - return null; } /// This is the order of configuration sources where a name with a lower /// enum value has a lower precedence in configuration. public enum ConfigDirectory { - NextToMeDirectory, + ExecutingAssemblyDirectory, SharedConfigDirectory, UserConfigDirectory, DotnetToolsDirectory diff --git a/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs b/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs index 359dbc4faf9..3913bb961f8 100644 --- a/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs +++ b/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs @@ -4,6 +4,7 @@ using System; using System.IO; +using System.Reflection; using System.Runtime.InteropServices; namespace Microsoft.Diagnostics.Tools.Monitor @@ -29,6 +30,11 @@ private const string UserConfigDirectoryOverrideEnvironmentVariable private const string DotnetToolsExtensionDirectoryOverrideEnvironmentVariable = "DotnetMonitorTestSettings__DotnetToolsExtensionDirectoryOverride"; + // Allows tests to override the user configuration directory so there + // is better control and access of what is visible during test. + private const string ExecutingAssemblyDirectoryOverrideEnvironmentVariable + = "DotnetMonitorTestSettings__ExecutingAssemblyDirectoryOverride"; + // Location where shared dotnet-monitor configuration is stored. // Windows: "%ProgramData%\dotnet-monitor // Other: /etc/dotnet-monitor @@ -59,6 +65,12 @@ private const string DotnetToolsExtensionDirectoryOverrideEnvironmentVariable Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "." + DotnetFolderName, ToolsFolderName) : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "." + DotnetFolderName, ToolsFolderName)); + // Location for dotnet-monitor's executing assembly. + public static readonly string ExecutingAssemblyDirectoryPath = + GetEnvironmentOverrideOrValue( + ExecutingAssemblyDirectoryOverrideEnvironmentVariable, + Assembly.GetExecutingAssembly().Location); + public string[] Urls { get; set; } public string[] MetricsUrls { get; set; } @@ -77,6 +89,8 @@ private const string DotnetToolsExtensionDirectoryOverrideEnvironmentVariable public string DotnetToolsExtensionDirectory { get; set; } + public string ExecutingAssemblyDirectory { get; set; } + public FileInfo UserProvidedConfigFilePath { get; set; } /// @@ -101,7 +115,8 @@ public static HostBuilderSettings CreateMonitor( SharedConfigDirectory = SharedConfigDirectoryPath, UserConfigDirectory = UserConfigDirectoryPath, UserProvidedConfigFilePath = userProvidedConfigFilePath, - DotnetToolsExtensionDirectory = DotnetToolsExtensionDirectoryPath + DotnetToolsExtensionDirectory = DotnetToolsExtensionDirectoryPath, + ExecutingAssemblyDirectory = ExecutingAssemblyDirectoryPath }; } diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index 3461cba7cdd..55c63c2cbd2 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -217,7 +217,7 @@ public static IServiceCollection ConfigureExtensions(this IServiceCollection ser // Add the services to discover extensions services.AddSingleton(); - string nextToMeFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string executingAssemblyFolder = settings.ExecutingAssemblyDirectory; string progDataFolder = settings.SharedConfigDirectory; string settingsFolder = settings.UserConfigDirectory; string dotnetToolsFolder = settings.DotnetToolsExtensionDirectory; @@ -230,7 +230,7 @@ public static IServiceCollection ConfigureExtensions(this IServiceCollection ser } // Add the folders we search to get extensions from - services.AddFolderExtensionRepository(nextToMeFolder); + services.AddFolderExtensionRepository(executingAssemblyFolder); services.AddFolderExtensionRepository(progDataFolder); services.AddFolderExtensionRepository(settingsFolder); services.AddToolsExtensionRepository(dotnetToolsFolder); From b2e6f3570433df41ecaf16752130f111c1b3e947 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 08:49:06 -0800 Subject: [PATCH 23/31] Cleanup, bug fix --- .../EgressExtensibilityTests.cs | 5 +---- .../EgressExtensionResources/extension.json | 9 --------- ...icrosoft.Diagnostics.Monitoring.Tool.UnitTests.csproj | 3 --- .../dotnet-monitor/HostBuilder/HostBuilderSettings.cs | 2 +- src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs | 1 - 5 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 1d532cdde93..92a898c4362 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -33,8 +33,7 @@ public sealed class EgressExtensibilityTests private const string TestAppExe = TestAppName + ".exe"; private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; private const string DotnetToolsExeDir = ""; - - public static byte[] ByteArray = Encoding.ASCII.GetBytes(string.Empty); + private readonly static byte[] ByteArray = Encoding.ASCII.GetBytes(string.Empty); public EgressExtensibilityTests(ITestOutputHelper outputHelper) { @@ -193,8 +192,6 @@ private string GetExtensionDirectoryName(HostBuilderSettings settings, ConfigDir } } - /// This is the order of configuration sources where a name with a lower - /// enum value has a lower precedence in configuration. public enum ConfigDirectory { ExecutingAssemblyDirectory, diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json deleted file mode 100644 index 5b1d377704c..00000000000 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensionResources/extension.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Id": "Microsoft.Diagnostics.Monitoring.AzureStorage", - "Version": "1.0.0", - "Program": "dotnet-monitor-egress-azureblobstorage.exe", - "Name": "AzureBlobStorage", - "SupportedExtensionTypes": [ - "Egress" - ] -} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index 26342751e8e..d24a1a1d003 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -114,9 +114,6 @@ Always - - Always - Always diff --git a/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs b/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs index 3913bb961f8..5decee63939 100644 --- a/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs +++ b/src/Tools/dotnet-monitor/HostBuilder/HostBuilderSettings.cs @@ -69,7 +69,7 @@ private const string ExecutingAssemblyDirectoryOverrideEnvironmentVariable public static readonly string ExecutingAssemblyDirectoryPath = GetEnvironmentOverrideOrValue( ExecutingAssemblyDirectoryOverrideEnvironmentVariable, - Assembly.GetExecutingAssembly().Location); + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); public string[] Urls { get; set; } diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index 55c63c2cbd2..4f5afb25d5e 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -31,7 +31,6 @@ using Microsoft.Extensions.Options; using System; using System.IO; -using System.Reflection; namespace Microsoft.Diagnostics.Tools.Monitor { From adde9cb0bbaf1a630bf6625b69e4f459f74ed3d6 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 09:39:57 -0800 Subject: [PATCH 24/31] Refactoring --- .../Program.cs | 1 - .../EgressExtensibilityTests.cs | 101 ++++++++---------- 2 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs index eed65df0ee9..61258d2fd5b 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/Program.cs @@ -80,5 +80,4 @@ private static bool GetConfig(IDictionary configDict, string pro return false; } } - } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 92a898c4362..cd79e65206f 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -25,12 +25,13 @@ public sealed class EgressExtensibilityTests private static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(3); private ITestOutputHelper _outputHelper; + private const string ExtensionsFolder = "extensions"; - public const string SampleArtifactPath = "my/sample/path"; + public const string SampleArtifactPath = "sample\\path"; public const string SampleFailureMessage = "the extension failed"; - private const string TestProviderName = "TestingProvider"; - private const string TestAppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; - private const string TestAppExe = TestAppName + ".exe"; + private const string ProviderName = "TestingProvider"; // Must match the name in extension.json + private const string AppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; + private const string AppExe = AppName + ".exe"; private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; private const string DotnetToolsExeDir = ""; private readonly static byte[] ByteArray = Encoding.ASCII.GetBytes(string.Empty); @@ -49,16 +50,14 @@ public void FoundExtension_Failure() var extensionDiscoverer = host.Services.GetService(); - const string extensionDisplayName = "InvalidProviderName"; - - Assert.Throws(() => extensionDiscoverer.FindExtension(extensionDisplayName)); + Assert.Throws(() => extensionDiscoverer.FindExtension("InvalidProviderName")); } [Theory] [InlineData(ConfigDirectory.ExecutingAssemblyDirectory, null, null)] [InlineData(ConfigDirectory.UserConfigDirectory, null, null)] [InlineData(ConfigDirectory.SharedConfigDirectory, null, null)] - [InlineData(ConfigDirectory.DotnetToolsDirectory, DotnetToolsExeDir, TestAppExe)] + [InlineData(ConfigDirectory.DotnetToolsExtensionDirectory, DotnetToolsExeDir, AppExe)] public void FoundExtensionFile_Success(ConfigDirectory configDirectory, string exePath, string exeName) { IEgressExtension extension = FindEgressExtension(configDirectory, exePath, exeName); @@ -69,16 +68,7 @@ public void FoundExtensionFile_Success(ConfigDirectory configDirectory, string e [Fact] public async Task ExtensionResponse_Success() { - var extension = FindEgressExtension(ConfigDirectory.UserConfigDirectory, null, null); - - ExtensionEgressPayload payload = new(); - - payload.Configuration = new Dictionary(); - payload.Configuration.Add("ShouldSucceed", "true"); - - CancellationTokenSource tokenSource = new(DefaultTimeout); - - EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + EgressArtifactResult result = await GetExtensionResponse(true); Assert.True(result.Succeeded); Assert.Equal(SampleArtifactPath, result.ArtifactPath); @@ -87,36 +77,42 @@ public async Task ExtensionResponse_Success() [Fact] public async Task ExtensionResponse_Failure() { - var extension = FindEgressExtension(ConfigDirectory.UserConfigDirectory, null, null); + EgressArtifactResult result = await GetExtensionResponse(false); - ExtensionEgressPayload payload = new(); + Assert.False(result.Succeeded); + Assert.Equal(SampleFailureMessage, result.FailureMessage); + } - payload.Configuration = new Dictionary(); - payload.Configuration.Add("ShouldSucceed", "false"); + private async Task GetExtensionResponse(bool shouldSucceed) + { + var extension = FindEgressExtension(ConfigDirectory.UserConfigDirectory); - CancellationTokenSource tokenSource = new(DefaultTimeout); + ExtensionEgressPayload payload = new(); + payload.Configuration = new Dictionary + { + { "ShouldSucceed", shouldSucceed.ToString() } + }; - EgressArtifactResult result = await extension.EgressArtifact(payload, GetStream, tokenSource.Token); + CancellationTokenSource tokenSource = new(DefaultTimeout); - Assert.False(result.Succeeded); - Assert.Equal(SampleFailureMessage, result.FailureMessage); + return await extension.EgressArtifact(payload, GetStream, tokenSource.Token); } - private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, string exePath, string exeName) + private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, string exePath = null, string exeName = null) { HostBuilderSettings settings = CreateHostBuilderSettings(); string directoryName = GetExtensionDirectoryName(settings, configDirectory); - string destinationPath = configDirectory != ConfigDirectory.DotnetToolsDirectory ? Path.Combine(directoryName, ExtensionsFolder, TestAppName) : Path.Combine(directoryName, DotnetToolsExtensionDir); + string extensionDirPath = configDirectory != ConfigDirectory.DotnetToolsExtensionDirectory ? Path.Combine(directoryName, ExtensionsFolder, AppName) : Path.Combine(directoryName, DotnetToolsExtensionDir); - CopyExtensionFiles(destinationPath, exePath, exeName); + CopyExtensionFiles(extensionDirPath, exePath, exeName); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); var extensionDiscoverer = host.Services.GetService(); - return extensionDiscoverer.FindExtension(TestProviderName); + return extensionDiscoverer.FindExtension(ProviderName); } private static async Task GetStream(Stream stream, CancellationToken cancellationToken) @@ -125,31 +121,31 @@ private static async Task GetStream(Stream stream, CancellationToken cancellatio await stream.WriteAsync(ByteArray); } - private static void CopyExtensionFiles(string destinationPath, string exePath = null, string exeName = null) + private static void CopyExtensionFiles(string extensionDirPath, string exePath = null, string exeName = null) { - Directory.CreateDirectory(destinationPath); + Directory.CreateDirectory(extensionDirPath); - bool separateExe = HasSeparateExe(exePath, exeName); - if (separateExe) - { - Directory.CreateDirectory(exePath); - } - - string testAppPath = AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), TestAppName); + string testAppDirPath = Path.GetDirectoryName(AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), AppName)); - string sourcePath = Path.GetDirectoryName(testAppPath); + bool hasSeparateExe = !string.IsNullOrEmpty(exePath) && !string.IsNullOrEmpty(exeName); - foreach (string sourceFilePath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + foreach (string testAppFilePath in Directory.GetFiles(testAppDirPath, "*.*", SearchOption.AllDirectories)) { - string replacementPath = separateExe && Path.GetFileName(sourceFilePath) == exeName ? exePath : destinationPath; - - string destinationFilePath = sourceFilePath.Replace(sourcePath, replacementPath); + string extensionFilePath = string.Empty; - string destinationDirPath = Path.GetDirectoryName(destinationFilePath); + if (hasSeparateExe && Path.GetFileName(testAppFilePath) == exeName) + { + Directory.CreateDirectory(exePath); + extensionFilePath = testAppFilePath.Replace(testAppDirPath, exePath); + } + else + { + extensionFilePath = testAppFilePath.Replace(testAppDirPath, extensionDirPath); + } - Directory.CreateDirectory(destinationDirPath); + Directory.CreateDirectory(Path.GetDirectoryName(extensionFilePath)); - File.Copy(sourceFilePath, destinationFilePath, true); + File.Copy(testAppFilePath, extensionFilePath, true); } } @@ -170,11 +166,6 @@ private HostBuilderSettings CreateHostBuilderSettings() }; } - private static bool HasSeparateExe(string directory, string exe) - { - return !string.IsNullOrEmpty(directory) && !string.IsNullOrEmpty(exe); - } - private string GetExtensionDirectoryName(HostBuilderSettings settings, ConfigDirectory configDirectory) { switch (configDirectory) @@ -183,12 +174,12 @@ private string GetExtensionDirectoryName(HostBuilderSettings settings, ConfigDir return settings.UserConfigDirectory; case ConfigDirectory.SharedConfigDirectory: return settings.SharedConfigDirectory; - case ConfigDirectory.DotnetToolsDirectory: + case ConfigDirectory.DotnetToolsExtensionDirectory: return settings.DotnetToolsExtensionDirectory; case ConfigDirectory.ExecutingAssemblyDirectory: return settings.ExecutingAssemblyDirectory; default: - throw new Exception("Config Directory not found."); + throw new ArgumentException("configDirectory not found."); } } @@ -197,7 +188,7 @@ public enum ConfigDirectory ExecutingAssemblyDirectory, SharedConfigDirectory, UserConfigDirectory, - DotnetToolsDirectory + DotnetToolsExtensionDirectory } } } From 2d5b6f454feeea6093a2e388530dff6925a72d7b Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 09:48:55 -0800 Subject: [PATCH 25/31] Fixed sln --- dotnet-monitor.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/dotnet-monitor.sln b/dotnet-monitor.sln index 10efeabdeba..748c59a0f16 100644 --- a/dotnet-monitor.sln +++ b/dotnet-monitor.sln @@ -154,6 +154,7 @@ Global {173F959B-231B-45D1-8328-9460D4C5BC71} = {19FAB78C-3351-4911-8F0C-8C6056401740} {0DBE362D-82F1-4740-AE6A-40C1A82EDCDB} = {C7568468-1C79-4944-8136-18812A7F9EA7} {A5A0CAAB-C200-44D2-BC93-8445C6E748AD} = {C7568468-1C79-4944-8136-18812A7F9EA7} + {8f8a9a15-24d5-496c-b769-3caed25d1ba8} = {C7568468-1C79-4944-8136-18812A7F9EA7} {5ED61A7B-F0AA-45F2-9E9A-8972FF7F7278} = {B62728C8-1267-4043-B46F-5537BBAEC692} {A25AC517-F7C6-43C6-B892-4A447914C42C} = {C7568468-1C79-4944-8136-18812A7F9EA7} {1CA2284B-A3A0-476A-9A93-A95E665E78BE} = {C7568468-1C79-4944-8136-18812A7F9EA7} From 71dedcba3f58d1bcd418b49f808b389445bffbba Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 10:08:16 -0800 Subject: [PATCH 26/31] Removed unused file --- .../Options/TestEgressProviderOptions.cs | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs deleted file mode 100644 index 02540321690..00000000000 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/TestEgressProviderOptions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Diagnostics.Monitoring.TestCommon.Options -{ - /// - /// Egress provider options for Azure blob storage. - /// - internal sealed partial class TestEgressProviderOptions - { - public bool ShouldSucceed { get; set; } - } -} From 3f77992f7fa633e3b053feb780f6c37a8f1d6a56 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 11:27:28 -0800 Subject: [PATCH 27/31] PR feedback --- .../EgressExtensibilityTests.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index cd79e65206f..d74a46529ff 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -22,6 +23,7 @@ namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests { public sealed class EgressExtensibilityTests { + // TODO: Use CommonTestTimeouts.GeneralTimeout private static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(3); private ITestOutputHelper _outputHelper; @@ -31,8 +33,8 @@ public sealed class EgressExtensibilityTests public const string SampleFailureMessage = "the extension failed"; private const string ProviderName = "TestingProvider"; // Must match the name in extension.json private const string AppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; - private const string AppExe = AppName + ".exe"; - private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; + private static string AppExe = AppName + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty); + private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; // TODO: Don't have this be a fixed version private const string DotnetToolsExeDir = ""; private readonly static byte[] ByteArray = Encoding.ASCII.GetBytes(string.Empty); @@ -54,13 +56,13 @@ public void FoundExtension_Failure() } [Theory] - [InlineData(ConfigDirectory.ExecutingAssemblyDirectory, null, null)] - [InlineData(ConfigDirectory.UserConfigDirectory, null, null)] - [InlineData(ConfigDirectory.SharedConfigDirectory, null, null)] - [InlineData(ConfigDirectory.DotnetToolsExtensionDirectory, DotnetToolsExeDir, AppExe)] - public void FoundExtensionFile_Success(ConfigDirectory configDirectory, string exePath, string exeName) + [InlineData(ConfigDirectory.ExecutingAssemblyDirectory, null)] + [InlineData(ConfigDirectory.UserConfigDirectory, null)] + [InlineData(ConfigDirectory.SharedConfigDirectory, null)] + [InlineData(ConfigDirectory.DotnetToolsExtensionDirectory, DotnetToolsExeDir)] + public void FoundExtensionFile_Success(ConfigDirectory configDirectory, string exePath) { - IEgressExtension extension = FindEgressExtension(configDirectory, exePath, exeName); + IEgressExtension extension = FindEgressExtension(configDirectory, exePath); Assert.NotNull(extension); } @@ -98,7 +100,7 @@ private async Task GetExtensionResponse(bool shouldSucceed return await extension.EgressArtifact(payload, GetStream, tokenSource.Token); } - private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, string exePath = null, string exeName = null) + private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, string exePath = null) { HostBuilderSettings settings = CreateHostBuilderSettings(); @@ -106,7 +108,7 @@ private IEgressExtension FindEgressExtension(ConfigDirectory configDirectory, st string extensionDirPath = configDirectory != ConfigDirectory.DotnetToolsExtensionDirectory ? Path.Combine(directoryName, ExtensionsFolder, AppName) : Path.Combine(directoryName, DotnetToolsExtensionDir); - CopyExtensionFiles(extensionDirPath, exePath, exeName); + CopyExtensionFiles(extensionDirPath, exePath); IHost host = TestHostHelper.CreateHost(_outputHelper, rootOptions => { }, host => { }, settings: settings); @@ -121,19 +123,19 @@ private static async Task GetStream(Stream stream, CancellationToken cancellatio await stream.WriteAsync(ByteArray); } - private static void CopyExtensionFiles(string extensionDirPath, string exePath = null, string exeName = null) + private static void CopyExtensionFiles(string extensionDirPath, string exePath = null) { Directory.CreateDirectory(extensionDirPath); string testAppDirPath = Path.GetDirectoryName(AssemblyHelper.GetAssemblyArtifactBinPath(Assembly.GetExecutingAssembly(), AppName)); - bool hasSeparateExe = !string.IsNullOrEmpty(exePath) && !string.IsNullOrEmpty(exeName); + bool hasSeparateExe = !string.IsNullOrEmpty(exePath); foreach (string testAppFilePath in Directory.GetFiles(testAppDirPath, "*.*", SearchOption.AllDirectories)) { string extensionFilePath = string.Empty; - if (hasSeparateExe && Path.GetFileName(testAppFilePath) == exeName) + if (hasSeparateExe && Path.GetFileName(testAppFilePath) == AppExe) { Directory.CreateDirectory(exePath); extensionFilePath = testAppFilePath.Replace(testAppDirPath, exePath); From 4cfaa0528c0dfd3c85c5c82a615490f5dc901b57 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 13:10:16 -0800 Subject: [PATCH 28/31] Experimenting with file extensions --- .../extension.json | 2 +- .../EgressExtensibilityTests.cs | 3 +-- .../dotnet-monitor/Extensibility/ProgramExtension.cs | 11 ++++++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json index 3dd069032b3..972567c6cbf 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -1,7 +1,7 @@ { "Id": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", "Version": "1.0.0", - "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.exe", + "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", "Name": "TestingProvider", "SupportedExtensionTypes": [ "Egress" diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index d74a46529ff..43029f69671 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -33,7 +33,6 @@ public sealed class EgressExtensibilityTests public const string SampleFailureMessage = "the extension failed"; private const string ProviderName = "TestingProvider"; // Must match the name in extension.json private const string AppName = "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp"; - private static string AppExe = AppName + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty); private const string DotnetToolsExtensionDir = ".store\\tool-name\\7.0\\tool-name\\7.0\\tools\\net7.0\\any"; // TODO: Don't have this be a fixed version private const string DotnetToolsExeDir = ""; private readonly static byte[] ByteArray = Encoding.ASCII.GetBytes(string.Empty); @@ -135,7 +134,7 @@ private static void CopyExtensionFiles(string extensionDirPath, string exePath = { string extensionFilePath = string.Empty; - if (hasSeparateExe && Path.GetFileName(testAppFilePath) == AppExe) + if (hasSeparateExe && Path.GetFileName(testAppFilePath) == AppName) { Directory.CreateDirectory(exePath); extensionFilePath = testAppFilePath.Replace(testAppDirPath, exePath); diff --git a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs index 3c1f7165c66..62472485328 100644 --- a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs +++ b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -65,7 +66,15 @@ public async Task EgressArtifact(ExtensionEgressPayload co // This is really weird, yes, but this is one of 2 overloads for [Stream].WriteAsync(...) that supports a CancellationToken, so we use a ReadOnlyMemory instead of a string. ReadOnlyMemory NewLine = new ReadOnlyMemory("\r\n".ToCharArray()); - string programRelPath = Path.Combine(Path.GetDirectoryName(_exePath), Declaration.Program); + string exeName = Declaration.Program; + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + exeName = Path.GetFileNameWithoutExtension(exeName); + } + + string programRelPath = Path.Combine(Path.GetDirectoryName(_exePath), exeName); + IFileInfo progInfo = _fileSystem.GetFileInfo(programRelPath); if (!progInfo.Exists || progInfo.IsDirectory || progInfo.PhysicalPath == null) { From 6ea63f53ba0f7b3c867dd05b43786bc8262ac287 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 13:32:45 -0800 Subject: [PATCH 29/31] Tweaks --- src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs index 62472485328..0d5f3325291 100644 --- a/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs +++ b/src/Tools/dotnet-monitor/Extensibility/ProgramExtension.cs @@ -68,7 +68,7 @@ public async Task EgressArtifact(ExtensionEgressPayload co string exeName = Declaration.Program; - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Path.GetExtension(exeName) == ".exe") { exeName = Path.GetFileNameWithoutExtension(exeName); } From 73acea96e9261efa1521642ed2a61438fb5e3e95 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 7 Dec 2022 14:43:08 -0800 Subject: [PATCH 30/31] Experimenting with how to get things working on all OS's --- .../extension.json | 2 +- .../EgressExtensibilityTests.cs | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json index 972567c6cbf..3dd069032b3 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp/extension.json @@ -1,7 +1,7 @@ { "Id": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", "Version": "1.0.0", - "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp", + "Program": "Microsoft.Diagnostics.Monitoring.EgressExtensibilityApp.exe", "Name": "TestingProvider", "SupportedExtensionTypes": [ "Egress" diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs index 43029f69671..0273fe8596d 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressExtensibilityTests.cs @@ -134,7 +134,7 @@ private static void CopyExtensionFiles(string extensionDirPath, string exePath = { string extensionFilePath = string.Empty; - if (hasSeparateExe && Path.GetFileName(testAppFilePath) == AppName) + if (hasSeparateExe && IsExecutablePath(testAppFilePath)) { Directory.CreateDirectory(exePath); extensionFilePath = testAppFilePath.Replace(testAppDirPath, exePath); @@ -150,6 +150,23 @@ private static void CopyExtensionFiles(string extensionDirPath, string exePath = } } + private static bool IsExecutablePath(string path) + { + if (Path.GetFileNameWithoutExtension(path) == AppName) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Path.GetExtension(path) == ".exe") + { + return true; + } + else + { + return Path.GetExtension(path) == string.Empty; + } + } + + return false; + } + private HostBuilderSettings CreateHostBuilderSettings() { using TemporaryDirectory executingAssemblyDir = new(_outputHelper); From 0fd96aea051e8f39e508f94a1e3bfd6ca7c53eef Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Wed, 22 Mar 2023 12:29:02 -0700 Subject: [PATCH 31/31] Update dotnet-monitor.sln --- dotnet-monitor.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/dotnet-monitor.sln b/dotnet-monitor.sln index 748c59a0f16..205fd485f16 100644 --- a/dotnet-monitor.sln +++ b/dotnet-monitor.sln @@ -165,3 +165,4 @@ Global SolutionGuid = {46465737-C938-44FC-BE1A-4CE139EBB5E0} EndGlobalSection EndGlobal +