Skip to content

Commit 543690b

Browse files
committed
Unit test
1 parent 1ffeb5e commit 543690b

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
lines changed

src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/TestAppScenarios.cs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public static class SubScenarios
6565
public const string AggregateException = nameof(AggregateException);
6666
public const string ReflectionTypeLoadException = nameof(ReflectionTypeLoadException);
6767
public const string HiddenFramesExceptionCommand = nameof(HiddenFramesExceptionCommand);
68+
public const string MultiPhase = nameof(MultiPhase);
6869
}
6970

7071
public static class Commands

src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/ExceptionsTests.cs

+76-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.Diagnostics.Monitoring.WebApi;
1313
using Microsoft.Diagnostics.Monitoring.WebApi.Models;
1414
using Microsoft.Extensions.DependencyInjection;
15+
using Microsoft.Extensions.Logging;
1516
using System;
1617
using System.Collections.Generic;
1718
using System.IO;
@@ -876,6 +877,79 @@ await ScenarioRunner.SingleTarget(
876877
});
877878
}
878879

880+
[Fact]
881+
public async Task Exceptions_ResetState()
882+
{
883+
DiagnosticPortHelper.Generate(
884+
DiagnosticPortConnectionMode.Listen,
885+
out DiagnosticPortConnectionMode appConnectionMode,
886+
out string diagnosticPortPath);
887+
888+
Func<Task<(MonitorCollectRunner Runner, HttpClient Client, ApiClient ApiClient)>> createMonitorRunner = async () =>
889+
{
890+
MonitorCollectRunner toolRunner = new(_outputHelper);
891+
toolRunner.ConnectionModeViaCommandLine = DiagnosticPortConnectionMode.Listen;
892+
toolRunner.DiagnosticPortPath = diagnosticPortPath;
893+
toolRunner.DisableAuthentication = true;
894+
toolRunner.ConfigurationFromEnvironment.EnableInProcessFeatures();
895+
896+
await toolRunner.StartAsync();
897+
HttpClient httpClient = await toolRunner.CreateHttpClientDefaultAddressAsync(_httpClientFactory);
898+
ApiClient apiClient = new(_outputHelper, httpClient);
899+
900+
return (toolRunner, httpClient, apiClient);
901+
};
902+
903+
var result = await createMonitorRunner();
904+
await using MonitorCollectRunner firstRunner = result.Runner;
905+
using HttpClient firstClient = result.Client;
906+
ApiClient apiClient = result.ApiClient;
907+
908+
await using AppRunner appRunner = new(_outputHelper, Assembly.GetExecutingAssembly());
909+
appRunner.ProfilerLogLevel = LogLevel.Information.ToString("G");
910+
appRunner.ConnectionMode = appConnectionMode;
911+
appRunner.DiagnosticPortPath = diagnosticPortPath;
912+
appRunner.ScenarioName = TestAppScenarios.Exceptions.Name;
913+
appRunner.SubScenarioName = TestAppScenarios.Exceptions.SubScenarios.MultiPhase;
914+
appRunner.EnableMonitorStartupHook = true;
915+
916+
await appRunner.ExecuteAsync(async () =>
917+
{
918+
await GetExceptions(apiClient, appRunner, ExceptionFormat.PlainText);
919+
920+
ValidateSingleExceptionText(
921+
SystemInvalidOperationException,
922+
ExceptionMessage,
923+
FrameTypeName,
924+
FrameMethodName,
925+
new List<string> { SimpleFrameParameterType, SimpleFrameParameterType });
926+
927+
await firstRunner.StopAsync();
928+
await firstRunner.DisposeAsync();
929+
930+
result = await createMonitorRunner();
931+
await using MonitorCollectRunner secondRunner = result.Runner;
932+
using HttpClient secondClient = result.Client;
933+
ApiClient secondApiClient = result.ApiClient;
934+
935+
// We cannot resume the scenario immediately against the second runner.
936+
// If the target application throws the second exception while we are starting up, it will be missed.
937+
// We wait until the process is perceived by dotnet-monitor.
938+
int appPid = await appRunner.ProcessIdTask;
939+
940+
_ = await secondApiClient.GetProcessWithRetryAsync(_outputHelper, pid: appPid);
941+
942+
await GetExceptions(secondApiClient, appRunner, ExceptionFormat.PlainText);
943+
944+
ValidateSingleExceptionText(
945+
SystemInvalidOperationException,
946+
ExceptionMessage,
947+
FrameTypeName,
948+
FrameMethodName,
949+
new List<string> { SimpleFrameParameterType, SimpleFrameParameterType });
950+
});
951+
}
952+
879953
private void ValidateMultipleExceptionsText(int exceptionsCount, List<string> exceptionTypes)
880954
{
881955
var exceptions = exceptionsResult.Split(new[] { FirstChanceExceptionMessage }, StringSplitOptions.RemoveEmptyEntries);
@@ -979,15 +1053,15 @@ private async Task GetExceptions(ApiClient apiClient, AppRunner appRunner, Excep
9791053
int processId = await appRunner.ProcessIdTask;
9801054

9811055
await RetryUtilities.RetryAsync(
982-
() => CaptureExtensions(apiClient, processId, format, configuration),
1056+
() => CaptureExceptions(apiClient, processId, format, configuration),
9831057
shouldRetry: (Exception ex) => ex is ArgumentException,
9841058
maxRetryCount: 5,
9851059
outputHelper: _outputHelper);
9861060

9871061
await appRunner.SendCommandAsync(TestAppScenarios.Exceptions.Commands.End);
9881062
}
9891063

990-
private async Task CaptureExtensions(ApiClient apiClient, int processId, ExceptionFormat format, ExceptionsConfiguration configuration)
1064+
private async Task CaptureExceptions(ApiClient apiClient, int processId, ExceptionFormat format, ExceptionsConfiguration configuration)
9911065
{
9921066
await Task.Delay(500);
9931067

src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/Scenarios/ExceptionsScenario.cs

+21
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ public static Command Command()
6868
Command hiddenFramesExceptionCommand = new(TestAppScenarios.Exceptions.SubScenarios.HiddenFramesExceptionCommand);
6969
hiddenFramesExceptionCommand.SetAction(HiddenFramesExceptionAsync);
7070

71+
Command multiPhaseCommand = new(TestAppScenarios.Exceptions.SubScenarios.MultiPhase);
72+
multiPhaseCommand.SetAction(MultiPhase);
73+
7174
Command scenarioCommand = new(TestAppScenarios.Exceptions.Name);
7275
scenarioCommand.Subcommands.Add(singleExceptionCommand);
7376
scenarioCommand.Subcommands.Add(multipleExceptionsCommand);
@@ -86,6 +89,7 @@ public static Command Command()
8689
scenarioCommand.Subcommands.Add(aggregateExceptionCommand);
8790
scenarioCommand.Subcommands.Add(reflectionTypeLoadExceptionCommand);
8891
scenarioCommand.Subcommands.Add(hiddenFramesExceptionCommand);
92+
scenarioCommand.Subcommands.Add(multiPhaseCommand);
8993
return scenarioCommand;
9094
}
9195

@@ -103,6 +107,23 @@ public static Task<int> SingleExceptionAsync(ParseResult result, CancellationTok
103107
}, token);
104108
}
105109

110+
public static Task<int> MultiPhase(ParseResult result, CancellationToken token)
111+
{
112+
return ScenarioHelpers.RunScenarioAsync(async logger =>
113+
{
114+
await ScenarioHelpers.WaitForCommandAsync(TestAppScenarios.Exceptions.Commands.Begin, logger);
115+
ThrowAndCatchInvalidOperationException();
116+
await ScenarioHelpers.WaitForCommandAsync(TestAppScenarios.Exceptions.Commands.End, logger);
117+
118+
// This subscenario is designed for a situation where the tool runner is terminated and restarted.
119+
120+
await ScenarioHelpers.WaitForCommandAsync(TestAppScenarios.Exceptions.Commands.Begin, logger);
121+
ThrowAndCatchInvalidOperationException();
122+
await ScenarioHelpers.WaitForCommandAsync(TestAppScenarios.Exceptions.Commands.End, logger);
123+
return 0;
124+
}, token);
125+
}
126+
106127
public static Task<int> MultipleExceptionsAsync(ParseResult result, CancellationToken token)
107128
{
108129
return ScenarioHelpers.RunScenarioAsync(async logger =>

0 commit comments

Comments
 (0)