diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests.csproj
index 32c177dd04b..1effc0581bf 100644
--- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests.csproj
+++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests.csproj
@@ -70,7 +70,7 @@
-
+
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 afb28d94448..36a604d4e1c 100644
--- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs
+++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/MonitorRunner.cs
@@ -165,7 +165,8 @@ public virtual async Task StartAsync(string command, string[] args, Cancellation
_adapter.Environment.Add("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", TestHostingStartupAssemblyName);
// Set configuration via environment variables
- var configurationViaEnvironment = ConfigurationFromEnvironment.ToEnvironmentConfiguration(useDotnetMonitorPrefix: true);
+ var optionsMapper = new CommonOptionsMapper();
+ var configurationViaEnvironment = optionsMapper.ToEnvironmentConfiguration(ConfigurationFromEnvironment, useDotnetMonitorPrefix: true);
if (configurationViaEnvironment.Count > 0)
{
// Set additional environment variables from configuration
@@ -197,7 +198,8 @@ protected virtual void StandardOutputCallback(string line)
public void WriteKeyPerValueConfiguration(RootOptions options)
{
- foreach (KeyValuePair entry in options.ToKeyPerFileConfiguration())
+ CommonOptionsMapper optionsMapper = new();
+ foreach (KeyValuePair entry in optionsMapper.ToKeyPerFileConfiguration(options))
{
File.WriteAllText(
Path.Combine(SharedConfigDirectoryPath, entry.Key),
diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/TestHostHelper.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/TestHostHelper.cs
index 02c48fa9433..bef5038156b 100644
--- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/TestHostHelper.cs
+++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/TestHostHelper.cs
@@ -10,6 +10,7 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Threading.Tasks;
using Xunit.Abstractions;
@@ -73,7 +74,9 @@ public static IHost CreateHost(
RootOptions options = new();
setup(options);
- IDictionary configurationValues = options.ToConfigurationValues();
+ CommonOptionsMapper optionsMapper = new();
+ optionsMapper.AddActionSettings(nameof(PassThroughAction), MapPassThroughOptions);
+ IDictionary configurationValues = optionsMapper.ToConfigurationValues(options);
outputHelper.WriteLine("Begin Configuration:");
foreach ((string key, string value) in configurationValues)
{
@@ -128,5 +131,21 @@ public static IHost CreateHost(
})
.Build();
}
+
+ private static void MapPassThroughOptions(PassThroughOptions obj, string valueName, string separator, IDictionary map)
+ {
+ if (null != obj)
+ {
+ string prefix = FormattableString.Invariant($"{valueName}{separator}");
+ MapString(obj.Input1, FormattableString.Invariant($"{prefix}{nameof(obj.Input1)}"));
+ MapString(obj.Input2, FormattableString.Invariant($"{prefix}{nameof(obj.Input2)}"));
+ MapString(obj.Input3, FormattableString.Invariant($"{prefix}{nameof(obj.Input3)}"));
+ }
+
+ void MapString(string value, string valueName)
+ {
+ map.Add(valueName, ConvertUtils.ToString(value, CultureInfo.InvariantCulture));
+ }
+ }
}
}
diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs
index 5e55d62eecf..0644ea01ab5 100644
--- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs
+++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs
@@ -142,14 +142,14 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
[Fact]
public async Task ProcessInfoTest()
{
- PassThroughOptions settings = null;
+ CollectionRuleActionOptions actionOptions = null;
await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
{
CollectionRuleOptions options = rootOptions.CreateCollectionRule(DefaultRuleName)
.AddPassThroughAction("a1", ConfigurationTokenParser.ProcessNameReference, ConfigurationTokenParser.ProcessIdReference, ConfigurationTokenParser.CommandLineReference)
.SetStartupTrigger();
- settings = (PassThroughOptions)options.Actions.Last().Settings;
+ actionOptions = options.Actions.Last();
}, host =>
{
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(TimeoutMs);
@@ -157,6 +157,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
CollectionRuleOptions ruleOptions = host.Services.GetRequiredService>().Get(DefaultRuleName);
ILogger logger = host.Services.GetRequiredService>();
TimeProvider timeProvider = host.Services.GetRequiredService();
+ ICollectionRuleActionOperations actionOperations = host.Services.GetRequiredService();
const string processName = "actionProcess";
const int processId = 123;
@@ -165,8 +166,8 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
Guid instanceId = Guid.NewGuid();
CollectionRuleContext context = new(DefaultRuleName, ruleOptions, new TestProcessInfo(instanceId, processId: processId, commandLine: commandLine), HostInfo.GetCurrent(timeProvider), logger);
- ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context);
- PassThroughOptions newSettings = (PassThroughOptions)analyzer.SubstituteOptionValues(new Dictionary(), 1, settings);
+ ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context, actionOperations);
+ PassThroughOptions newSettings = (PassThroughOptions)analyzer.SubstituteOptionValues(new Dictionary(), 1, actionOptions);
Assert.Equal(processName, newSettings.Input1);
Assert.Equal(processId.ToString(CultureInfo.InvariantCulture), newSettings.Input2);
@@ -181,14 +182,14 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
[Fact]
public async Task HostInfoTest()
{
- PassThroughOptions settings = null;
+ CollectionRuleActionOptions actionOptions = null;
await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
{
CollectionRuleOptions options = rootOptions.CreateCollectionRule(DefaultRuleName)
.AddPassThroughAction("a1", ConfigurationTokenParser.HostNameReference, ConfigurationTokenParser.UnixTimeReference, "test")
.SetStartupTrigger();
- settings = (PassThroughOptions)options.Actions.Last().Settings;
+ actionOptions = options.Actions.Last();
}, host =>
{
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(TimeoutMs);
@@ -196,14 +197,15 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
CollectionRuleOptions ruleOptions = host.Services.GetRequiredService>().Get(DefaultRuleName);
ILogger logger = host.Services.GetRequiredService>();
MockTimeProvider timeProvider = host.Services.GetRequiredService() as MockTimeProvider;
+ ICollectionRuleActionOperations actionOperations = host.Services.GetRequiredService();
const string hostName = "exampleHost";
Guid instanceId = Guid.NewGuid();
HostInfo hostInfo = new HostInfo(hostName, timeProvider);
CollectionRuleContext context = new(DefaultRuleName, ruleOptions, new TestProcessInfo(instanceId), hostInfo, logger);
- ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context);
- PassThroughOptions newSettings = (PassThroughOptions)analyzer.SubstituteOptionValues(new Dictionary(), 1, settings);
+ ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context, actionOperations);
+ PassThroughOptions newSettings = (PassThroughOptions)analyzer.SubstituteOptionValues(new Dictionary(), 1, actionOptions);
Assert.Equal(hostName, newSettings.Input1);
Assert.Equal(hostInfo.TimeProvider.GetUtcNow().ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture), newSettings.Input2);
@@ -223,7 +225,7 @@ public async Task InvalidTokenReferenceTest()
string a2input3 = "$(Actions.a1.MissingResult)";
LogRecord record = new LogRecord();
- PassThroughOptions settings = null;
+ CollectionRuleActionOptions actionOptions = null;
await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
{
CollectionRuleOptions options = rootOptions.CreateCollectionRule(DefaultRuleName)
@@ -231,7 +233,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
.AddPassThroughAction("a2", a2input1, a2input2, a2input3)
.SetStartupTrigger();
- settings = (PassThroughOptions)options.Actions.Last().Settings;
+ actionOptions = options.Actions.Last();
}, host =>
{
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(TimeoutMs);
@@ -239,13 +241,14 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
CollectionRuleOptions ruleOptions = host.Services.GetRequiredService>().Get(DefaultRuleName);
ILogger logger = host.Services.GetRequiredService>();
TimeProvider timeProvider = host.Services.GetRequiredService();
+ ICollectionRuleActionOperations actionOperations = host.Services.GetRequiredService();
Guid instanceId = Guid.NewGuid();
CollectionRuleContext context = new(DefaultRuleName, ruleOptions, new TestProcessInfo(instanceId), HostInfo.GetCurrent(timeProvider), logger);
- ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context);
+ ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context, actionOperations);
analyzer.GetActionDependencies(1);
- analyzer.SubstituteOptionValues(new Dictionary(), 1, settings);
+ analyzer.SubstituteOptionValues(new Dictionary(), 1, actionOptions);
Assert.Equal(3, record.Events.Count);
Assert.Equal(LoggingEventIds.InvalidActionReferenceToken.Id(), record.Events[0].EventId.Id);
@@ -264,27 +267,28 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
[Fact]
public async Task RuntimeIdReferenceTest()
{
- PassThroughOptions settings = null;
+ CollectionRuleActionOptions actionOptions = null;
await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions =>
{
CollectionRuleOptions options = rootOptions.CreateCollectionRule(DefaultRuleName)
.AddPassThroughAction("a1", ConfigurationTokenParser.RuntimeIdReference, "test", "test")
.SetStartupTrigger();
- settings = (PassThroughOptions)options.Actions.Last().Settings;
- }, host =>
+ actionOptions = options.Actions.Last();
+ }, host =>
{
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(TimeoutMs);
CollectionRuleOptions ruleOptions = host.Services.GetRequiredService>().Get(DefaultRuleName);
ILogger logger = host.Services.GetRequiredService>();
TimeProvider timeProvider = host.Services.GetRequiredService();
+ ICollectionRuleActionOperations actionOperations = host.Services.GetRequiredService();
Guid instanceId = Guid.NewGuid();
CollectionRuleContext context = new(DefaultRuleName, ruleOptions, new TestProcessInfo(instanceId), HostInfo.GetCurrent(timeProvider), logger);
- ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context);
- PassThroughOptions newSettings = (PassThroughOptions)analyzer.SubstituteOptionValues(new Dictionary(), 1, settings);
+ ActionOptionsDependencyAnalyzer analyzer = ActionOptionsDependencyAnalyzer.Create(context, actionOperations);
+ PassThroughOptions newSettings = (PassThroughOptions)analyzer.SubstituteOptionValues(new Dictionary(), 1, actionOptions);
Assert.Equal(instanceId.ToString("D"), newSettings.Input1);
diff --git a/src/Tools/dotnet-monitor/CommonOptionsExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CommonOptionsExtensions.cs
similarity index 95%
rename from src/Tools/dotnet-monitor/CommonOptionsExtensions.cs
rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CommonOptionsExtensions.cs
index 718ffa4f27a..0a4fe8dfbce 100644
--- a/src/Tools/dotnet-monitor/CommonOptionsExtensions.cs
+++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CommonOptionsExtensions.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable enable
@@ -6,6 +6,7 @@
#if UNITTEST
using Microsoft.Diagnostics.Monitoring.TestCommon;
#endif
+using Microsoft.Diagnostics.Tools.Monitor;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections;
@@ -15,7 +16,7 @@
using System.Reflection;
using System.Text;
-namespace Microsoft.Diagnostics.Tools.Monitor
+namespace Microsoft.Diagnostics.Monitoring.Tool.UnitTests
{
internal static class CommonOptionsExtensions
{
@@ -118,7 +119,8 @@ private static void MapValue(object? value, string valueName, string separator,
valueType.IsEnum ||
typeof(Guid) == valueType ||
typeof(string) == valueType ||
- typeof(TimeSpan) == valueType)
+ typeof(TimeSpan) == valueType ||
+ typeof(Uri) == valueType)
{
map.Add(
valueName,
diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ConfigurationTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ConfigurationTests.cs
index 25c2f68d179..e8020bd255b 100644
--- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ConfigurationTests.cs
+++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ConfigurationTests.cs
@@ -5,6 +5,7 @@
using Microsoft.Diagnostics.Monitoring.TestCommon;
using Microsoft.Diagnostics.Tools.Monitor;
using Microsoft.Diagnostics.Tools.Monitor.Auth;
+using Microsoft.Diagnostics.Tools.Monitor.CollectionRules;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -363,6 +364,132 @@ private string WriteAndRetrieveConfiguration(IConfiguration configuration, bool
}
}
+ [Theory]
+ [MemberData(nameof(GetTriggerOptionsTestData))]
+ public void ConfigurationMappingTriggerTest(Type triggerOptionsType, string triggerTypeName)
+ {
+ var actionData = GetActionOptionsTestData().First();
+ var actionType = (Type)actionData[0];
+ var actionName = (string)actionData[1];
+
+ var optionsFactory = new TestOptionsFactory(
+ triggerOptionsType,
+ actionType,
+ triggerTypeName,
+ actionName);
+
+ var rootOptions = optionsFactory.CreateRootOptions();
+
+ ValidateOptionsMapping(rootOptions);
+ }
+
+ [Theory]
+ [MemberData(nameof(GetActionOptionsTestData))]
+ public void ConfigurationMappingActionTest(Type actionOptionsType, string actionTypeName)
+ {
+ var triggerData = GetTriggerOptionsTestData().First();
+ var triggerType = (Type)triggerData[0];
+ var triggerName = (string)triggerData[1];
+
+ var optionsFactory = new TestOptionsFactory(
+ triggerType,
+ actionOptionsType,
+ triggerName,
+ actionTypeName);
+
+ var rootOptions = optionsFactory.CreateRootOptions();
+
+ ValidateOptionsMapping(rootOptions);
+ }
+
+ private static void ValidateOptionsMapping(RootOptions rootOptions)
+ {
+ var optionsMapper = new CommonOptionsMapper();
+
+ IDictionary expectedConfigurationValues = rootOptions.ToConfigurationValues();
+ var configurationValues = optionsMapper.ToConfigurationValues(rootOptions);
+ ValidateMapping(expectedConfigurationValues, configurationValues);
+
+ IDictionary expectedEnvironmentConfiguration = rootOptions.ToEnvironmentConfiguration();
+ var environmentConfiguration = optionsMapper.ToEnvironmentConfiguration(rootOptions);
+ ValidateMapping(expectedEnvironmentConfiguration, environmentConfiguration);
+
+ Assert.Equal(expectedEnvironmentConfiguration.Count, environmentConfiguration.Count);
+ IDictionary expectedKeyPerFileConfiguration = rootOptions.ToKeyPerFileConfiguration();
+ var keyPerFileConfiguration = optionsMapper.ToKeyPerFileConfiguration(rootOptions);
+
+ ValidateMapping(expectedKeyPerFileConfiguration, keyPerFileConfiguration);
+
+ static void ValidateMapping(IDictionary expected, IDictionary actual)
+ {
+ foreach (var kvp in expected)
+ {
+ Assert.True(actual.TryGetValue(kvp.Key, out string value),
+ $"Key {kvp.Key} not found in configuration values.");
+ Assert.Equal(kvp.Value, value);
+ }
+
+ Assert.Equal(expected.Count, actual.Count);
+ }
+ }
+
+ public static IEnumerable