⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 285132 in webkit


Ignore:
Timestamp:
Nov 1, 2021, 2:30:38 PM (5 years ago)
Author:
timothy_horton@apple.com
Message:

Add a run-webkit-tests mode to A/B test a given feature
​https://bugs.webkit.org/show_bug.cgi?id=232553

Reviewed by Jonathan Bedard.

Add the argument --self-compare-with-header to run-webkit-tests, which
can be used to test the impact of a given feature (or set of features;
it accepts the standard test features header format).

When tests are run in this mode, all tests are run in the ref-test
style, but with the expected and actual results loading the same
test file (ignoring the usual -expected.html or whatever); they differ
only in the set of features/preferences enabled.

This is especially useful for testing the impact of e.g. platform
graphics features, where the difference between the shipping behavior
and in-development behavior is more interesting than whether or not
it actually makes the tests, as written, fail.

  • Scripts/webkitpy/layout_tests/controllers/single_test_runner.py:

(SingleTestRunner):
(SingleTestRunner._run_comparison_test):
Add the comparison test runner, and prefer it if requested.

One note here: the run with the options derived from the given header is
considered the "actual" result and the default configuration the "expected".

  • Scripts/webkitpy/layout_tests/run_webkit_tests.py:

(parse_args):

  • Scripts/webkitpy/port/driver.py:

(DriverInput.init):
(DriverInput.repr):
(Driver._command_from_driver_input):
Pass the comparison test header along to the test runner.

Also, fix a longstanding error where --dump-jsconsolelog-in-stderr
could get inserted immediately after --pixel-test, causing the test runner
to consume it as the expected image hash! And leave a comment so nobody
else has to debug this again...

  • TestRunnerShared/TestCommand.cpp:

(WTR::parseInputLine):

  • TestRunnerShared/TestCommand.h:
  • TestRunnerShared/TestFeatures.cpp:

(WTR::parseTestHeaderString):
(WTR::parseTestHeader):
(WTR::featureDefaultsFromComparisonTestHeader):
Factor out the parsing of the part of the test header inside the [ ],
since we use this format for the value of --self-compare-with-header as well.

  • TestRunnerShared/TestFeatures.h:
  • WebKitTestRunner/Options.h:
  • WebKitTestRunner/TestController.cpp:

(WTR::TestController::testOptionsForTest const):
Merge the comparison header's options in to the test options before
the test's own header, so that the comparison header wins.

