Esempio n. 1
0
        public string GetRunResultsAsXml(int maxConcurrentRunners)
        {
            if (!_configured)
            {
                throw new InvalidOperationException("You must call ConfigureRun first");
            }

            //Keep a reference to standard out
            var stdOut       = new TextWriterWrapper(Console.Out);
            var totalRuntime = new Stopwatch();

            totalRuntime.Start();


            var outputPath = _runnerSettings.OutputBasePath;

            if (!Directory.Exists(outputPath))
            {
                Directory.CreateDirectory(outputPath);
            }


            var shouldRunOther = _categoriesToRun.Count == 0 ||
                                 _categoriesToRun.Contains("all");

            //var categoryMessage = "Categories run will be: " + string.Join(", ", runnableCategories);
            //Debug.WriteLine(categoryMessage);
            //Console.WriteLine(categoryMessage);

            stdOut.WriteLine("Starting tests...");
            if (maxConcurrentRunners > 0)
            {
                stdOut.WriteLine("   Running upto " + maxConcurrentRunners + " concurrently");
            }
            stdOut.WriteLine("(ctrl-c and a few seconds to cancel, '{0}' means running, '{1}' means finished)",
                             _progressDisplayBuilder.ArrayValueToRunningStatusChar(ProgressState.Running),
                             _progressDisplayBuilder.ArrayValueToRunningStatusChar(ProgressState.Finished));


            var testFixturesToRun = new List <string>();

            if (shouldRunOther)
            {
                testFixturesToRun = new List <string>(_otherTestFixtures);
            }

            var runnableCategories = _categoriesToRun.Count > 0
                                         ? _categories.Intersect(_categoriesToRun).ToList()
                                         : _categories;
            int totalToRun = runnableCategories.Count();

            if (_runnerSettings.RunUncategorizedTestFixturesParallel)
            {
                totalToRun += testFixturesToRun.Count;
            }
            else if (shouldRunOther && _otherTestFixtures.Any())
            {
                totalToRun += 1;
            }

            stdOut.WriteLine();
            stdOut.WriteLine("Found {0} categories/fixtures to run", totalToRun);

            var  testResults = new ConcurrentBag <RunStats>();
            bool cancelled   = false;

            try
            {
                var runningTests = new ProgressStats(totalToRun);

                int indicatorPos    = 0;
                var buildingDisplay = new object();
                var timer           = new Timer(x =>
                {
                    if (Console.IsOutputRedirected)
                    {
                        return;
                    }
                    if (!Monitor.TryEnter(buildingDisplay))
                    {
                        return;
                    }

                    try
                    {
                        int windowWidth = Console.WindowWidth;

                        stdOut.Write("\r");
                        stdOut.Write(_progressDisplayBuilder.BuildProgressDisplay(windowWidth, runningTests,
                                                                                  ref indicatorPos,
                                                                                  _runnerSettings.DisplayFailureSymbolsInProgressDisplay));
                    }
                    catch (Exception exception)
                    {
                        stdOut.Write("display error...");
                        throw new ApplicationException("Unable to properly build progress display.", exception);
                    }
                    finally
                    {
                        Monitor.Exit(buildingDisplay);
                    }
                }, null, 0, 250);

                if (Console.IsOutputRedirected)
                {
                    timer.Change(Timeout.Infinite, Timeout.Infinite);
                }

                //Setup ability to catch ctrl-c
                Console.CancelKeyPress += (sender, args) =>
                {
                    timer.Change(Timeout.Infinite, Timeout.Infinite);

                    args.Cancel = true;
                    _cancelTokenSource.Cancel();

                    //stdOut.WriteLine();
                    //stdOut.WriteLine("CANCEL KEY PUSHED");

                    //Stop any running ones... maybe don't do this until pressed twice?
                    Process.GetProcesses()
                    .Where(p => p.ProcessName == "nunit-console" ||
                           p.ProcessName == "nunit-agent")
                    .Each(x => x.Kill());
                };

                var startOrderInt = 0;
                var token         = _cancelTokenSource.Token;

                var buildSortedAllActions = BuildSortedAllActions(testFixturesToRun, runnableCategories)
                                            .ToArray();
                RunActionsOnThreads(maxConcurrentRunners, buildSortedAllActions, token, stdOut, runningTests, startOrderInt, totalRuntime, testResults);

                timer.Change(0, Timeout.Infinite);
                //Tacky way to fix line printing problem
                Thread.Sleep(100);
                stdOut.WriteLine();
            }
            catch (OperationCanceledException)
            {
                cancelled = true;
                stdOut.WriteLine();
                stdOut.WriteLine("== Cancelled ==");
            }

            totalRuntime.Stop();
            stdOut.WriteLine("= Total runtime: " + TimeSpanFormat(totalRuntime.Elapsed));
            stdOut.WriteLine("Finished with tests, merging results");

            var SkippedTests = _categories.Except(testResults.Select(a => a.Name)).ToList();

            _resultsStatsWriter.OutputRunStats(totalRuntime.Elapsed, testResults, SkippedTests);

            var outputResultsXmlPath    = _runnerSettings.ResultsXmlFilepath;
            var outputResultsReportPath = _runnerSettings.ResultsHtmlReportFilepath;
            var xmlOutput = _resultsWriter.MergeResultsProcess(outputPath, outputResultsXmlPath, outputResultsReportPath);

            if (cancelled)
            {
                Environment.ExitCode = -9;
            }
            if (testResults.Any(x => x.ExitCode != 0))
            {
                stdOut.WriteLine("ERROR: Test process exited with error!");
                Environment.ExitCode = -1;
            }

            //Do we really need to return this? if so we should have the writing happen elsewhere...
            return(xmlOutput);
        }