async ValueTask <int> RunProject( XunitProject project, _IMessageSink reporterMessageHandler) { XElement?assembliesElement = null; var clockTime = Stopwatch.StartNew(); var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; // TODO: Parallelize the ones that will parallelize, and then run the rest sequentially? var parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); if (needsXml) { assembliesElement = new XElement("assemblies"); } var originalWorkingFolder = Directory.GetCurrentDirectory(); if (parallelizeAssemblies) { var tasks = project.Assemblies.Select( assembly => Task.Run( () => ExecuteAssembly( assembly, needsXml, reporterMessageHandler ).AsTask() ) ); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.WhereNotNull()) { assembliesElement?.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = await ExecuteAssembly( assembly, needsXml, reporterMessageHandler ); if (assemblyElement != null) { assembliesElement?.Add(assemblyElement); } } } clockTime.Stop(); if (assembliesElement != null) { assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); } if (completionMessages.Count > 0) { var summaries = new TestExecutionSummaries { ElapsedClockTime = clockTime.Elapsed }; foreach (var completionMessage in completionMessages.OrderBy(kvp => kvp.Key)) { summaries.Add(completionMessage.Key, completionMessage.Value); } reporterMessageHandler.OnMessage(summaries); } Directory.SetCurrentDirectory(originalWorkingFolder); if (assembliesElement != null) { xmlTransformers.ForEach(transformer => transformer(assembliesElement)); } return(failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed + summary.Errors)); }
public override bool Execute() { Guard.ArgumentNotNull(nameof(Assemblies), Assemblies); RemotingUtility.CleanUpRegisteredChannels(); XElement?assembliesElement = null; if (NeedsXml) { assembliesElement = new XElement("assemblies"); } var appDomains = default(AppDomainSupport?); switch (AppDomains?.ToLowerInvariant()) { case null: break; case "ifavailable": appDomains = AppDomainSupport.IfAvailable; break; case "true": case "required": appDomains = AppDomainSupport.Required; break; case "false": case "denied": appDomains = AppDomainSupport.Denied; break; default: Log.LogError("AppDomains value '{0}' is invalid: must be 'ifavailable', 'required', or 'denied'", AppDomains); return(false); } switch (MaxParallelThreads) { case null: case "default": break; case "unlimited": maxThreadCount = -1; break; default: int threadValue; if (!int.TryParse(MaxParallelThreads, out threadValue) || threadValue < 1) { Log.LogError("MaxParallelThreads value '{0}' is invalid: must be 'default', 'unlimited', or a positive number", MaxParallelThreads); return(false); } maxThreadCount = threadValue; break; } var originalWorkingFolder = Directory.GetCurrentDirectory(); var internalDiagnosticsMessageSink = DiagnosticMessageSink.ForInternalDiagnostics(Log, InternalDiagnosticMessages); using (AssemblyHelper.SubscribeResolveForAssembly(typeof(xunit), internalDiagnosticsMessageSink)) { var reporter = GetReporter(); if (reporter == null) { return(false); } try { logger = new MSBuildLogger(Log); reporterMessageHandler = reporter.CreateMessageHandler(logger, internalDiagnosticsMessageSink).GetAwaiter().GetResult(); if (!NoLogo) { Log.LogMessage(MessageImportance.High, $"xUnit.net v3 MSBuild Runner v{ThisAssembly.AssemblyInformationalVersion} ({IntPtr.Size * 8}-bit {RuntimeInformation.FrameworkDescription})"); } var project = new XunitProject(); foreach (var assembly in Assemblies) { var assemblyFileName = assembly.GetMetadata("FullPath"); var configFileName = assembly.GetMetadata("ConfigFile"); if (configFileName != null && configFileName.Length == 0) { configFileName = null; } var targetFramework = AssemblyUtility.GetTargetFramework(assemblyFileName); var projectAssembly = new XunitProjectAssembly(project) { AssemblyFilename = assemblyFileName, ConfigFilename = configFileName, TargetFramework = targetFramework }; ConfigReader.Load(projectAssembly.Configuration, assemblyFileName, configFileName); if (shadowCopy.HasValue) { projectAssembly.Configuration.ShadowCopy = shadowCopy; } project.Add(projectAssembly); } if (WorkingFolder != null) { Directory.SetCurrentDirectory(WorkingFolder); } var clockTime = Stopwatch.StartNew(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(assembly, appDomains).AsTask())); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.WhereNotNull()) { assembliesElement !.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(assembly, appDomains); if (assemblyElement != null) { assembliesElement !.Add(assemblyElement); } } } clockTime.Stop(); if (assembliesElement != null) { assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); } if (completionMessages.Count > 0) { var summaries = new TestExecutionSummaries { ElapsedClockTime = clockTime.Elapsed }; foreach (var completionMessage in completionMessages.OrderBy(kvp => kvp.Key)) { summaries.Add(completionMessage.Key, completionMessage.Value); } reporterMessageHandler.OnMessage(summaries); } } finally { reporter.DisposeAsync().GetAwaiter().GetResult(); } } Directory.SetCurrentDirectory(WorkingFolder ?? originalWorkingFolder); if (NeedsXml && assembliesElement != null) { if (Xml != null) { TransformFactory.Transform("xml", assembliesElement, Xml.GetMetadata("FullPath")); } if (XmlV1 != null) { TransformFactory.Transform("xmlv1", assembliesElement, XmlV1.GetMetadata("FullPath")); } if (Html != null) { TransformFactory.Transform("html", assembliesElement, Html.GetMetadata("FullPath")); } if (NUnit != null) { TransformFactory.Transform("nunit", assembliesElement, NUnit.GetMetadata("FullPath")); } if (JUnit != null) { TransformFactory.Transform("junit", assembliesElement, JUnit.GetMetadata("FullPath")); } } // ExitCode is set to 1 for test failures and -1 for Exceptions. return(ExitCode == 0 || (ExitCode == 1 && IgnoreFailures)); }