// This method is called by the xUnit test framework classes to run the test case. We will do the // loop here, forwarding on to the implementation in XunitTestCase to do the heavy lifting. We will // continue to re-run the test until the aggregator has an error (meaning that some internal error // condition happened), or the test runs without failure, or we've hit the maximum number of tries. public override async Task <RunSummary> RunAsync(IMessageSink diagnosticMessageSink, IMessageBus messageBus, object[] constructorArguments, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) { var runCount = 0; while (true) { // This is really the only tricky bit: we need to capture and delay messages (since those will // contain run status) until we know we've decided to accept the final result; var delayedMessageBus = new DelayedMessageBus(messageBus); RunSummary summary = await base.RunAsync(diagnosticMessageSink, delayedMessageBus, constructorArguments, aggregator, cancellationTokenSource); if (aggregator.HasExceptions || summary.Failed > 0) { var details = ExtractTestFailDetailsFromMessageBus(delayedMessageBus); var errorMessage = $"Execution of '{DisplayName}' failed (attempt #{runCount + 1}) with details {details}."; diagnosticMessageSink.OnMessage(new DiagnosticMessage(errorMessage)); Console.WriteLine(errorMessage); } if (summary.Failed == 0 || ++runCount >= maxRetries) { delayedMessageBus.Dispose(); // Sends all the delayed messages return(summary); } } }
private static string ExtractTestFailDetailsFromMessageBus(DelayedMessageBus delayedMessageBus) { string details = ""; foreach (var message in delayedMessageBus.messages) { if (message.ToString() == "Xunit.Sdk.TestFailed") { try { var messages = (string[])message.GetType().GetProperty("Messages").GetValue(message); var exceptionTypes = (string[])message.GetType().GetProperty("ExceptionTypes").GetValue(message); var stackTraces = (string[])message.GetType().GetProperty("StackTraces").GetValue(message); if (messages != null && messages.Length > 0) { details += "Messages: " + string.Join(";", messages) + ". "; } if (exceptionTypes != null && exceptionTypes.Length > 0) { details += "ExceptionTypes: " + string.Join(";", exceptionTypes) + ". "; } if (stackTraces != null && stackTraces.Length > 0) { details += "StackTraces: " + string.Join(";", stackTraces) + "."; } } catch { Console.WriteLine($"Fail to read test fail message from message bus."); } } } return(details); }