Example #1
0
        // Run all test passes.
        private static bool RunTestPasses(
            List <TestInfo> testList,
            List <TestInfo> unfilteredTestList,
            CommandLineArgs commandLineArgs,
            StreamWriter log,
            long loopCount,
            long repeat,
            bool profiling = false)
        {
            bool buildMode                = commandLineArgs.ArgAsBool("buildcheck");
            bool randomOrder              = commandLineArgs.ArgAsBool("random");
            bool demoMode                 = commandLineArgs.ArgAsBool("demo");
            bool offscreen                = commandLineArgs.ArgAsBool("offscreen");
            bool internet                 = commandLineArgs.ArgAsBool("internet");
            bool perftests                = commandLineArgs.ArgAsBool("perftests");
            bool addsmallmoleculenodes    = commandLineArgs.ArgAsBool("testsmallmolecules");       // Add the magic small molecule test node to every document?
            bool runsmallmoleculeversions = commandLineArgs.ArgAsBool("runsmallmoleculeversions"); // Run the various tests that are versions of other tests with the document completely converted to small molecules?
            bool useVendorReaders         = commandLineArgs.ArgAsBool("vendors");
            bool showStatus               = commandLineArgs.ArgAsBool("status");
            bool showFormNames            = commandLineArgs.ArgAsBool("showformnames");
            bool showMatchingPages        = commandLineArgs.ArgAsBool("showpages");
            bool qualityMode              = commandLineArgs.ArgAsBool("quality");
            bool pass0             = commandLineArgs.ArgAsBool("pass0");
            bool pass1             = commandLineArgs.ArgAsBool("pass1");
            int  timeoutMultiplier = (int)commandLineArgs.ArgAsLong("multi");
            int  pauseSeconds      = (int)commandLineArgs.ArgAsLong("pause");
            var  formList          = commandLineArgs.ArgAsString("form");
            var  pauseDialogs      = (string.IsNullOrEmpty(formList)) ? null : formList.Split(',');
            var  results           = commandLineArgs.ArgAsString("results");
            var  maxSecondsPerTest = commandLineArgs.ArgAsDouble("maxsecondspertest");

            // If we haven't been told to run perf tests, remove any from the list
            // which may have shown up by default
            if (!perftests)
            {
                for (var t = testList.Count; t-- > 0;)
                {
                    if (testList[t].IsPerfTest)
                    {
                        testList.RemoveAt(t);
                    }
                }
                for (var ut = unfilteredTestList.Count; ut-- > 0;)
                {
                    if (unfilteredTestList[ut].IsPerfTest)
                    {
                        unfilteredTestList.RemoveAt(ut);
                    }
                }
            }
            // Even if we have been told to run perftests, if none are in the list
            // then make sure we don't chat about perf tests in the log
            perftests &= testList.Any(t => t.IsPerfTest);

            if (buildMode)
            {
                randomOrder      = false;
                demoMode         = false;
                offscreen        = true;
                useVendorReaders = true;
                showStatus       = false;
                qualityMode      = false;
                pauseSeconds     = 0;
            }

            var runTests = new RunTests(
                demoMode, buildMode, offscreen, internet, showStatus, perftests, addsmallmoleculenodes,
                runsmallmoleculeversions,
                pauseDialogs, pauseSeconds, useVendorReaders, timeoutMultiplier,
                results, log);

            if (commandLineArgs.ArgAsBool("clipboardcheck"))
            {
                runTests.TestContext.Properties["ClipboardCheck"] = "TestRunner clipboard check";
                Console.WriteLine("Checking clipboard use for {0} tests...\n", testList.Count);
                loopCount   = 1;
                randomOrder = false;
            }
            else
            {
                if (!randomOrder && perftests)
                {
                    runTests.Log("Perf tests will run last, for maximum overall test coverage.\r\n");
                }
                runTests.Log("Running {0}{1} tests{2}{3}...\r\n",
                             testList.Count,
                             testList.Count < unfilteredTestList.Count ? "/" + unfilteredTestList.Count : "",
                             (loopCount <= 0) ? " forever" : (loopCount == 1) ? "" : " in " + loopCount + " loops",
                             (repeat <= 1) ? "" : ", repeated " + repeat + " times each per language");
            }

            // Get list of languages
            var languages = buildMode
                ? new[] { "en" }
                : commandLineArgs.ArgAsString("language").Split(',');

            if (showFormNames)
            {
                runTests.Skyline.Set("ShowFormNames", true);
            }
            if (showMatchingPages)
            {
                runTests.Skyline.Set("ShowMatchingPages", true);
            }

            var executingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var qualityLanguages   = new FindLanguages(executingDirectory, "en", "fr").Enumerate().ToArray();
            var removeList         = new List <TestInfo>();

            // Pass 0: Test an interesting collection of edge cases:
            //         French number format,
            //         No vendor readers,
            //         No internet access,
            //         Old reports
            if (pass0)
            {
                runTests.Log("\r\n");
                runTests.Log("# Pass 0: Run with French number format, no vendor readers, no internet access, old reports.\r\n");

                runTests.Language = new CultureInfo("fr");
                runTests.Skyline.Set("NoVendorReaders", true);
                runTests.AccessInternet        = false;
                runTests.LiveReports           = false;
                runTests.RunPerfTests          = false;
                runTests.AddSmallMoleculeNodes = false;
                runTests.CheckCrtLeaks         = CrtLeakThreshold;
                bool warnedPass0PerfTest = false;
                for (int testNumber = 0; testNumber < testList.Count; testNumber++)
                {
                    var test = testList[testNumber];
                    if (test.IsPerfTest)
                    {
                        // These are largely about vendor and/or internet performance, so not worth doing in pass 0
                        if (!warnedPass0PerfTest)
                        {
                            warnedPass0PerfTest = true;
                            runTests.Log("# Skipping perf tests for pass 0.\r\n");
                        }
                        continue;
                    }
                    if (!runTests.Run(test, 0, testNumber))
                    {
                        removeList.Add(test);
                    }
                }
                runTests.Skyline.Set("NoVendorReaders", false);
                runTests.AccessInternet        = internet;
                runTests.LiveReports           = true;
                runTests.RunPerfTests          = perftests;
                runTests.AddSmallMoleculeNodes = addsmallmoleculenodes;
                runTests.CheckCrtLeaks         = 0;

                foreach (var removeTest in removeList)
                {
                    testList.Remove(removeTest);
                }
                removeList.Clear();
            }

            // Pass 1: Look for cumulative leaks when test is run multiple times.
            if (pass1)
            {
                runTests.Log("\r\n");
                runTests.Log("# Pass 1: Run tests multiple times to detect memory leaks.\r\n");
                bool warnedPass1PerfTest = false;

                for (int testNumber = 0; testNumber < testList.Count; testNumber++)
                {
                    var  test   = testList[testNumber];
                    bool failed = false;

                    if (test.IsPerfTest)
                    {
                        // These are generally too lengthy to run multiple times, so not a good fit for pass 1
                        if (!warnedPass1PerfTest)
                        {
                            warnedPass1PerfTest = true;
                            runTests.Log("# Skipping perf tests for pass 1 leak checks.\r\n");
                        }
                        continue;
                    }

                    // Warm up memory by running the test in each language.
                    for (int i = 0; i < qualityLanguages.Length; i++)
                    {
                        runTests.Language = new CultureInfo(qualityLanguages[i]);
                        if (!runTests.Run(test, 1, testNumber))
                        {
                            failed = true;
                            removeList.Add(test);
                            break;
                        }
                    }

                    if (failed)
                    {
                        continue;
                    }

                    // Run test repeatedly until we can confidently assess the leak status.
                    double slope        = 0;
                    var    memoryPoints = new List <double> {
                        runTests.TotalMemoryBytes
                    };
                    for (int i = 0; i < LeakCheckIterations; i++)
                    {
                        // Run the test in the next language.
                        runTests.Language =
                            new CultureInfo(qualityLanguages[i % qualityLanguages.Length]);
                        if (!runTests.Run(test, 1, testNumber))
                        {
                            failed = true;
                            removeList.Add(test);
                            break;
                        }

                        // Run linear regression on memory size samples.
                        var memoryBytes = runTests.TotalMemoryBytes;
                        memoryPoints.Add(memoryBytes);
                        if (memoryPoints.Count < 8)
                        {
                            continue;
                        }

                        // Stop if the leak magnitude is below our threshold.
                        slope = CalculateSlope(memoryPoints);
                        if (slope < LeakThreshold)
                        {
                            break;
                        }
                        memoryPoints.RemoveAt(0);
                    }

                    if (failed)
                    {
                        continue;
                    }

                    if (slope >= LeakThreshold)
                    {
                        runTests.Log("!!! {0} LEAKED {1} bytes\r\n", test.TestMethod.Name, Math.Floor(slope));
                        removeList.Add(test);
                    }
                }

                foreach (var removeTest in removeList)
                {
                    testList.Remove(removeTest);
                }
                removeList.Clear();
            }

            if (qualityMode)
            {
                languages = qualityLanguages;
            }

            // Run all test passes.
            int pass    = 1;
            int passEnd = pass + (int)loopCount;

            if (pass0 || pass1)
            {
                pass++;
                passEnd++;
            }
            if (loopCount <= 0)
            {
                passEnd = int.MaxValue;
            }

            if (pass == 2 && pass < passEnd && testList.Count > 0)
            {
                runTests.Log("\r\n");
                runTests.Log("# Pass 2+: Run tests in each selected language.\r\n");
            }

            int  perfPass = pass;                                             // We'll run perf tests just once per language, and only in one language (french) if english and french (along with any others) are both enabled
            bool needsPerfTestPass2Warning = testList.Any(t => t.IsPerfTest); // No perf tests, no warning
            bool flip = true;
            var  perfTestsFrenchOnly = perftests && languages.Any(l => l.StartsWith("en")) && languages.Any(l => l.StartsWith("fr"));

            for (; pass < passEnd; pass++)
            {
                if (testList.Count == 0)
                {
                    break;
                }

                // Run each test in this test pass.
                var testPass = randomOrder ? testList.RandomOrder().ToList() : testList;
                for (int testNumber = 0; testNumber < testPass.Count; testNumber++)
                {
                    var test = testPass[testNumber];

                    // Perf Tests are generally too lengthy to run multiple times (but non-english format check is useful)
                    var languagesThisTest = (test.IsPerfTest && perfTestsFrenchOnly) ? new[] { "fr" } : languages;
                    if (perfTestsFrenchOnly && needsPerfTestPass2Warning)
                    {
                        // NB the phrase "# Perf tests" in a log is a key for SkylineNightly to post to a different URL - so don't mess with this.
                        runTests.Log("# Perf tests will be run only once, and only in French.  To run perf tests in other languages, enable all but English.\r\n");
                        needsPerfTestPass2Warning = false;
                    }

                    // Run once (or repeat times) for each language.
                    for (int i = 0; i < languagesThisTest.Length; i++)
                    {
                        runTests.Language = new CultureInfo(languagesThisTest[i]);
                        var stopWatch = new Stopwatch();
                        stopWatch.Start(); // Limit the repeats in case of very long tests
                        for (int repeatCounter = 1; repeatCounter <= repeat; repeatCounter++)
                        {
                            if (test.IsPerfTest && ((pass > perfPass) || (repeatCounter > 1)))
                            {
                                // Perf Tests are generally too lengthy to run multiple times (but per-language check is useful)
                                if (needsPerfTestPass2Warning)
                                {
                                    // NB the phrase "# Perf tests" in a log is a key for SkylineNightly to post to a different URL - so don't mess with this.
                                    runTests.Log("# Perf tests will be run only once per language.\r\n");
                                    needsPerfTestPass2Warning = false;
                                }
                                break;
                            }
                            if (!runTests.Run(test, pass, testNumber))
                            {
                                removeList.Add(test);
                                i = languages.Length - 1;   // Don't run other languages.
                                break;
                            }
                            if (maxSecondsPerTest > 0)
                            {
                                var maxSecondsPerTestPerLanguage = maxSecondsPerTest / languagesThisTest.Length; // We'd like no more than 5 minutes per test across all languages when doing stess tests
                                if (stopWatch.Elapsed.TotalSeconds > maxSecondsPerTestPerLanguage && repeatCounter <= repeat - 1)
                                {
                                    runTests.Log(string.Format("# Breaking repeat test at count {0} of requested {1} (at {2} minutes), to allow other tests and languages to run.\r\n", repeatCounter, repeat, stopWatch.Elapsed.TotalMinutes));
                                    break;
                                }
                            }
                        }
                        if (profiling)
                        {
                            break;
                        }
                    }
                }

                foreach (var removeTest in removeList)
                {
                    testList.Remove(removeTest);
                }
                removeList.Clear();
                runTests.AddSmallMoleculeNodes = addsmallmoleculenodes && (flip = !flip); // Do this in every other pass, so we get it both ways
            }

            return(runTests.FailureCount == 0);
        }