From b9dd000ae0a10336f08adfd8a95e468d2a80ff58 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Mon, 14 Sep 2026 11:23:57 -0400 Subject: [PATCH 1/2] Make EventLogs tests order-independent Match expected log records by message instead of assuming global ordering across EventPipe producer threads, and re-enable the previously skipped coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2d5c60f7-9c89-42e6-b9fc-04ef78c8f8d8 --- .../EventLogsPipelineUnitTests.cs | 150 ++++++++---------- 1 file changed, 62 insertions(+), 88 deletions(-) diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs index 1b1d00e0e8..47e540cc46 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; +using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -43,32 +43,26 @@ public EventLogsPipelineUnitTests(ITestOutputHelper output) [SkippableTheory, MemberData(nameof(Configurations))] public async Task TestLogsAllCategoriesAllLevels(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - using Stream outputStream = await GetLogsAsync(config, settings => { settings.UseAppFilters = false; }); Assert.True(outputStream.Length > 0, "No data written by logging process."); - using StreamReader reader = new(outputStream); - - ValidateLoggerRemoteCategoryInformationMessage(reader); - ValidateLoggerRemoteCategoryWarningMessage(reader); - ValidateAppLoggerCategoryInformationMessage(reader); - ValidateAppLoggerCategoryWarningMessage(reader); - ValidateAppLoggerCategoryErrorMessage(reader); + IReadOnlyList results = ReadResults(outputStream); - Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); + Assert.Equal(6, results.Count); + ValidateLoggerRemoteCategoryInformationMessage(results); + ValidateLoggerRemoteCategoryWarningMessage(results); + ValidateAppLoggerCategoryInformationMessage(results); + ValidateAppLoggerCategoryWarningMessage(results); + ValidateAppLoggerCategoryErrorMessage(results); } /// /// Test that log events at or above the default level are collected. /// - [SkippableTheory(Skip = "https://github.com/dotnet/diagnostics/issues/2541"), MemberData(nameof(Configurations))] + [SkippableTheory, MemberData(nameof(Configurations))] public async Task TestLogsAllCategoriesDefaultLevel(TestConfiguration config) { using Stream outputStream = await GetLogsAsync(config, settings => { @@ -78,26 +72,20 @@ public async Task TestLogsAllCategoriesDefaultLevel(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - using StreamReader reader = new(outputStream); - - ValidateLoggerRemoteCategoryWarningMessage(reader); - ValidateAppLoggerCategoryWarningMessage(reader); - ValidateAppLoggerCategoryErrorMessage(reader); + IReadOnlyList results = ReadResults(outputStream); - Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); + Assert.Equal(3, results.Count); + ValidateLoggerRemoteCategoryWarningMessage(results); + ValidateAppLoggerCategoryWarningMessage(results); + ValidateAppLoggerCategoryErrorMessage(results); } /// /// Test that log events at the default level are collected for categories without a specified level. /// - [SkippableTheory(Skip = "Unreliable test https://github.com/dotnet/diagnostics/issues/3143"), MemberData(nameof(Configurations))] + [SkippableTheory, MemberData(nameof(Configurations))] public async Task TestLogsAllCategoriesDefaultLevelFallback(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - using Stream outputStream = await GetLogsAsync(config, settings => { settings.UseAppFilters = false; settings.LogLevel = LogLevel.Error; @@ -110,13 +98,12 @@ public async Task TestLogsAllCategoriesDefaultLevelFallback(TestConfiguration co Assert.True(outputStream.Length > 0, "No data written by logging process."); - using StreamReader reader = new(outputStream); + IReadOnlyList results = ReadResults(outputStream); - ValidateLoggerRemoteCategoryInformationMessage(reader); - ValidateLoggerRemoteCategoryWarningMessage(reader); - ValidateAppLoggerCategoryErrorMessage(reader); - - Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); + Assert.Equal(4, results.Count); + ValidateLoggerRemoteCategoryInformationMessage(results); + ValidateLoggerRemoteCategoryWarningMessage(results); + ValidateAppLoggerCategoryErrorMessage(results); } /// @@ -143,28 +130,22 @@ public async Task TestLogsAllCategoriesDefaultLevelNoneNotSupported(TestConfigur [SkippableTheory, MemberData(nameof(Configurations))] public async Task TestLogsUseAppFilters(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - using Stream outputStream = await GetLogsAsync(config); Assert.True(outputStream.Length > 0, "No data written by logging process."); - using StreamReader reader = new(outputStream); + IReadOnlyList results = ReadResults(outputStream); - ValidateAppLoggerCategoryWarningMessage(reader); - ValidateAppLoggerCategoryErrorMessage(reader); - - Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); + Assert.Equal(2, results.Count); + ValidateAppLoggerCategoryWarningMessage(results); + ValidateAppLoggerCategoryErrorMessage(results); } /// /// Test that log events are collected for the categories and levels specified by the application /// and for the categories and levels specified in the filter specs. /// - [SkippableTheory(Skip = "https://github.com/dotnet/diagnostics/issues/2541"), MemberData(nameof(Configurations))] + [SkippableTheory, MemberData(nameof(Configurations))] public async Task TestLogsUseAppFiltersAndFilterSpecs(TestConfiguration config) { using Stream outputStream = await GetLogsAsync(config, settings => { @@ -176,13 +157,12 @@ public async Task TestLogsUseAppFiltersAndFilterSpecs(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - using StreamReader reader = new(outputStream); + IReadOnlyList results = ReadResults(outputStream); - ValidateLoggerRemoteCategoryWarningMessage(reader); - ValidateAppLoggerCategoryWarningMessage(reader); - ValidateAppLoggerCategoryErrorMessage(reader); - - Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); + Assert.Equal(3, results.Count); + ValidateLoggerRemoteCategoryWarningMessage(results); + ValidateAppLoggerCategoryWarningMessage(results); + ValidateAppLoggerCategoryErrorMessage(results); } /// @@ -191,11 +171,6 @@ public async Task TestLogsUseAppFiltersAndFilterSpecs(TestConfiguration config) [SkippableTheory, MemberData(nameof(Configurations))] public async Task TestLogsWildcardCategory(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - using Stream outputStream = await GetLogsAsync(config, settings => { settings.UseAppFilters = false; settings.LogLevel = LogLevel.Critical; @@ -208,12 +183,11 @@ public async Task TestLogsWildcardCategory(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - using StreamReader reader = new(outputStream); + IReadOnlyList results = ReadResults(outputStream); - ValidateAppLoggerCategoryWarningMessage(reader); - ValidateAppLoggerCategoryErrorMessage(reader); - - Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); + Assert.Equal(2, results.Count); + ValidateAppLoggerCategoryWarningMessage(results); + ValidateAppLoggerCategoryErrorMessage(results); } private async Task GetLogsAsync(TestConfiguration config, Action settingsCallback = null) @@ -240,12 +214,24 @@ private async Task GetLogsAsync(TestConfiguration config, Action ReadResults(Stream stream) { - string message = reader.ReadLine(); - Assert.NotNull(message); + // The tracee emits from multiple threads, so EventPipe delivery order is not deterministic. + using StreamReader reader = new(stream); + List results = new(); + string message; + while ((message = reader.ReadLine()) != null) + { + LoggerTestResult result = JsonSerializer.Deserialize(message); + Assert.NotNull(result); + results.Add(result); + } + return results; + } - LoggerTestResult result = JsonSerializer.Deserialize(message); + private static void ValidateLoggerRemoteCategoryInformationMessage(IReadOnlyList results) + { + LoggerTestResult result = GetResult(results, "Some warning message with 6"); Assert.Equal("Some warning message with 6", result.Message); Assert.Equal(LoggerRemoteTestName, result.Category); Assert.Equal("Information", result.LogLevel); @@ -254,10 +240,7 @@ private static void ValidateLoggerRemoteCategoryInformationMessage(StreamReader Validate(result.Scopes, ("BoolValue", "true"), ("StringValue", "test"), ("IntValue", "5")); Validate(result.Arguments, ("Arg", "6")); - message = reader.ReadLine(); - Assert.NotNull(message); - - result = JsonSerializer.Deserialize(message); + result = GetResult(results, "Some other message with 7"); Assert.Equal("Some other message with 7", result.Message); Assert.Equal(LoggerRemoteTestName, result.Category); Assert.Equal("Information", result.LogLevel); @@ -267,12 +250,9 @@ private static void ValidateLoggerRemoteCategoryInformationMessage(StreamReader Validate(result.Arguments, ("Arg", "7")); } - private static void ValidateLoggerRemoteCategoryWarningMessage(StreamReader reader) + private static void ValidateLoggerRemoteCategoryWarningMessage(IReadOnlyList results) { - string message = reader.ReadLine(); - Assert.NotNull(message); - - LoggerTestResult result = JsonSerializer.Deserialize(message); + LoggerTestResult result = GetResult(results, "Another message"); Assert.Equal("Another message", result.Message); Assert.Equal(LoggerRemoteTestName, result.Category); Assert.Equal("Warning", result.LogLevel); @@ -283,12 +263,9 @@ private static void ValidateLoggerRemoteCategoryWarningMessage(StreamReader read Assert.Equal(1, result.Arguments.Count); } - private static void ValidateAppLoggerCategoryInformationMessage(StreamReader reader) + private static void ValidateAppLoggerCategoryInformationMessage(IReadOnlyList results) { - string message = reader.ReadLine(); - Assert.NotNull(message); - - LoggerTestResult result = JsonSerializer.Deserialize(message); + LoggerTestResult result = GetResult(results, "Information message."); Assert.Equal("Information message.", result.Message); Assert.Equal(AppLoggerCategoryName, result.Category); Assert.Equal("Information", result.LogLevel); @@ -299,12 +276,9 @@ private static void ValidateAppLoggerCategoryInformationMessage(StreamReader rea Assert.Equal(1, result.Arguments.Count); } - private static void ValidateAppLoggerCategoryWarningMessage(StreamReader reader) + private static void ValidateAppLoggerCategoryWarningMessage(IReadOnlyList results) { - string message = reader.ReadLine(); - Assert.NotNull(message); - - LoggerTestResult result = JsonSerializer.Deserialize(message); + LoggerTestResult result = GetResult(results, "Warning message."); Assert.Equal("Warning message.", result.Message); Assert.Equal(AppLoggerCategoryName, result.Category); Assert.Equal("Warning", result.LogLevel); @@ -315,12 +289,9 @@ private static void ValidateAppLoggerCategoryWarningMessage(StreamReader reader) Assert.Equal(1, result.Arguments.Count); } - private static void ValidateAppLoggerCategoryErrorMessage(StreamReader reader) + private static void ValidateAppLoggerCategoryErrorMessage(IReadOnlyList results) { - string message = reader.ReadLine(); - Assert.NotNull(message); - - LoggerTestResult result = JsonSerializer.Deserialize(message); + LoggerTestResult result = GetResult(results, "Error message."); Assert.Equal("Error message.", result.Message); Assert.Equal(AppLoggerCategoryName, result.Category); Assert.Equal("Error", result.LogLevel); @@ -331,6 +302,9 @@ private static void ValidateAppLoggerCategoryErrorMessage(StreamReader reader) Assert.Equal(1, result.Arguments.Count); } + private static LoggerTestResult GetResult(IReadOnlyList results, string message) => + Assert.Single(results, result => result.Message == message); + private static void Validate(IDictionary values, params (string key, object value)[] expectedValues) { Assert.NotNull(values); From a085389567971e09906ed92169e1d979ceb826e6 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Mon, 14 Sep 2026 15:30:35 -0400 Subject: [PATCH 2/2] Initialize logging before EventPipe starts Construct the tracee logger factory before signaling readiness so EventPipe filter updates cannot race options-monitor initialization and drop the initial log records. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2d5c60f7-9c89-42e6-b9fc-04ef78c8f8d8 --- .../Debuggees/EventPipeTracee/Program.cs | 19 +-- .../EventLogsPipelineUnitTests.cs | 123 +++++++++--------- 2 files changed, 74 insertions(+), 68 deletions(-) diff --git a/src/tests/CommonTestRunner/Debuggees/EventPipeTracee/Program.cs b/src/tests/CommonTestRunner/Debuggees/EventPipeTracee/Program.cs index a8251d4406..bc1afbf44a 100644 --- a/src/tests/CommonTestRunner/Debuggees/EventPipeTracee/Program.cs +++ b/src/tests/CommonTestRunner/Debuggees/EventPipeTracee/Program.cs @@ -42,11 +42,13 @@ public static async Task Main(string[] args) Console.WriteLine($"{pid} EventPipeTracee: start process"); Console.Out.Flush(); - // Workaround for https://github.com/dotnet/runtime/issues/127681 - // LoggingEventSource has a static initialization order bug fields are declared after the singleton instance. + // Workaround for https://github.com/dotnet/runtime/issues/127681. + // LoggingEventSource has a static initialization order bug: fields are declared after the singleton instance. // If EventPipe enables the source during or before the LoggingEventSource.Instance constructor, ParseFilterSpec - // produces wrong rules. Force the type initializer to complete before connecting to the pipe (which signals - // the test harness that EventPipe can be enabled). + // produces wrong rules. The pipe connection signals that the test harness can enable EventPipe, so fully + // construct the logger factory and loggers first. This also ensures its filter options monitor is subscribed + // before EventPipe updates the filter specification; otherwise that update can be missed and the application + // filters remain active, dropping the LoggerRemoteTest records. ServiceCollection serviceCollection = new(); serviceCollection.AddLogging(builder => { builder.AddEventSourceLogger(); @@ -55,6 +57,10 @@ public static async Task Main(string[] args) builder.AddFilter(AppLoggerCategoryName, LogLevel.Warning); }); + using ILoggerFactory loggerFactory = serviceCollection.BuildServiceProvider().GetService(); + ILogger customCategoryLogger = loggerFactory.CreateLogger(loggerCategory); + ILogger appCategoryLogger = loggerFactory.CreateLogger(AppLoggerCategoryName); + // Signal that the tracee has started Console.WriteLine($"{pid} EventPipeTracee: connecting to pipe"); Console.Out.Flush(); @@ -62,11 +68,6 @@ public static async Task Main(string[] args) Console.WriteLine($"{pid} EventPipeTracee: connected to pipe"); Console.Out.Flush(); - - using ILoggerFactory loggerFactory = serviceCollection.BuildServiceProvider().GetService(); - ILogger customCategoryLogger = loggerFactory.CreateLogger(loggerCategory); - ILogger appCategoryLogger = loggerFactory.CreateLogger(AppLoggerCategoryName); - using ActivitySource activitySource = useActivitySource ? new ActivitySource("EventPipeTracee.ActivitySource", version: "1.0.0") : null; diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs index 47e540cc46..280a3528d1 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -49,14 +48,15 @@ public async Task TestLogsAllCategoriesAllLevels(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - IReadOnlyList results = ReadResults(outputStream); + using StreamReader reader = new(outputStream); - Assert.Equal(6, results.Count); - ValidateLoggerRemoteCategoryInformationMessage(results); - ValidateLoggerRemoteCategoryWarningMessage(results); - ValidateAppLoggerCategoryInformationMessage(results); - ValidateAppLoggerCategoryWarningMessage(results); - ValidateAppLoggerCategoryErrorMessage(results); + ValidateLoggerRemoteCategoryInformationMessage(reader); + ValidateLoggerRemoteCategoryWarningMessage(reader); + ValidateAppLoggerCategoryInformationMessage(reader); + ValidateAppLoggerCategoryWarningMessage(reader); + ValidateAppLoggerCategoryErrorMessage(reader); + + Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); } /// @@ -72,12 +72,13 @@ public async Task TestLogsAllCategoriesDefaultLevel(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - IReadOnlyList results = ReadResults(outputStream); + using StreamReader reader = new(outputStream); + + ValidateLoggerRemoteCategoryWarningMessage(reader); + ValidateAppLoggerCategoryWarningMessage(reader); + ValidateAppLoggerCategoryErrorMessage(reader); - Assert.Equal(3, results.Count); - ValidateLoggerRemoteCategoryWarningMessage(results); - ValidateAppLoggerCategoryWarningMessage(results); - ValidateAppLoggerCategoryErrorMessage(results); + Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); } /// @@ -98,12 +99,13 @@ public async Task TestLogsAllCategoriesDefaultLevelFallback(TestConfiguration co Assert.True(outputStream.Length > 0, "No data written by logging process."); - IReadOnlyList results = ReadResults(outputStream); + using StreamReader reader = new(outputStream); - Assert.Equal(4, results.Count); - ValidateLoggerRemoteCategoryInformationMessage(results); - ValidateLoggerRemoteCategoryWarningMessage(results); - ValidateAppLoggerCategoryErrorMessage(results); + ValidateLoggerRemoteCategoryInformationMessage(reader); + ValidateLoggerRemoteCategoryWarningMessage(reader); + ValidateAppLoggerCategoryErrorMessage(reader); + + Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); } /// @@ -134,11 +136,12 @@ public async Task TestLogsUseAppFilters(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - IReadOnlyList results = ReadResults(outputStream); + using StreamReader reader = new(outputStream); + + ValidateAppLoggerCategoryWarningMessage(reader); + ValidateAppLoggerCategoryErrorMessage(reader); - Assert.Equal(2, results.Count); - ValidateAppLoggerCategoryWarningMessage(results); - ValidateAppLoggerCategoryErrorMessage(results); + Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); } /// @@ -157,12 +160,13 @@ public async Task TestLogsUseAppFiltersAndFilterSpecs(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - IReadOnlyList results = ReadResults(outputStream); + using StreamReader reader = new(outputStream); - Assert.Equal(3, results.Count); - ValidateLoggerRemoteCategoryWarningMessage(results); - ValidateAppLoggerCategoryWarningMessage(results); - ValidateAppLoggerCategoryErrorMessage(results); + ValidateLoggerRemoteCategoryWarningMessage(reader); + ValidateAppLoggerCategoryWarningMessage(reader); + ValidateAppLoggerCategoryErrorMessage(reader); + + Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); } /// @@ -183,11 +187,12 @@ public async Task TestLogsWildcardCategory(TestConfiguration config) Assert.True(outputStream.Length > 0, "No data written by logging process."); - IReadOnlyList results = ReadResults(outputStream); + using StreamReader reader = new(outputStream); + + ValidateAppLoggerCategoryWarningMessage(reader); + ValidateAppLoggerCategoryErrorMessage(reader); - Assert.Equal(2, results.Count); - ValidateAppLoggerCategoryWarningMessage(results); - ValidateAppLoggerCategoryErrorMessage(results); + Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream."); } private async Task GetLogsAsync(TestConfiguration config, Action settingsCallback = null) @@ -214,24 +219,12 @@ private async Task GetLogsAsync(TestConfiguration config, Action ReadResults(Stream stream) + private static void ValidateLoggerRemoteCategoryInformationMessage(StreamReader reader) { - // The tracee emits from multiple threads, so EventPipe delivery order is not deterministic. - using StreamReader reader = new(stream); - List results = new(); - string message; - while ((message = reader.ReadLine()) != null) - { - LoggerTestResult result = JsonSerializer.Deserialize(message); - Assert.NotNull(result); - results.Add(result); - } - return results; - } + string message = reader.ReadLine(); + Assert.NotNull(message); - private static void ValidateLoggerRemoteCategoryInformationMessage(IReadOnlyList results) - { - LoggerTestResult result = GetResult(results, "Some warning message with 6"); + LoggerTestResult result = JsonSerializer.Deserialize(message); Assert.Equal("Some warning message with 6", result.Message); Assert.Equal(LoggerRemoteTestName, result.Category); Assert.Equal("Information", result.LogLevel); @@ -240,7 +233,10 @@ private static void ValidateLoggerRemoteCategoryInformationMessage(IReadOnlyList Validate(result.Scopes, ("BoolValue", "true"), ("StringValue", "test"), ("IntValue", "5")); Validate(result.Arguments, ("Arg", "6")); - result = GetResult(results, "Some other message with 7"); + message = reader.ReadLine(); + Assert.NotNull(message); + + result = JsonSerializer.Deserialize(message); Assert.Equal("Some other message with 7", result.Message); Assert.Equal(LoggerRemoteTestName, result.Category); Assert.Equal("Information", result.LogLevel); @@ -250,9 +246,12 @@ private static void ValidateLoggerRemoteCategoryInformationMessage(IReadOnlyList Validate(result.Arguments, ("Arg", "7")); } - private static void ValidateLoggerRemoteCategoryWarningMessage(IReadOnlyList results) + private static void ValidateLoggerRemoteCategoryWarningMessage(StreamReader reader) { - LoggerTestResult result = GetResult(results, "Another message"); + string message = reader.ReadLine(); + Assert.NotNull(message); + + LoggerTestResult result = JsonSerializer.Deserialize(message); Assert.Equal("Another message", result.Message); Assert.Equal(LoggerRemoteTestName, result.Category); Assert.Equal("Warning", result.LogLevel); @@ -263,9 +262,12 @@ private static void ValidateLoggerRemoteCategoryWarningMessage(IReadOnlyList results) + private static void ValidateAppLoggerCategoryInformationMessage(StreamReader reader) { - LoggerTestResult result = GetResult(results, "Information message."); + string message = reader.ReadLine(); + Assert.NotNull(message); + + LoggerTestResult result = JsonSerializer.Deserialize(message); Assert.Equal("Information message.", result.Message); Assert.Equal(AppLoggerCategoryName, result.Category); Assert.Equal("Information", result.LogLevel); @@ -276,9 +278,12 @@ private static void ValidateAppLoggerCategoryInformationMessage(IReadOnlyList results) + private static void ValidateAppLoggerCategoryWarningMessage(StreamReader reader) { - LoggerTestResult result = GetResult(results, "Warning message."); + string message = reader.ReadLine(); + Assert.NotNull(message); + + LoggerTestResult result = JsonSerializer.Deserialize(message); Assert.Equal("Warning message.", result.Message); Assert.Equal(AppLoggerCategoryName, result.Category); Assert.Equal("Warning", result.LogLevel); @@ -289,9 +294,12 @@ private static void ValidateAppLoggerCategoryWarningMessage(IReadOnlyList results) + private static void ValidateAppLoggerCategoryErrorMessage(StreamReader reader) { - LoggerTestResult result = GetResult(results, "Error message."); + string message = reader.ReadLine(); + Assert.NotNull(message); + + LoggerTestResult result = JsonSerializer.Deserialize(message); Assert.Equal("Error message.", result.Message); Assert.Equal(AppLoggerCategoryName, result.Category); Assert.Equal("Error", result.LogLevel); @@ -302,9 +310,6 @@ private static void ValidateAppLoggerCategoryErrorMessage(IReadOnlyList results, string message) => - Assert.Single(results, result => result.Message == message); - private static void Validate(IDictionary values, params (string key, object value)[] expectedValues) { Assert.NotNull(values);