tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

tcuTestCase.js (17153B)


      1 /*-------------------------------------------------------------------------
      2 * drawElements Quality Program OpenGL ES Utilities
      3 * ------------------------------------------------
      4 *
      5 * Copyright 2014 The Android Open Source Project
      6 *
      7 * Licensed under the Apache License, Version 2.0 (the "License");
      8 * you may not use this file except in compliance with the License.
      9 * You may obtain a copy of the License at
     10 *
     11 *      http://www.apache.org/licenses/LICENSE-2.0
     12 *
     13 * Unless required by applicable law or agreed to in writing, software
     14 * distributed under the License is distributed on an "AS IS" BASIS,
     15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16 * See the License for the specific language governing permissions and
     17 * limitations under the License.
     18 *
     19 */
     20 
     21 /**
     22 * This class allows one to create a hierarchy of tests and iterate over them.
     23 * It replaces TestCase and TestCaseGroup classes.
     24 */
     25 'use strict';
     26 goog.provide('framework.common.tcuTestCase');
     27 goog.require('framework.common.tcuSkipList');
     28 
     29 goog.scope(function() {
     30 
     31    var tcuTestCase = framework.common.tcuTestCase;
     32    var tcuSkipList = framework.common.tcuSkipList;
     33 
     34    tcuTestCase.getQueryVal = function(key) {
     35        const queryVars = window.location.search.substring(1).split('&');
     36        for (let kv of queryVars) {
     37            kv = kv.split('=');
     38            if (decodeURIComponent(kv[0]) === key)
     39                return decodeURIComponent(kv[1]);
     40        }
     41        return null;
     42    };
     43 
     44    tcuTestCase.isQuickMode = () => tcuTestCase.getQueryVal('quick') === '1';
     45    tcuTestCase.isQuietMode = () => tcuTestCase.getQueryVal('quiet') === '1';
     46 
     47    /**
     48     * Reads the filter parameter from the URL to filter tests.
     49     * @return {?string }
     50     */
     51    tcuTestCase.getFilter = () => tcuTestCase.getQueryVal('filter');
     52 
     53    /**
     54     * Indicates the state of an iteration operation.
     55     * @enum {number}
     56     */
     57    tcuTestCase.IterateResult = {
     58        STOP: 0,
     59        CONTINUE: 1
     60    };
     61 
     62    /****************************************
     63    * Runner
     64    ***************************************/
     65 
     66    /**
     67    * A simple state machine.
     68    * The purpose of this this object is to break
     69    * long tests into small chunks that won't cause a timeout
     70    * @constructor
     71    */
     72    tcuTestCase.Runner = function() {
     73        /** @type {tcuTestCase.DeqpTest} */ this.currentTest = null;
     74        /** @type {tcuTestCase.DeqpTest} */ this.nextTest = null;
     75        /** @type {tcuTestCase.DeqpTest} */ this.testCases = null;
     76        /** @type {?string } */ this.filter = tcuTestCase.getFilter();
     77    };
     78 
     79    /**
     80    * @param {tcuTestCase.DeqpTest} root The root test of the test tree.
     81    */
     82    tcuTestCase.Runner.prototype.setRoot = function(root) {
     83        this.currentTest = null;
     84        this.testCases = root;
     85    };
     86 
     87    tcuTestCase.Runner.prototype.setRange = function(range) {
     88        this.range = range;
     89    };
     90 
     91    /**
     92    * Searches the test tree for the next executable test
     93    * @return {?tcuTestCase.DeqpTest }
     94    */
     95    tcuTestCase.Runner.prototype.next = function() {
     96 
     97        // First time? Use root test
     98        if (!this.currentTest) {
     99            this.currentTest = this.testCases;
    100 
    101            // Root is executable? Use it
    102            if (this.currentTest.isExecutable())
    103                return this.currentTest;
    104        }
    105 
    106        // Should we proceed with the next test?
    107        if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP) {
    108            // Look for next executable test
    109            do {
    110                if (this.range)
    111                    this.currentTest = this.currentTest.nextInRange(this.filter, this.range);
    112                else
    113                    this.currentTest = this.currentTest.next(this.filter);
    114            } while (this.currentTest && !this.currentTest.isExecutable());
    115        }
    116 
    117        return this.currentTest;
    118    };
    119 
    120    /**
    121    * Schedule the callback to be run ASAP
    122    * @param {function()} callback Callback to schedule
    123    */
    124    tcuTestCase.Runner.prototype.runCallback = function(callback) {
    125        setTimeout(function() {
    126            callback();
    127        }.bind(this), 0);
    128    };
    129 
    130    /**
    131    * Call this function at the end of the test
    132    */
    133    tcuTestCase.Runner.prototype.terminate = function() {
    134        finishTest();
    135        if (!tcuTestCase.isQuietMode()) {
    136            console.log('finishTest() after (in ms):', performance.now());
    137        }
    138    };
    139 
    140    tcuTestCase.runner = new tcuTestCase.Runner();
    141 
    142    /** @type {tcuTestCase.IterateResult} */ tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
    143 
    144    /***************************************
    145    * DeqpTest
    146    ***************************************/
    147 
    148    /**
    149    * Assigns name, description and specification to test
    150    * @constructor
    151    * @param {?string} name
    152    * @param {?string} description
    153    * @param {Object=} spec
    154    */
    155    tcuTestCase.DeqpTest = function(name, description, spec) {
    156        this.name = name || '';
    157        this.description = description || '';
    158        this.spec = spec;
    159        this.currentTestNdx = 0;
    160        this.parentTest = null;
    161        this.childrenTests = [];
    162        this.executeAlways = false;
    163    };
    164 
    165    /**
    166     * Abstract init function(each particular test will implement it, or not)
    167     */
    168    tcuTestCase.DeqpTest.prototype.init = function() {};
    169 
    170    /**
    171     * Abstract deinit function(each particular test will implement it, or not)
    172     */
    173    tcuTestCase.DeqpTest.prototype.deinit = function() {};
    174 
    175    /**
    176     * Abstract iterate function(each particular test will implement it, or not)
    177     * @return {tcuTestCase.IterateResult}
    178     */
    179    tcuTestCase.DeqpTest.prototype.iterate = function() { return tcuTestCase.IterateResult.STOP; };
    180 
    181    /**
    182    * Checks if the test is executable
    183    * @return {boolean}
    184    */
    185    tcuTestCase.DeqpTest.prototype.isExecutable = function() {
    186        return this.childrenTests.length == 0 || this.executeAlways;
    187    };
    188 
    189    /**
    190     * Checks if the test is a leaf
    191     */
    192    tcuTestCase.DeqpTest.prototype.isLeaf = function() {
    193        return this.childrenTests.length == 0;
    194    };
    195 
    196    /**
    197     * Marks the test as always executable
    198     */
    199    tcuTestCase.DeqpTest.prototype.makeExecutable = function() {
    200        this.executeAlways = true;
    201    };
    202 
    203    /**
    204    * Adds a child test to the test's children
    205    * @param {tcuTestCase.DeqpTest} test
    206    */
    207    tcuTestCase.DeqpTest.prototype.addChild = function(test) {
    208        test.parentTest = this;
    209        this.childrenTests.push(test);
    210    };
    211 
    212    /**
    213     * Sets the whole children tests array
    214     * @param {Array<tcuTestCase.DeqpTest>} tests
    215     */
    216    tcuTestCase.DeqpTest.prototype.setChildren = function(tests) {
    217        for (var test in tests)
    218            tests[test].parentTest = this;
    219        this.childrenTests = tests;
    220    };
    221 
    222    /**
    223    * Returns the next test in the hierarchy of tests
    224    *
    225    * @param {?string } pattern Optional pattern to search for
    226    * @return {tcuTestCase.DeqpTest}
    227    */
    228    tcuTestCase.DeqpTest.prototype.next = function(pattern) {
    229        return this._nextHonoringSkipList(pattern);
    230    };
    231 
    232    /**
    233    * Returns the next test in the hierarchy of tests, honoring the
    234    * skip list, and reporting skipped tests.
    235    *
    236    * @param {?string } pattern Optional pattern to search for
    237    * @return {tcuTestCase.DeqpTest}
    238    */
    239    tcuTestCase.DeqpTest.prototype._nextHonoringSkipList = function(pattern) {
    240        var tryAgain = false;
    241        var test = null;
    242        do {
    243            tryAgain = false;
    244            test = this._nextIgnoringSkipList(pattern);
    245            if (test != null) {
    246                // See whether the skip list vetoes the execution of
    247                // this test.
    248                var fullTestName = test.fullName();
    249                var skipDisposition = tcuSkipList.getSkipStatus(fullTestName);
    250                if (skipDisposition.skip) {
    251                    tryAgain = true;
    252                    setCurrentTestName(fullTestName);
    253                    checkMessage(false, 'Skipping test due to tcuSkipList: ' + fullTestName);
    254                }
    255            }
    256        } while (tryAgain);
    257        return test;
    258    };
    259 
    260 
    261    /**
    262    * Returns the next test in the hierarchy of tests, ignoring the
    263    * skip list.
    264    *
    265    * @param {?string } pattern Optional pattern to search for
    266    * @return {tcuTestCase.DeqpTest}
    267    */
    268    tcuTestCase.DeqpTest.prototype._nextIgnoringSkipList = function(pattern) {
    269        if (pattern)
    270            return this._findIgnoringSkipList(pattern);
    271 
    272        var test = null;
    273 
    274        //Look for the next child
    275        if (this.currentTestNdx < this.childrenTests.length) {
    276            test = this.childrenTests[this.currentTestNdx];
    277            this.currentTestNdx++;
    278        }
    279 
    280        // If no more children, get the next brother
    281        if (test == null && this.parentTest != null) {
    282            test = this.parentTest._nextIgnoringSkipList(null);
    283        }
    284 
    285        return test;
    286    };
    287 
    288    /**
    289    * Returns the next test in the hierarchy of tests
    290    * whose 1st level is in the given range
    291    *
    292    * @param {?string } pattern Optional pattern to search for
    293    * @param {Array<number>} range
    294    * @return {tcuTestCase.DeqpTest}
    295    */
    296    tcuTestCase.DeqpTest.prototype.nextInRange = function(pattern, range) {
    297        while (true) {
    298            var test = this._nextHonoringSkipList(pattern);
    299            if (!test)
    300                return null;
    301            var topLevelId = tcuTestCase.runner.testCases.currentTestNdx - 1;
    302            if (topLevelId >= range[0] && topLevelId < range[1])
    303                return test;
    304        }
    305    };
    306 
    307    /**
    308    * Returns the full name of the test
    309    *
    310    * @return {string} Full test name.
    311    */
    312    tcuTestCase.DeqpTest.prototype.fullName = function() {
    313        if (this.parentTest) {
    314            var parentName = this.parentTest.fullName();
    315            if (parentName)
    316                return parentName + '.' + this.name;
    317        }
    318        return this.name;
    319    };
    320 
    321    /**
    322    * Returns the description of the test
    323    *
    324    * @return {string} Test description.
    325    */
    326    tcuTestCase.DeqpTest.prototype.getDescription = function() {
    327        return this.description;
    328    };
    329 
    330    /**
    331    * Find a test with a matching name.  Fast-forwards to a test whose
    332    * full name matches the given pattern.
    333    *
    334    * @param {string} pattern Regular expression to search for
    335    * @return {?tcuTestCase.DeqpTest } Found test or null.
    336    */
    337    tcuTestCase.DeqpTest.prototype.find = function(pattern) {
    338        return this._findHonoringSkipList(pattern);
    339    };
    340 
    341    /**
    342    * Find a test with a matching name. Fast-forwards to a test whose
    343    * full name matches the given pattern, honoring the skip list, and
    344    * reporting skipped tests.
    345    *
    346    * @param {string} pattern Regular expression to search for
    347    * @return {?tcuTestCase.DeqpTest } Found test or null.
    348    */
    349    tcuTestCase.DeqpTest.prototype._findHonoringSkipList = function(pattern) {
    350        var tryAgain = false;
    351        var test = null;
    352        do {
    353            tryAgain = false;
    354            test = this._findIgnoringSkipList(pattern);
    355            if (test != null) {
    356                // See whether the skip list vetoes the execution of
    357                // this test.
    358                var fullTestName = test.fullName();
    359                var skipDisposition = tcuSkipList.getSkipStatus(fullTestName);
    360                if (skipDisposition.skip) {
    361                    tryAgain = true;
    362                    checkMessage(false, 'Skipping test due to tcuSkipList: ' + fullTestName);
    363                }
    364            }
    365        } while (tryAgain);
    366        return test;
    367    };
    368 
    369    /**
    370    * Find a test with a matching name. Fast-forwards to a test whose
    371    * full name matches the given pattern.
    372    *
    373    * @param {string} pattern Regular expression to search for
    374    * @return {?tcuTestCase.DeqpTest } Found test or null.
    375    */
    376    tcuTestCase.DeqpTest.prototype._findIgnoringSkipList = function(pattern) {
    377        var test = this;
    378        while (true) {
    379            test = test._nextIgnoringSkipList(null);
    380            if (!test)
    381                break;
    382            if (test.fullName().match(pattern) || test.executeAlways)
    383                break;
    384        }
    385        return test;
    386    };
    387 
    388    /**
    389    * Reset the iterator.
    390    */
    391    tcuTestCase.DeqpTest.prototype.reset = function() {
    392        this.currentTestNdx = 0;
    393 
    394        for (var i = 0; i < this.childrenTests.length; i++)
    395            this.childrenTests[i].reset();
    396    };
    397 
    398    /**
    399    * Defines a new test
    400    *
    401    * @param {?string} name Short test name
    402    * @param {?string} description Description of the test
    403    * @param {Object=} spec Test specification
    404    *
    405    * @return {tcuTestCase.DeqpTest} The new test
    406    */
    407    tcuTestCase.newTest = function(name, description, spec) {
    408        var test = new tcuTestCase.DeqpTest(name, description, spec);
    409 
    410        return test;
    411    };
    412 
    413    /**
    414    * Defines a new executable test so it gets run even if it's not a leaf
    415    *
    416    * @param {string} name Short test name
    417    * @param {string} description Description of the test
    418    * @param {Object=} spec Test specification
    419    *
    420    * @return {tcuTestCase.DeqpTest} The new test
    421    */
    422    tcuTestCase.newExecutableTest = function(name, description, spec) {
    423        var test = tcuTestCase.newTest(name, description, spec);
    424        test.makeExecutable();
    425 
    426        return test;
    427    };
    428 
    429    /**
    430    * Run through the test cases giving time to system operation.
    431    */
    432    tcuTestCase.runTestCases = function() {
    433        var state = tcuTestCase.runner;
    434 
    435        if (state.next()) {
    436            try {
    437                // If proceeding with the next test, prepare it.
    438                var fullTestName = state.currentTest.fullName();
    439                var inited = true;
    440                if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP) {
    441                    // Update current test name
    442                    setCurrentTestName(fullTestName);
    443                    bufferedLogToConsole('Init testcase: ' + fullTestName); //Show also in console so we can see which test crashed the browser's tab
    444 
    445                    // Initialize particular test
    446                    inited = state.currentTest.init();
    447                    inited = inited === undefined ? true : inited;
    448 
    449                    //If it's a leaf test, notify of it's execution.
    450                    if (state.currentTest.isLeaf() && inited)
    451                        debug('<hr/><br/>Start testcase: ' + fullTestName);
    452                }
    453 
    454                if (inited) {
    455                    // Run the test, save the result.
    456 
    457                    const debug = tcuTestCase._debug = tcuTestCase._debug || (() => {
    458                        function LapStopwatch() {
    459                            this.lap = function() {
    460                                const now = performance.now();
    461                                const ret = now - this.last;
    462                                this.last = now;
    463                                return ret;
    464                            };
    465                            this.lap();
    466                        }
    467                        return {
    468                            stopwatch: new LapStopwatch(),
    469                            testDoneCount: 0,
    470                        };
    471                    })();
    472                    const overheadDur = debug.stopwatch.lap();
    473 
    474                    tcuTestCase.lastResult = state.currentTest.iterate();
    475 
    476                    const testDur = debug.stopwatch.lap();
    477                    debug.testDoneCount += 1;
    478                    console.log(
    479                        `[test ${debug.testDoneCount}] Ran in ${testDur}ms`,
    480                        `(+ ${overheadDur}ms overhead)`,
    481                    );
    482                } else {
    483                    // Skip uninitialized test.
    484                    tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
    485                }
    486 
    487                // Cleanup
    488                if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP)
    489                    state.currentTest.deinit();
    490            }
    491            catch (err) {
    492                // If the exception was not thrown by a test check, log it, but don't throw it again
    493                if (!(err instanceof TestFailedException)) {
    494                    //Stop execution of current test.
    495                    tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
    496                    try {
    497                        // Cleanup
    498                        if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP)
    499                            state.currentTest.deinit();
    500                    } catch (cerr) {
    501                        bufferedLogToConsole('Error while cleaning up test: ' + cerr);
    502                    }
    503                    var msg = err;
    504                    if (err.message)
    505                        msg = err.message;
    506                    testFailedOptions(msg, false);
    507                }
    508                bufferedLogToConsole(err);
    509            }
    510 
    511            tcuTestCase.runner.runCallback(tcuTestCase.runTestCases);
    512        } else {
    513            tcuTestCase.runner.terminate();
    514        }
    515    };
    516 });