diff --git a/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/Browser/WasmBrowserTestRunner.cs b/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/Browser/WasmBrowserTestRunner.cs index c5e834706..a8e8e9e5c 100644 --- a/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/Browser/WasmBrowserTestRunner.cs +++ b/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/Browser/WasmBrowserTestRunner.cs @@ -167,7 +167,7 @@ private async Task RunConsoleMessagesPump(WebSocket socket, TaskCompletionSource var line = Encoding.UTF8.GetString(mem.GetBuffer(), 0, (int)mem.Length); line += Environment.NewLine; - _messagesProcessor.Invoke(line); + _messagesProcessor.ProcessOutMessage(line, true); mem.SetLength(0); mem.Seek(0, SeekOrigin.Begin); } @@ -221,7 +221,7 @@ private void RunSeleniumLogMessagePump(IWebDriver driver, CancellationToken toke var match = s_consoleLogRegex.Match(Regex.Unescape(logEntry.Message)); string msg = match.Success ? match.Groups[1].Value : logEntry.Message; - _messagesProcessor.Invoke(msg); + _messagesProcessor.ProcessOutMessage(msg, false); } } } diff --git a/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/JS/WasmTestCommand.cs b/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/JS/WasmTestCommand.cs index 2f8693abe..6bf74972d 100644 --- a/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/JS/WasmTestCommand.cs +++ b/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/JS/WasmTestCommand.cs @@ -132,7 +132,7 @@ protected override async Task InvokeInternal(ILogger logger) engineBinary, engineArgs, log: new CallbackLog(m => logger.LogInformation(m)), - stdoutLog: new CallbackLog(logProcessor.Invoke), + stdoutLog: new CallbackLog(logProcessor.ProcessOutMessage), stderrLog: new CallbackLog(logProcessor.ProcessErrorMessage), Arguments.Timeout); diff --git a/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/WasmTestMessagesProcessor.cs b/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/WasmTestMessagesProcessor.cs index 937264920..1acd6ee22 100644 --- a/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/WasmTestMessagesProcessor.cs +++ b/src/Microsoft.DotNet.XHarness.CLI/Commands/WASM/WasmTestMessagesProcessor.cs @@ -5,8 +5,8 @@ using System; using System.IO; using System.Text.Json; +using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Xml.Linq; using Microsoft.Extensions.Logging; #nullable enable @@ -14,7 +14,8 @@ namespace Microsoft.DotNet.XHarness.CLI.Commands.Wasm { public class WasmTestMessagesProcessor { - private MemoryStream? _xmlResultsMemoryStream; + private static Regex xmlRx = new Regex(@"^STARTRESULTXML ([0-9]*) ([^ ]*) ENDRESULTXML", RegexOptions.Compiled | RegexOptions.CultureInvariant); + private bool _isXmlFromWebSocket; private StreamWriter? _xmlResultsFileWriter; private readonly StreamWriter _stdoutFileWriter; private readonly string _xmlResultsFilePath; @@ -41,12 +42,16 @@ public WasmTestMessagesProcessor(string xmlResultsFilePath, string stdoutFilePat _errorScanner = new Lazy(() => new ErrorPatternScanner(errorPatternsFile, logger)); } } + public void ProcessOutMessage(string message) + { + ProcessOutMessage(message, false); + } - public void Invoke(string message) + public void ProcessOutMessage(string message, bool isWebSocket) { try { - InvokeInternal(message); + InvokeInternal(message, isWebSocket); } catch (Exception ex) when (WasmExitReceivedTcs.Task.IsCompletedSuccessfully) { @@ -55,7 +60,7 @@ public void Invoke(string message) } } - private void InvokeInternal(string message) + private void InvokeInternal(string message, bool isWebSocket) { WasmLogMessage? logMessage = null; string line; @@ -77,16 +82,18 @@ private void InvokeInternal(string message) line = message.TrimEnd(); } - if (_xmlResultsFileWriter == null) + var match = xmlRx.Match(line); + if (match.Success) { - if (line.Contains("STARTRESULTXML")) + using (var stream = new FileStream(_xmlResultsFilePath, FileMode.CreateNew)) { - _logger.LogDebug("Reached start of testResults.xml"); - _xmlResultsMemoryStream = new MemoryStream(); - _xmlResultsFileWriter = new StreamWriter(_xmlResultsMemoryStream); - return; + var bytes = System.Convert.FromBase64String(match.Groups[2].Value); + stream.Write(bytes); } - else if (line.StartsWith("[PASS]") || line.StartsWith("[SKIP]")) + } + else + { + if (line.StartsWith("[PASS]") || line.StartsWith("[SKIP]")) { _logger.LogDebug(line); } @@ -113,38 +120,6 @@ private void InvokeInternal(string message) if (_stdoutFileWriter.BaseStream.CanWrite) _stdoutFileWriter.WriteLine(line); } - else - { - if (line.Contains("ENDRESULTXML")) - { - _logger.LogDebug($"Reached end of {_xmlResultsFilePath}"); - _xmlResultsFileWriter.Flush(); - _xmlResultsMemoryStream!.Seek(0, SeekOrigin.Begin); - try - { - // we validate it, to make sure it's not corrupted. - var testResults = XElement.Load(_xmlResultsMemoryStream); - using (var testResultsFile = File.CreateText(_xmlResultsFilePath)) - { - testResults.Save(testResultsFile); - _logger.LogInformation($"Written {_xmlResultsMemoryStream.Length} original bytes of {_xmlResultsFilePath} as {testResultsFile.BaseStream.Length} formatted bytes"); - }; - } - catch (Exception ex) - { - _logger.LogError($"Error while saving testResults.xml {ex}"); - throw; - } - _xmlResultsFileWriter.Dispose(); - _xmlResultsFileWriter = null; - _xmlResultsMemoryStream.Dispose(); - _xmlResultsMemoryStream = null; - return; - } - - if (_xmlResultsFileWriter?.BaseStream.CanWrite == true) - _xmlResultsFileWriter.WriteLine(line); - } // the test runner writes this as the last line, // after the tests have run, and the xml results file diff --git a/src/Microsoft.DotNet.XHarness.TestRunners.Xunit/ThreadlessXunitTestRunner.cs b/src/Microsoft.DotNet.XHarness.TestRunners.Xunit/ThreadlessXunitTestRunner.cs index bb74f19bd..68c48624f 100644 --- a/src/Microsoft.DotNet.XHarness.TestRunners.Xunit/ThreadlessXunitTestRunner.cs +++ b/src/Microsoft.DotNet.XHarness.TestRunners.Xunit/ThreadlessXunitTestRunner.cs @@ -1,28 +1,28 @@ -// 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. - -#nullable enable - -using System; -using System.Collections.Generic; +// 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. + +#nullable enable + +using System; +using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Reflection; +using System.Linq; +using System.Reflection; using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; - -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.DotNet.XHarness.TestRunners.Xunit -{ - internal class ThreadlessXunitTestRunner - { - public static async Task Run(string assemblyFileName, bool printXml, XunitFilters filters) - { +using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; + +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.XHarness.TestRunners.Xunit +{ + internal class ThreadlessXunitTestRunner + { + public static async Task Run(string assemblyFileName, bool printXml, XunitFilters filters) + { try { var configuration = new TestAssemblyConfiguration() { ShadowCopy = false, ParallelizeAssembly = false, ParallelizeTestCollections = false, MaxParallelThreads = 1, PreEnumerateTheories = false }; @@ -72,27 +72,16 @@ public static async Task Run(string assemblyFileName, bool printXml, XunitF { var resultsXml = new XElement("assemblies"); resultsXml.Add(resultsXmlAssembly); - using (var ms = new MemoryStream()) + int length; + using (var sw = new StringWriter()) { - using (var tw = new StreamWriter(ms, Encoding.UTF8, 100*1024, true)) - { - // no new line. make it single line, single WS message - resultsXml.Save(tw, SaveOptions.DisableFormatting); - } - ms.Seek(0, SeekOrigin.Begin); - using (var stdout = Console.OpenStandardOutput()) - { - using (var twc = new StreamWriter(stdout)) - { - twc.WriteLine($"STARTRESULTXML {ms.Length}"); - twc.Flush(); - ms.CopyTo(stdout, 100 * 1024); - twc.WriteLine(); - twc.WriteLine("ENDRESULTXML"); - } - } - Console.WriteLine($"Finished writing {ms.Length} bytes of RESULTXML"); + resultsXml.Save(sw); + var bytes = System.Text.Encoding.UTF8.GetBytes(sw.ToString()); + length=bytes.Length; + var base64 = Convert.ToBase64String(bytes, Base64FormattingOptions.None); + Console.WriteLine($"STARTRESULTXML {length} {base64} ENDRESULTXML"); } + Console.WriteLine($"Finished writing {length} bytes of RESULTXML"); } var failed = resultsSink.ExecutionSummary.Failed > 0 || resultsSink.ExecutionSummary.Errors > 0; @@ -102,45 +91,45 @@ public static async Task Run(string assemblyFileName, bool printXml, XunitF { Console.Error.WriteLine($"ThreadlessXunitTestRunner failed: {ex}"); return 2; - } - } - } - - internal class ThreadlessXunitDiscoverer : global::Xunit.Sdk.XunitTestFrameworkDiscoverer - { - public ThreadlessXunitDiscoverer(IAssemblyInfo assemblyInfo, ISourceInformationProvider sourceProvider, IMessageSink diagnosticMessageSink) - : base(assemblyInfo, sourceProvider, diagnosticMessageSink) - { - } - - public void FindWithoutThreads(bool includeSourceInformation, IMessageSink discoveryMessageSink, ITestFrameworkDiscoveryOptions discoveryOptions) - { - using (var messageBus = new global::Xunit.Sdk.SynchronousMessageBus(discoveryMessageSink)) - { - foreach (var type in AssemblyInfo.GetTypes(includePrivateTypes: false).Where(IsValidTestClass)) - { - var testClass = CreateTestClass(type); - if (!FindTestsForType(testClass, includeSourceInformation, messageBus, discoveryOptions)) - { - break; - } - } - - messageBus.QueueMessage(new global::Xunit.Sdk.DiscoveryCompleteMessage()); - } - } - } - - internal class ConsoleDiagnosticMessageSink : global::Xunit.Sdk.LongLivedMarshalByRefObject, IMessageSink - { - public bool OnMessage(IMessageSinkMessage message) - { - if (message is IDiagnosticMessage diagnosticMessage) - { - Console.WriteLine(diagnosticMessage.Message); - } - - return true; - } - } -} + } + } + } + + internal class ThreadlessXunitDiscoverer : global::Xunit.Sdk.XunitTestFrameworkDiscoverer + { + public ThreadlessXunitDiscoverer(IAssemblyInfo assemblyInfo, ISourceInformationProvider sourceProvider, IMessageSink diagnosticMessageSink) + : base(assemblyInfo, sourceProvider, diagnosticMessageSink) + { + } + + public void FindWithoutThreads(bool includeSourceInformation, IMessageSink discoveryMessageSink, ITestFrameworkDiscoveryOptions discoveryOptions) + { + using (var messageBus = new global::Xunit.Sdk.SynchronousMessageBus(discoveryMessageSink)) + { + foreach (var type in AssemblyInfo.GetTypes(includePrivateTypes: false).Where(IsValidTestClass)) + { + var testClass = CreateTestClass(type); + if (!FindTestsForType(testClass, includeSourceInformation, messageBus, discoveryOptions)) + { + break; + } + } + + messageBus.QueueMessage(new global::Xunit.Sdk.DiscoveryCompleteMessage()); + } + } + } + + internal class ConsoleDiagnosticMessageSink : global::Xunit.Sdk.LongLivedMarshalByRefObject, IMessageSink + { + public bool OnMessage(IMessageSinkMessage message) + { + if (message is IDiagnosticMessage diagnosticMessage) + { + Console.WriteLine(diagnosticMessage.Message); + } + + return true; + } + } +}