15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (c) 2010 Google Inc. All rights reserved.
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Redistribution and use in source and binary forms, with or without
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# modification, are permitted provided that the following conditions are
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# met:
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions of source code must retain the above copyright
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# notice, this list of conditions and the following disclaimer.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions in binary form must reproduce the above
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# in the documentation and/or other materials provided with the
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# distribution.
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Neither the name of Google Inc. nor the names of its
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# contributors may be used to endorse or promote products derived from
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# this software without specific prior written permission.
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import fnmatch
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import os
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import os.path
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import BaseHTTPServer
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.layout_tests.port.base import Port
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.tool.servers.reflectionhandler import ReflectionHandler
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)STATE_NEEDS_REBASELINE = 'needs_rebaseline'
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)STATE_REBASELINE_FAILED = 'rebaseline_failed'
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)STATE_REBASELINE_SUCCEEDED = 'rebaseline_succeeded'
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _get_actual_result_files(test_file, test_config):
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_name, _ = os.path.splitext(test_file)
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_directory = os.path.dirname(test_file)
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_results_directory = test_config.filesystem.join(
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_config.results_directory, test_directory)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    actual_pattern = os.path.basename(test_name) + '-actual.*'
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    actual_files = []
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for filename in test_config.filesystem.listdir(test_results_directory):
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if fnmatch.fnmatch(filename, actual_pattern):
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            actual_files.append(filename)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    actual_files.sort()
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return tuple(actual_files)
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _rebaseline_test(test_file, baseline_target, baseline_move_to, test_config, log):
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_name, _ = os.path.splitext(test_file)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_directory = os.path.dirname(test_name)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    log('Rebaselining %s...' % test_name)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    actual_result_files = _get_actual_result_files(test_file, test_config)
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    filesystem = test_config.filesystem
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scm = test_config.scm
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    layout_tests_directory = test_config.layout_tests_directory
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    results_directory = test_config.results_directory
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    target_expectations_directory = filesystem.join(
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        layout_tests_directory, 'platform', baseline_target, test_directory)
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_results_directory = test_config.filesystem.join(
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_config.results_directory, test_directory)
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # If requested, move current baselines out
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    current_baselines = get_test_baselines(test_file, test_config)
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if baseline_target in current_baselines and baseline_move_to != 'none':
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        log('  Moving current %s baselines to %s' %
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            (baseline_target, baseline_move_to))
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # See which ones we need to move (only those that are about to be
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # updated), and make sure we're not clobbering any files in the
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # destination.
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        current_extensions = set(current_baselines[baseline_target].keys())
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        actual_result_extensions = [
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            os.path.splitext(f)[1] for f in actual_result_files]
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        extensions_to_move = current_extensions.intersection(
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            actual_result_extensions)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if extensions_to_move.intersection(
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            current_baselines.get(baseline_move_to, {}).keys()):
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            log('    Already had baselines in %s, could not move existing '
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                '%s ones' % (baseline_move_to, baseline_target))
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Do the actual move.
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if extensions_to_move:
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if not _move_test_baselines(
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                test_file,
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                list(extensions_to_move),
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                baseline_target,
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                baseline_move_to,
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                test_config,
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                log):
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return False
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            log('    No current baselines to move')
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    log('  Updating baselines for %s' % baseline_target)
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    filesystem.maybe_make_directory(target_expectations_directory)
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for source_file in actual_result_files:
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        source_path = filesystem.join(test_results_directory, source_file)
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        destination_file = source_file.replace('-actual', '-expected')
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        destination_path = filesystem.join(
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            target_expectations_directory, destination_file)
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        filesystem.copyfile(source_path, destination_path)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        exit_code = scm.add(destination_path, return_exit_code=True)
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if exit_code:
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            log('    Could not update %s in SCM, exit code %d' %
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (destination_file, exit_code))
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            log('    Updated %s' % destination_file)
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return True
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _move_test_baselines(test_file, extensions_to_move, source_platform, destination_platform, test_config, log):
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_file_name = os.path.splitext(os.path.basename(test_file))[0]
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_directory = os.path.dirname(test_file)
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    filesystem = test_config.filesystem
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Want predictable output order for unit tests.
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    extensions_to_move.sort()
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    source_directory = os.path.join(
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_config.layout_tests_directory,
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        'platform',
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        source_platform,
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_directory)
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    destination_directory = os.path.join(
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_config.layout_tests_directory,
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        'platform',
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        destination_platform,
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_directory)
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    filesystem.maybe_make_directory(destination_directory)
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for extension in extensions_to_move:
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        file_name = test_file_name + '-expected' + extension
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        source_path = filesystem.join(source_directory, file_name)
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        destination_path = filesystem.join(destination_directory, file_name)
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        filesystem.copyfile(source_path, destination_path)
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        exit_code = test_config.scm.add(destination_path, return_exit_code=True)
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if exit_code:
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            log('    Could not update %s in SCM, exit code %d' %
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                (file_name, exit_code))
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            log('    Moved %s' % file_name)
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return True
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def get_test_baselines(test_file, test_config):
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # FIXME: This seems like a hack. This only seems used to access the Port.expected_baselines logic.
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    class AllPlatformsPort(Port):
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        def __init__(self, host):
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            super(AllPlatformsPort, self).__init__(host, 'mac')
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._platforms_by_directory = dict([(self._webkit_baseline_path(p), p) for p in test_config.platforms])
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        def baseline_search_path(self):
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return self._platforms_by_directory.keys()
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        def platform_from_directory(self, directory):
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return self._platforms_by_directory[directory]
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    test_path = test_config.filesystem.join(test_config.layout_tests_directory, test_file)
1777242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    host = test_config.host
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    all_platforms_port = AllPlatformsPort(host)
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    all_test_baselines = {}
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for baseline_extension in ('.txt', '.checksum', '.png'):
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_baselines = test_config.test_port.expected_baselines(test_file, baseline_extension)
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        baselines = all_platforms_port.expected_baselines(test_file, baseline_extension, all_baselines=True)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for platform_directory, expected_filename in baselines:
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if not platform_directory:
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if platform_directory == test_config.layout_tests_directory:
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                platform = 'base'
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else:
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                platform = all_platforms_port.platform_from_directory(platform_directory)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            platform_baselines = all_test_baselines.setdefault(platform, {})
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            was_used_for_test = (platform_directory, expected_filename) in test_baselines
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            platform_baselines[baseline_extension] = was_used_for_test
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return all_test_baselines
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class RebaselineHTTPServer(BaseHTTPServer.HTTPServer):
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, httpd_port, config):
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        server_name = ""
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        BaseHTTPServer.HTTPServer.__init__(self, (server_name, httpd_port), RebaselineHTTPRequestHandler)
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.test_config = config['test_config']
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.results_json = config['results_json']
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.platforms_json = config['platforms_json']
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class RebaselineHTTPRequestHandler(ReflectionHandler):
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    STATIC_FILE_NAMES = frozenset([
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "index.html",
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "loupe.js",
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "main.js",
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "main.css",
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "queue.js",
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "util.js",
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ])
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    STATIC_FILE_DIRECTORY = os.path.join(os.path.dirname(__file__), "data", "rebaselineserver")
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def results_json(self):
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._serve_json(self.server.results_json)
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def test_config(self):
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._serve_json(self.server.test_config)
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def platforms_json(self):
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._serve_json(self.server.platforms_json)
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def rebaseline(self):
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test = self.query['test'][0]
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        baseline_target = self.query['baseline-target'][0]
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        baseline_move_to = self.query['baseline-move-to'][0]
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_json = self.server.results_json['tests'][test]
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if test_json['state'] != STATE_NEEDS_REBASELINE:
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.send_error(400, "Test %s is in unexpected state: %s" % (test, test_json["state"]))
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        log = []
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        success = _rebaseline_test(
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            test,
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            baseline_target,
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            baseline_move_to,
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.server.test_config,
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            log=lambda l: log.append(l))
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if success:
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            test_json['state'] = STATE_REBASELINE_SUCCEEDED
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.send_response(200)
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            test_json['state'] = STATE_REBASELINE_FAILED
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.send_response(500)
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.send_header('Content-type', 'text/plain')
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.end_headers()
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.wfile.write('\n'.join(log))
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def test_result(self):
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        test_name, _ = os.path.splitext(self.query['test'][0])
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        mode = self.query['mode'][0]
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if mode == 'expected-image':
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-expected.png'
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif mode == 'actual-image':
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-actual.png'
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if mode == 'expected-checksum':
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-expected.checksum'
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif mode == 'actual-checksum':
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-actual.checksum'
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif mode == 'diff-image':
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-diff.png'
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if mode == 'expected-text':
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-expected.txt'
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif mode == 'actual-text':
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-actual.txt'
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif mode == 'diff-text':
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-diff.txt'
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif mode == 'diff-text-pretty':
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_name = test_name + '-pretty-diff.html'
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        file_path = os.path.join(self.server.test_config.results_directory, file_name)
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Let results be cached for 60 seconds, so that they can be pre-fetched
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # by the UI
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._serve_file(file_path, cacheable_seconds=60)
284