Location:
trunk/Tools
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r285131 r285132  
     12021-11-01  Tim Horton  <timothy_horton@apple.com>
     2
     3        Add a run-webkit-tests mode to A/B test a given feature
     4        https://bugs.webkit.org/show_bug.cgi?id=232553
     5
     6        Reviewed by Jonathan Bedard.
     7
     8        Add the argument --self-compare-with-header to run-webkit-tests, which
     9        can be used to test the impact of a given feature (or set of features;
     10        it accepts the standard test features header format).
     11
     12        When tests are run in this mode, all tests are run in the ref-test
     13        style, but with the `expected` and `actual` results loading the same
     14        test file (ignoring the usual -expected.html or whatever); they differ
     15        only in the set of features/preferences enabled.
     16
     17        This is especially useful for testing the impact of e.g. platform
     18        graphics features, where the difference between the shipping behavior
     19        and in-development behavior is more interesting than whether or not
     20        it actually makes the tests, as written, fail.
     21
     22        * Scripts/webkitpy/layout_tests/controllers/single_test_runner.py:
     23        (SingleTestRunner):
     24        (SingleTestRunner._run_comparison_test):
     25        Add the comparison test runner, and prefer it if requested.
     26
     27        One note here: the run with the options derived from the given header is
     28        considered the "actual" result and the default configuration the "expected".
     29
     30        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
     31        (parse_args):
     32        * Scripts/webkitpy/port/driver.py:
     33        (DriverInput.__init__):
     34        (DriverInput.__repr__):
     35        (Driver._command_from_driver_input):
     36        Pass the comparison test header along to the test runner.
     37
     38        Also, fix a longstanding error where --dump-jsconsolelog-in-stderr
     39        could get inserted immediately after --pixel-test, causing the test runner
     40        to consume it as the expected image hash! And leave a comment so nobody
     41        else has to debug this again...
     42
     43        * TestRunnerShared/TestCommand.cpp:
     44        (WTR::parseInputLine):
     45        * TestRunnerShared/TestCommand.h:
     46        * TestRunnerShared/TestFeatures.cpp:
     47        (WTR::parseTestHeaderString):
     48        (WTR::parseTestHeader):
     49        (WTR::featureDefaultsFromComparisonTestHeader):
     50        Factor out the parsing of the part of the test header inside the [ ],
     51        since we use this format for the value of --self-compare-with-header as well.
     52
     53        * TestRunnerShared/TestFeatures.h:
     54        * WebKitTestRunner/Options.h:
     55        * WebKitTestRunner/TestController.cpp:
     56        (WTR::TestController::testOptionsForTest const):
     57        Merge the comparison header's options in to the test options before
     58        the test's own header, so that the comparison header wins.
     59
    1602021-11-01  Jonathan Bedard  <jbedard@apple.com>
    261
  • trunk/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py

    r284987 r285132  
    112112
    113113    def run(self):
     114        self_comparison_header = self._port.get_option('self_compare_with_header')
     115        if self_comparison_header:
     116            return self._run_self_comparison_test(self_comparison_header)
    114117        if self._reference_files:
    115118            if self._port.get_option('no_ref_tests') or self._options.reset_results:
    … …  
    337340        return TestResult(self._test_input, test_result.failures, total_test_time + test_result.test_run_time, test_result.has_stderr, reftest_type=reftest_type, pid=test_result.pid, references=reference_test_names)
    338341
     342    def _run_self_comparison_test(self, header):
     343        driver_input = self._driver_input()
     344        driver_input.should_run_pixel_test = True
     345
     346        reference_output = self._driver.run_test(driver_input, self._stop_when_done)
     347        driver_input.self_comparison_header = header
     348        test_output = self._driver.run_test(driver_input, self._stop_when_done)
     349
     350        test_full_path = self._port.abspath_for_test(self._test_name)
     351        test_result = self._compare_output_with_reference(reference_output, test_output, test_full_path, False)
     352
     353        assert(reference_output)
     354        test_result_writer.write_test_result(self._filesystem, self._port, self._results_directory, self._test_name, test_output, reference_output, test_result.failures)
     355        return TestResult(self._test_input, test_result.failures, test_result.test_run_time, test_result.has_stderr, pid=test_result.pid)
     356
    339357    @staticmethod
    340358    def _relative_reference_path(test_full_path, reference_full_path):
  • trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py

    r281649 r285132  
    344344            "--prefer-integrated-gpu", action="store_true", default=False,
    345345            help=("Prefer using the lower-power integrated GPU on a dual-GPU system. Note that other running applications and the tests themselves can override this request.")),
    346         optparse.make_option('--show-window', action="store_true", default=False, help="Make the test runner window visible during testing."),
     346        optparse.make_option("--show-window", action="store_true", default=False, help="Make the test runner window visible during testing."),
     347        optparse.make_option("--self-compare-with-header", help="Run all tests as A/B tests between the default configuration and the given test features header (ignoring expected results)."),
    347348    ]))
    348349
  • trunk/Tools/Scripts/webkitpy/port/driver.py

    r282347 r285132  
    4747
    4848class DriverInput(object):
    49     def __init__(self, test_name, timeout, image_hash, should_run_pixel_test, should_dump_jsconsolelog_in_stderr=None, args=None):
     49    def __init__(self, test_name, timeout, image_hash, should_run_pixel_test, should_dump_jsconsolelog_in_stderr=None, args=None, self_comparison_header=None):
    5050        self.test_name = test_name
    5151        self.timeout = timeout  # in ms
    … …  
    5454        self.should_dump_jsconsolelog_in_stderr = should_dump_jsconsolelog_in_stderr
    5555        self.args = args or []
     56        self.self_comparison_header = self_comparison_header
    5657
    5758    def __repr__(self):
    58         return "DriverInput(test_name='{}', timeout={}, image_hash={}, should_run_pixel_test={}, should_dump_jsconsolelog_in_stderr={}'".format(self.test_name, self.timeout, self.image_hash, self.should_run_pixel_test, self.should_dump_jsconsolelog_in_stderr)
     59        return "DriverInput(test_name='{}', timeout={}, image_hash={}, should_run_pixel_test={}, should_dump_jsconsolelog_in_stderr={}, self_comparison_header={}'".format(self.test_name, self.timeout, self.image_hash, self.should_run_pixel_test, self.should_dump_jsconsolelog_in_stderr, self.self_comparison_header)
    5960
    6061
    … …  
    632633        if self._port.supports_per_test_timeout():
    633634            command += "'--timeout'%s" % driver_input.timeout
     635        if driver_input.should_dump_jsconsolelog_in_stderr:
     636            command += "'--dump-jsconsolelog-in-stderr"
     637        if driver_input.self_comparison_header:
     638            command += "'--self-compare-with-header'%s" % driver_input.self_comparison_header
     639
     640        # --pixel-test must be the last argument, because the hash is optional,
     641        # and any argument put in its place will be incorrectly consumed as the hash.
    634642        if driver_input.should_run_pixel_test:
    635643            command += "'--pixel-test"
    636         if driver_input.should_dump_jsconsolelog_in_stderr:
    637             command += "'--dump-jsconsolelog-in-stderr"
    638         if driver_input.image_hash:
    639             command += "'" + driver_input.image_hash
     644            if driver_input.image_hash:
     645                command += "'" + driver_input.image_hash
    640646        return command + "\n"
    641647
  • trunk/Tools/TestRunnerShared/TestCommand.cpp

    r277317 r285132  
    9999            if (tokenizer.hasNext())
    100100                result.expectedPixelHash = tokenizer.next();
     101        } else if (arg == "--self-compare-with-header") {
     102            if (tokenizer.hasNext())
     103                result.selfComparisonHeader = tokenizer.next();
     104            else
     105                die(inputLine);
    101106        } else if (arg == std::string("--dump-jsconsolelog-in-stderr"))
    102107            result.dumpJSConsoleLogInStdErr = true;
  • trunk/Tools/TestRunnerShared/TestCommand.h

    r268370 r285132  
    3636    std::filesystem::path absolutePath;
    3737    std::string expectedPixelHash;
     38    std::string selfComparisonHeader;
    3839    WTF::Seconds timeout;
    3940    bool shouldDumpPixels { false };
  • trunk/Tools/TestRunnerShared/TestFeatures.cpp

    r278540 r285132  
    244244}
    245245
    246 static TestFeatures parseTestHeader(std::filesystem::path path, const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMap)
     246static TestFeatures parseTestHeaderString(const std::string& pairString, std::filesystem::path path, const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMap)
    247247{
    248248    TestFeatures features;
    249     std::error_code ec;
    250     if (!std::filesystem::exists(path, ec))
    251         return features;
    252 
    253     std::ifstream file(path);
    254     if (!file.good()) {
    255         LOG_ERROR("Could not open file to inspect test headers in %s", path.c_str());
    256         return features;
    257     }
    258 
    259     std::string options;
    260     getline(file, options);
    261     std::string beginString("webkit-test-runner [ ");
    262     std::string endString(" ]");
    263     size_t beginLocation = options.find(beginString);
    264     if (beginLocation == std::string::npos)
    265         return features;
    266     size_t endLocation = options.find(endString, beginLocation);
    267     if (endLocation == std::string::npos) {
    268         LOG_ERROR("Could not find end of test header in %s", path.c_str());
    269         return features;
    270     }
    271     std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
     249
    272250    size_t pairStart = 0;
    273251    while (pairStart < pairString.size()) {
    … …  
    292270}
    293271
     272static TestFeatures parseTestHeader(std::filesystem::path path, const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMap)
     273{
     274    std::error_code ec;
     275    if (!std::filesystem::exists(path, ec))
     276        return { };
     277
     278    std::ifstream file(path);
     279    if (!file.good()) {
     280        LOG_ERROR("Could not open file to inspect test headers in %s", path.c_str());
     281        return { };
     282    }
     283
     284    std::string options;
     285    getline(file, options);
     286    std::string beginString("webkit-test-runner [ ");
     287    std::string endString(" ]");
     288    size_t beginLocation = options.find(beginString);
     289    if (beginLocation == std::string::npos)
     290        return { };
     291    size_t endLocation = options.find(endString, beginLocation);
     292    if (endLocation == std::string::npos) {
     293        LOG_ERROR("Could not find end of test header in %s", path.c_str());
     294        return { };
     295    }
     296    std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
     297    return parseTestHeaderString(pairString, path, keyTypeMap);
     298}
     299
    294300TestFeatures featureDefaultsFromTestHeaderForTest(const TestCommand& command, const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMap)
    295301{
    … …  
    297303}
    298304
    299 }
     305TestFeatures featureDefaultsFromSelfComparisonHeader(const TestCommand& command, const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMap)
     306{
     307    if (command.selfComparisonHeader.empty())
     308        return { };
     309    return parseTestHeaderString(command.selfComparisonHeader, command.absolutePath, keyTypeMap);
     310}
     311
     312} // namespace WTF
  • trunk/Tools/TestRunnerShared/TestFeatures.h

    r269390 r285132  
    7070};
    7171TestFeatures featureDefaultsFromTestHeaderForTest(const TestCommand&, const std::unordered_map<std::string, TestHeaderKeyType>&);
     72TestFeatures featureDefaultsFromSelfComparisonHeader(const TestCommand&, const std::unordered_map<std::string, TestHeaderKeyType>&);
    7273
    7374}
  • trunk/Tools/WebKitTestRunner/TestController.cpp

    r284610 r285132  
    13121312    merge(features, hardcodedFeaturesBasedOnPathForTest(command));
    13131313    merge(features, platformSpecificFeatureDefaultsForTest(command));
     1314    merge(features, featureDefaultsFromSelfComparisonHeader(command, TestOptions::keyTypeMapping()));
    13141315    merge(features, featureDefaultsFromTestHeaderForTest(command, TestOptions::keyTypeMapping()));
    13151316    merge(features, platformSpecificFeatureOverridesDefaultsForTest(command));
Note: See TracChangeset for help on using the changeset viewer.