diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs index be5a52e878..2ec8c47815 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs @@ -38,6 +38,7 @@ internal sealed class TrxReportGenerator : private readonly IOutputDevice _outputDisplay; private readonly ITestFramework _testFramework; private readonly ITestFrameworkCapabilities _testFrameworkCapabilities; + private readonly ITestApplicationProcessExitCode _testApplicationProcessExitCode; private readonly TrxTestApplicationLifecycleCallbacks? _trxTestApplicationLifecycleCallbacks; private readonly ILogger _logger; private readonly List _tests = []; @@ -62,6 +63,7 @@ public TrxReportGenerator( IOutputDevice outputDisplay, ITestFramework testFramework, ITestFrameworkCapabilities testFrameworkCapabilities, + ITestApplicationProcessExitCode testApplicationProcessExitCode, // Can be null in case of server mode TrxTestApplicationLifecycleCallbacks? trxTestApplicationLifecycleCallbacks, ILogger logger) @@ -75,6 +77,7 @@ public TrxReportGenerator( _outputDisplay = outputDisplay; _testFramework = testFramework; _testFrameworkCapabilities = testFrameworkCapabilities; + _testApplicationProcessExitCode = testApplicationProcessExitCode; _trxTestApplicationLifecycleCallbacks = trxTestApplicationLifecycleCallbacks; _logger = logger; _isEnabled = commandLineOptionsService.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName); @@ -232,16 +235,15 @@ public async Task OnTestSessionFinishingAsync(SessionUid sessionUid, Cancellatio ApplicationStateGuard.Ensure(_testStartTime is not null); + int exitCode = _testApplicationProcessExitCode.GetProcessExitCode(); TrxReportEngine trxReportGeneratorEngine = new(_testApplicationModuleInfo, _environment, _commandLineOptionsService, _configuration, _clock, _tests.ToArray(), _failedTestsCount, _passedTestsCount, _notExecutedTestsCount, _timeoutTestsCount, _artifactsByExtension, _artifactsByTestNode, - _adapterSupportTrxCapability, _testFramework, _testStartTime.Value, cancellationToken); + _adapterSupportTrxCapability, _testFramework, _testStartTime.Value, exitCode, cancellationToken); string reportFileName = await trxReportGeneratorEngine.GenerateReportAsync(); if ( - // TestController is not used when we run in server mode _commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey) || - // If crash dump is not enabled we run trx in-process only !_commandLineOptionsService.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName)) { diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs index f39e09df1c..0a5e0991a8 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs @@ -164,6 +164,7 @@ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testH adapterSupportTrxCapability: null, new TestAdapterInfo(_testAdapterInformationRequest!.TestAdapterId, _testAdapterInformationRequest.TestAdapterVersion), _startTime, + testHostProcessInformation.ExitCode, cancellation); await _messageBus.PublishAsync( @@ -194,6 +195,7 @@ await _messageBus.PublishAsync( false, new TestAdapterInfo(_testAdapterInformationRequest!.TestAdapterId, _testAdapterInformationRequest.TestAdapterVersion), _startTime, + testHostProcessInformation.ExitCode, cancellation); await trxReportGeneratorEngine.AddArtifactsAsync(trxFile, artifacts); diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs index 03ecbd1941..10d7a0399a 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs @@ -102,11 +102,12 @@ internal sealed partial class TrxReportEngine private readonly ITestFramework _testFrameworkAdapter; private readonly DateTimeOffset _testStartTime; private readonly CancellationToken _cancellationToken; + private readonly int _exitCode; private readonly XNamespace _namespaceUri = XNamespace.Get("http://microsoft.com/schemas/VisualStudio/TeamTest/2010"); private readonly IFileSystem _fileSystem; private readonly bool _isCopyingFileAllowed; - public TrxReportEngine(ITestApplicationModuleInfo testApplicationModuleInfo, IEnvironment environment, ICommandLineOptions commandLineOptionsService, IConfiguration configuration, IClock clock, TestNodeUpdateMessage[] testNodeUpdatedMessages, int failedTestsCount, int passedTestsCount, int notExecutedTestsCount, int timeoutTestsCount, Dictionary> artifactsByExtension, Dictionary> artifactsByTestNode, bool? adapterSupportTrxCapability, ITestFramework testFrameworkAdapter, DateTimeOffset testStartTime, CancellationToken cancellationToken) + public TrxReportEngine(ITestApplicationModuleInfo testApplicationModuleInfo, IEnvironment environment, ICommandLineOptions commandLineOptionsService, IConfiguration configuration, IClock clock, TestNodeUpdateMessage[] testNodeUpdatedMessages, int failedTestsCount, int passedTestsCount, int notExecutedTestsCount, int timeoutTestsCount, Dictionary> artifactsByExtension, Dictionary> artifactsByTestNode, bool? adapterSupportTrxCapability, ITestFramework testFrameworkAdapter, DateTimeOffset testStartTime, int exitCode, CancellationToken cancellationToken) : this( new SystemFileSystem(), testApplicationModuleInfo, @@ -124,11 +125,12 @@ public TrxReportEngine(ITestApplicationModuleInfo testApplicationModuleInfo, IEn adapterSupportTrxCapability, testFrameworkAdapter, testStartTime, + exitCode, cancellationToken) { } - public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testApplicationModuleInfo, IEnvironment environment, ICommandLineOptions commandLineOptionsService, IConfiguration configuration, IClock clock, TestNodeUpdateMessage[] testNodeUpdatedMessages, int failedTestsCount, int passedTestsCount, int notExecutedTestsCount, int timeoutTestsCount, Dictionary> artifactsByExtension, Dictionary> artifactsByTestNode, bool? adapterSupportTrxCapability, ITestFramework testFrameworkAdapter, DateTimeOffset testStartTime, CancellationToken cancellationToken, bool isCopyingFileAllowed = true) + public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testApplicationModuleInfo, IEnvironment environment, ICommandLineOptions commandLineOptionsService, IConfiguration configuration, IClock clock, TestNodeUpdateMessage[] testNodeUpdatedMessages, int failedTestsCount, int passedTestsCount, int notExecutedTestsCount, int timeoutTestsCount, Dictionary> artifactsByExtension, Dictionary> artifactsByTestNode, bool? adapterSupportTrxCapability, ITestFramework testFrameworkAdapter, DateTimeOffset testStartTime, int exitCode, CancellationToken cancellationToken, bool isCopyingFileAllowed = true) { _testApplicationModuleInfo = testApplicationModuleInfo; _environment = environment; @@ -146,6 +148,7 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp _testFrameworkAdapter = testFrameworkAdapter; _testStartTime = testStartTime; _cancellationToken = cancellationToken; + _exitCode = exitCode; _fileSystem = fileSystem; _isCopyingFileAllowed = isCopyingFileAllowed; } @@ -175,9 +178,9 @@ public async Task GenerateReportAsync(string testHostCrashInfo = "", boo AddTestLists(testRun, uncategorizedTestId); // NotExecuted is the status for the skipped test. - resultSummaryOutcome = isTestHostCrashed ? "Failed" : resultSummaryOutcome is "Passed" or "NotExecuted" ? "Completed" : resultSummaryOutcome; + resultSummaryOutcome = isTestHostCrashed || _exitCode != ExitCodes.Success ? "Failed" : resultSummaryOutcome is "Passed" or "NotExecuted" ? "Completed" : resultSummaryOutcome; - await AddResultSummaryAsync(testRun, resultSummaryOutcome, runDeploymentRoot, testHostCrashInfo, isTestHostCrashed); + await AddResultSummaryAsync(testRun, resultSummaryOutcome, runDeploymentRoot, testHostCrashInfo, _exitCode, isTestHostCrashed); // will need catch Unauthorized access document.Add(testRun); @@ -289,7 +292,7 @@ private async Task AddArtifactsToCollectionAsync(Dictionary(), serviceProvider.GetLoggerFactory().CreateLogger())); diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs index 9b84a60bcf..5ce9dc10be 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxTestApplicationLifecycleCallbacks.cs @@ -24,13 +24,10 @@ public TrxTestApplicationLifecycleCallbacks( IEnvironment environment) { _isEnabled = - // TrxReportGenerator is enabled only when trx report is enabled commandLineOptionsService.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName) && - // TestController is not used when we run in server mode !commandLineOptionsService.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey) && - // If crash dump is not enabled we run trx in-process only commandLineOptionsService.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName); diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs index b936d64749..15adebb7ff 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.cs @@ -94,7 +94,7 @@ await ExecuteRequestAsync( // Get the exit code service to be able to set the exit code ITestApplicationProcessExitCode testApplicationResult = ServiceProvider.GetTestApplicationProcessExitCode(); statistics = testApplicationResult.GetStatistics(); - exitCode = await testApplicationResult.GetProcessExitCodeAsync(); + exitCode = testApplicationResult.GetProcessExitCode(); await _logger.LogInformationAsync($"Test session '{ServiceProvider.GetTestSessionContext().SessionId}' ended with exit code '{exitCode}' in {consoleRunStarted.Elapsed}"); diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs index e73c9f80a3..0b89ab72fc 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs @@ -324,6 +324,10 @@ public async Task BuildAsync( serviceProvider.AddService(nonCooperativeParentProcessListener); } + // Add TestApplicationResultProxy + TestApplicationResultProxy testApplicationResultProxy = new(); + serviceProvider.AddService(testApplicationResultProxy); + // ============= SETUP COMMON SERVICE USED IN ALL MODES END ===============// // ============= SELECT AND RUN THE ACTUAL MODE ===============// @@ -730,7 +734,11 @@ private async Task BuildTestFrameworkAsync(TestFrameworkBuilderD serviceProvider.GetTestApplicationCancellationTokenSource(), serviceProvider.GetCommandLineOptions(), serviceProvider.GetEnvironment()); - await RegisterAsServiceOrConsumerOrBothAsync(testApplicationResult, serviceProvider, dataConsumersBuilder); + + // Set the concrete TestApplicationResult + TestApplicationResultProxy testApplicationResultProxy = serviceProvider.GetRequiredService(); + testApplicationResultProxy.SetTestApplicationProcessExitCode(testApplicationResult); + await RegisterAsServiceOrConsumerOrBothAsync(testApplicationResultProxy, serviceProvider, dataConsumersBuilder); // We register the data consumer handler if we're connected to the dotnet test pipe if (pushOnlyProtocolDataConsumer is not null) diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.Designer.cs b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.Designer.cs index 9a56ec812f..795e7057bc 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.Designer.cs +++ b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.Designer.cs @@ -1311,6 +1311,15 @@ internal static string TestApplicationResultDisplayName { } } + /// + /// Looks up a localized string similar to The ITestApplicationResult has not been built yet.. + /// + internal static string TestApplicationResultNotReady { + get { + return ResourceManager.GetString("TestApplicationResultNotReady", resourceCulture); + } + } + /// /// Looks up a localized string similar to VSTest mode only supports a single TestApplicationBuilder per process. /// diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx index 70c4b35f84..4a25d8f2f7 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx +++ b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx @@ -631,4 +631,7 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is Expected --client-port when jsonRpc protocol is used. - + + The ITestApplicationResult has not been built yet. + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf index 1c9880f368..cf27605ad4 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf @@ -730,6 +730,11 @@ Platné hodnoty jsou Normal a Detailed. Výchozí hodnota je Normal. Výsledek testovací aplikace + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process Režim VSTest podporuje jen jeden TestApplicationBuilder na proces. diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf index caf865254f..d704586af7 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf @@ -730,6 +730,11 @@ Gültige Werte sind „Normal“, „Detailed“. Der Standardwert ist „Normal Testanwendungsergebnis + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process Der VSTest-Modus unterstützt nur einen einzelnen TestApplicationBuilder pro Prozess. diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf index ad6a232b66..082a8a4c38 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf @@ -730,6 +730,11 @@ Los valores válidos son 'Normal', 'Detallado'. El valor predeterminado es 'Norm Resultado de la aplicación de prueba + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process El modo VSTest solo admite un único TestApplicationBuilder por proceso diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf index c1eb5172b9..e27bd81d5e 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf @@ -730,6 +730,11 @@ Les valeurs valides sont « Normal » et « Détaillé ». La valeur par dé Résultat de l’application de test + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process Le mode VSTest ne prend en charge qu’un seul TestApplicationBuilder par processus diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf index b4c30b5eaa..2ec79fba04 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf @@ -730,6 +730,11 @@ I valori validi sono 'Normal', 'Detailed'. L'impostazione predefinita è 'Normal Risultato del test dell'applicazione + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process La modalità VSTest supporta solo un singolo TestApplicationBuilder per processo diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf index 076908f972..2b41134c7f 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf @@ -731,6 +731,11 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. テスト アプリケーションの結果 + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process VSTest モードは、プロセスごとに 1 つの TestApplicationBuilder のみをサポートします diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf index 98432e39c3..f8461dc1e5 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf @@ -730,6 +730,11 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 테스트 애플리케이션 결과 + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process VSTest 모드는 프로세스당 단일 TestApplicationBuilder만 지원합니다. diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf index ab41077d76..d8727a468b 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf @@ -730,6 +730,11 @@ Prawidłowe wartości to „Normalne”, „Szczegółowe”. Wartość domyśln Wynik aplikacji testowej + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process Tryb VSTest obsługuje tylko jeden element TestApplicationBuilder na proces diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf index 28637e8fb3..b9e1e5e0de 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf @@ -730,6 +730,11 @@ Os valores válidos são “Normal”, “Detalhado”. O padrão é “Normal Resultado do aplicativo de teste + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process O modo VSTest dá suporte apenas a um único TestApplicationBuilder por processo diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf index 943cbe236d..47c89311bf 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf @@ -730,6 +730,11 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. Результат приложения для тестирования + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process Режим VSTest поддерживает только один TestApplicationBuilder для каждого процесса diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf index 42fd67992c..8d42ca0ba9 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf @@ -730,6 +730,11 @@ Geçerli değerler: ‘Normal’, ‘Ayrıntılı’. Varsayılan değer: ‘Nor Test uygulaması sonucu + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process VSTest modu, işlem başına yalnızca tek bir TestApplicationBuilder destekler diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf index 774f23bed6..f422e1c7a8 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf @@ -730,6 +730,11 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 测试应用程序结果 + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process VSTest 模式仅支持每个进程一个 TestApplicationBuilder diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf index 6b09d38192..7554ffd878 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf @@ -730,6 +730,11 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 測試應用程式結果 + + The ITestApplicationResult has not been built yet. + The ITestApplicationResult has not been built yet. + + VSTest mode only supports a single TestApplicationBuilder per process VSTest 模式僅支援每一程序的單一 TestApplicationBuilder diff --git a/src/Platform/Microsoft.Testing.Platform/Services/ITestApplicationProcessExitCode.cs b/src/Platform/Microsoft.Testing.Platform/Services/ITestApplicationProcessExitCode.cs index f15708b622..1f8a11274b 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/ITestApplicationProcessExitCode.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/ITestApplicationProcessExitCode.cs @@ -13,7 +13,8 @@ internal interface ITestApplicationProcessExitCode : IDataConsumer Task SetTestAdapterTestSessionFailureAsync(string errorMessage); - Task GetProcessExitCodeAsync(); + // If we decide to open this extension we should make it Task GetProcessExitCodeAsync(); + int GetProcessExitCode(); Statistics GetStatistics(); } diff --git a/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs b/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs index 490929851b..e01fad11fe 100644 --- a/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs +++ b/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResult.cs @@ -1,14 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Concurrent; using System.Globalization; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Extensions.Messages; using Microsoft.Testing.Platform.Extensions.OutputDevice; using Microsoft.Testing.Platform.Helpers; -using Microsoft.Testing.Platform.Logging; using Microsoft.Testing.Platform.Messages; using Microsoft.Testing.Platform.OutputDevice; using Microsoft.Testing.Platform.Resources; @@ -19,13 +17,12 @@ internal sealed class TestApplicationResult( IOutputDevice outputService, ITestApplicationCancellationTokenSource testApplicationCancellationTokenSource, ICommandLineOptions commandLineOptions, - IEnvironment environment) : ITestApplicationProcessExitCode, ILoggerProvider, IOutputDeviceDataProducer + IEnvironment environment) : ITestApplicationProcessExitCode, IOutputDeviceDataProducer { private readonly IOutputDevice _outputService = outputService; private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; private readonly ICommandLineOptions _commandLineOptions = commandLineOptions; private readonly IEnvironment _environment = environment; - private readonly List _testApplicationResultLoggers = []; private readonly List _failedTests = []; private int _totalRanTests; private bool _testAdapterTestSessionFailure; @@ -81,25 +78,9 @@ public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationTo return Task.CompletedTask; } - public ILogger CreateLogger(string categoryName) + public int GetProcessExitCode() { - TestApplicationResultLogger logger = new(categoryName); - _testApplicationResultLoggers.Add(logger); - - return logger; - } - - public async Task GetProcessExitCodeAsync() - { - bool anyError = false; - foreach ((string categoryName, string error) in _testApplicationResultLoggers.SelectMany(logger => logger.Errors.Select(error => (logger.CategoryName, error)))) - { - anyError = true; - await _outputService.DisplayAsync(this, FormattedTextOutputDeviceDataBuilder.CreateRedConsoleColorText($"[{categoryName}] {error}")); - } - int exitCode = ExitCodes.Success; - exitCode = anyError ? ExitCodes.GenericFailure : exitCode; exitCode = exitCode == ExitCodes.Success && _testAdapterTestSessionFailure ? ExitCodes.TestAdapterTestSessionFailure : exitCode; exitCode = exitCode == ExitCodes.Success && _failedTests.Count > 0 ? ExitCodes.AtLeastOneTestFailed : exitCode; exitCode = exitCode == ExitCodes.Success && _testApplicationCancellationTokenSource.CancellationToken.IsCancellationRequested ? ExitCodes.TestSessionAborted : exitCode; @@ -145,25 +126,4 @@ public async Task SetTestAdapterTestSessionFailureAsync(string errorMessage) public Statistics GetStatistics() => new() { TotalRanTests = _totalRanTests, TotalFailedTests = _failedTests.Count }; - - private sealed class TestApplicationResultLogger(string categoryName) : ILogger - { - private readonly ConcurrentBag _errors = []; - - public IReadOnlyCollection Errors => _errors; - - public string CategoryName { get; } = categoryName; - - public bool IsEnabled(LogLevel logLevel) - => logLevel is LogLevel.Error or LogLevel.Critical; - - public Task LogAsync(LogLevel logLevel, TState state, Exception? exception, Func formatter) - { - _errors.Add(formatter(state, exception)); - return Task.CompletedTask; - } - - public void Log(LogLevel logLevel, TState state, Exception? exception, Func formatter) - => _errors.Add(formatter(state, exception)); - } } diff --git a/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResultProxy.cs b/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResultProxy.cs new file mode 100644 index 0000000000..ed7da43e36 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/Services/TestApplicationResultProxy.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Extensions.Messages; + +namespace Microsoft.Testing.Platform.Services; + +internal class TestApplicationResultProxy : ITestApplicationProcessExitCode +{ + private ITestApplicationProcessExitCode? _testApplicationProcessExitCode; + + public bool HasTestAdapterTestSessionFailure + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.HasTestAdapterTestSessionFailure; + + public string? TestAdapterTestSessionFailureErrorMessage + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.TestAdapterTestSessionFailureErrorMessage; + + public Type[] DataTypesConsumed + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.DataTypesConsumed; + + public string Uid + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.Uid; + + public string Version + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.Version; + + public string DisplayName + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.DisplayName; + + public string Description + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.Description; + + public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken) + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.ConsumeAsync(dataProducer, value, cancellationToken); + + public int GetProcessExitCode() + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.GetProcessExitCode(); + + public Statistics GetStatistics() + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.GetStatistics(); + + public Task IsEnabledAsync() + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.IsEnabledAsync(); + + public Task SetTestAdapterTestSessionFailureAsync(string errorMessage) + => _testApplicationProcessExitCode is null ? + throw new InvalidOperationException(Resources.PlatformResources.TestApplicationResultNotReady) : + _testApplicationProcessExitCode.SetTestAdapterTestSessionFailureAsync(errorMessage); + + public void SetTestApplicationProcessExitCode(ITestApplicationProcessExitCode testApplicationProcessExitCode) + { + Guard.NotNull(testApplicationProcessExitCode); + _testApplicationProcessExitCode = testApplicationProcessExitCode; + } +} diff --git a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/TrxTests.cs b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/TrxTests.cs index 19bb8f6905..ec20efca39 100644 --- a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/TrxTests.cs +++ b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/TrxTests.cs @@ -80,7 +80,7 @@ public async Task Trx_WhenSkipTest_ItAppearsAsExpectedInsideTheTrx(string tfm) Assert.That(trxContent.Contains(@""""), trxContent); + Assert.That(trxContent.Contains(""""""), trxContent); Assert.That(trxContent.Contains(""""""), trxContent); } diff --git a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs index ca137802fe..e411f49abc 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs @@ -396,7 +396,7 @@ public async Task TrxReportEngine_GenerateReportAsync_FileAlreadyExists_WillRetr _ = _testApplicationModuleInfoMock.Setup(_ => _.GetCurrentTestApplicationFullPath()).Returns("TestAppPath"); TrxReportEngine trxReportEngine = new(_fileSystem.Object, _testApplicationModuleInfoMock.Object, _environmentMock.Object, _commandLineOptionsMock.Object, _configurationMock.Object, _clockMock.Object, [], 0, 0, 0, 0, - _artifactsByExtension, _artifactsByTestNode, true, _testFrameworkMock.Object, DateTime.UtcNow, CancellationToken.None, + _artifactsByExtension, _artifactsByTestNode, true, _testFrameworkMock.Object, DateTime.UtcNow, 0, CancellationToken.None, isCopyingFileAllowed: false); // Act @@ -451,7 +451,7 @@ private TrxReportEngine GenerateTrxReportEngine(int passedTestsCount, int failed return new TrxReportEngine(_fileSystem.Object, _testApplicationModuleInfoMock.Object, _environmentMock.Object, _commandLineOptionsMock.Object, _configurationMock.Object, _clockMock.Object, testNodeUpdatedMessages, failedTestsCount, passedTestsCount, notExecutedTestsCount, timeoutTestsCount, - _artifactsByExtension, _artifactsByTestNode, adapterSupportTrxCapability, _testFrameworkMock.Object, testStartTime, cancellationToken, + _artifactsByExtension, _artifactsByTestNode, adapterSupportTrxCapability, _testFrameworkMock.Object, testStartTime, 0, cancellationToken, isCopyingFileAllowed: false); } diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs index 3c763223aa..6964e6aa45 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Services/TestApplicationResultTests.cs @@ -33,7 +33,7 @@ public async Task GetProcessExitCodeAsync_If_All_Skipped_Returns_ZeroTestsRan() Properties = new PropertyBag(SkippedTestNodeStateProperty.CachedInstance), }), CancellationToken.None); - Assert.AreEqual(ExitCodes.ZeroTests, await _testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.ZeroTests, _testApplicationResult.GetProcessExitCode()); } public async Task GetProcessExitCodeAsync_If_No_Tests_Ran_Returns_ZeroTestsRan() @@ -47,7 +47,7 @@ public async Task GetProcessExitCodeAsync_If_No_Tests_Ran_Returns_ZeroTestsRan() Properties = new PropertyBag(), }), CancellationToken.None); - Assert.AreEqual(ExitCodes.ZeroTests, await _testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.ZeroTests, _testApplicationResult.GetProcessExitCode()); } [ArgumentsProvider(nameof(FailedState))] @@ -62,7 +62,7 @@ public async Task GetProcessExitCodeAsync_If_Failed_Tests_Returns_AtLeastOneTest Properties = new PropertyBag(testNodeStateProperty), }), CancellationToken.None); - Assert.AreEqual(ExitCodes.AtLeastOneTestFailed, await _testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.AtLeastOneTestFailed, _testApplicationResult.GetProcessExitCode()); } public async Task GetProcessExitCodeAsync_If_Canceled_Returns_TestSessionAborted() @@ -87,7 +87,7 @@ TestApplicationResult testApplicationResult Properties = new PropertyBag(), }), CancellationToken.None); - Assert.AreEqual(ExitCodes.TestSessionAborted, await testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.TestSessionAborted, testApplicationResult.GetProcessExitCode()); } public async Task GetProcessExitCodeAsync_If_TestAdapter_Returns_TestAdapterTestSessionFailure() @@ -102,7 +102,7 @@ public async Task GetProcessExitCodeAsync_If_TestAdapter_Returns_TestAdapterTest Properties = new PropertyBag(PassedTestNodeStateProperty.CachedInstance), }), CancellationToken.None); - Assert.AreEqual(ExitCodes.TestAdapterTestSessionFailure, await _testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.TestAdapterTestSessionFailure, _testApplicationResult.GetProcessExitCode()); } public async Task GetProcessExitCodeAsync_If_MinimumExpectedTests_Violated_Returns_MinimumExpectedTestsPolicyViolation() @@ -130,7 +130,7 @@ TestApplicationResult testApplicationResult Properties = new PropertyBag(InProgressTestNodeStateProperty.CachedInstance), }), CancellationToken.None); - Assert.AreEqual(ExitCodes.MinimumExpectedTestsPolicyViolation, await testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.MinimumExpectedTestsPolicyViolation, testApplicationResult.GetProcessExitCode()); } public async Task GetProcessExitCodeAsync_OnDiscovery_No_Tests_Discovered_Returns_ZeroTests() @@ -148,7 +148,7 @@ TestApplicationResult testApplicationResult DisplayName = "DisplayName", }), CancellationToken.None); - Assert.AreEqual(ExitCodes.ZeroTests, await testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.ZeroTests, testApplicationResult.GetProcessExitCode()); } public async Task GetProcessExitCodeAsync_OnDiscovery_Some_Tests_Discovered_Returns_Success() @@ -167,7 +167,7 @@ TestApplicationResult testApplicationResult Properties = new PropertyBag(DiscoveredTestNodeStateProperty.CachedInstance), }), CancellationToken.None); - Assert.AreEqual(ExitCodes.Success, await testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(ExitCodes.Success, testApplicationResult.GetProcessExitCode()); } [Arguments("8", ExitCodes.Success)] @@ -181,7 +181,7 @@ TestApplicationResult testApplicationResult [Arguments(";", ExitCodes.ZeroTests)] [Arguments(null, ExitCodes.ZeroTests)] [Arguments("", ExitCodes.ZeroTests)] - public async Task GetProcessExitCodeAsync_IgnoreExitCodes(string argument, int expectedExitCode) + public void GetProcessExitCodeAsync_IgnoreExitCodes(string argument, int expectedExitCode) { Mock environment = new(); environment.Setup(x => x.GetEnvironmentVariable(EnvironmentVariableConstants.TESTINGPLATFORM_EXITCODE_IGNORE)).Returns(argument); @@ -196,7 +196,7 @@ public async Task GetProcessExitCodeAsync_IgnoreExitCodes(string argument, int e environment.Object), }) { - Assert.AreEqual(expectedExitCode, await testApplicationResult.GetProcessExitCodeAsync()); + Assert.AreEqual(expectedExitCode, testApplicationResult.GetProcessExitCode()); } }