Home | History | Annotate | Download | only in commands
      1 # Copyright (C) 2010 Google Inc. All rights reserved.
      2 #
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #    * Redistributions of source code must retain the above copyright
      8 # notice, this list of conditions and the following disclaimer.
      9 #    * Redistributions in binary form must reproduce the above
     10 # copyright notice, this list of conditions and the following disclaimer
     11 # in the documentation and/or other materials provided with the
     12 # distribution.
     13 #    * Neither the name of Google Inc. nor the names of its
     14 # contributors may be used to endorse or promote products derived from
     15 # this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 import webkitpy.thirdparty.unittest2 as unittest
     30 
     31 from webkitpy.common.system.outputcapture import OutputCapture
     32 from webkitpy.common.checkout.baselineoptimizer import BaselineOptimizer
     33 from webkitpy.common.net.buildbot.buildbot_mock import MockBuilder
     34 from webkitpy.common.net.layouttestresults import LayoutTestResults
     35 from webkitpy.common.system.executive_mock import MockExecutive2
     36 from webkitpy.thirdparty.mock import Mock
     37 from webkitpy.tool.commands.rebaseline import *
     38 from webkitpy.tool.mocktool import MockTool, MockOptions
     39 
     40 
     41 class _BaseTestCase(unittest.TestCase):
     42     MOCK_WEB_RESULT = 'MOCK Web result, convert 404 to None=True'
     43     WEB_PREFIX = 'http://example.com/f/builders/WebKit Mac10.7/results/layout-test-results'
     44 
     45     command_constructor = None
     46 
     47     def setUp(self):
     48         self.tool = MockTool()
     49         self.command = self.command_constructor()  # lint warns that command_constructor might not be set, but this is intentional; pylint: disable=E1102
     50         self.command.bind_to_tool(self.tool)
     51         self.lion_port = self.tool.port_factory.get_from_builder_name("WebKit Mac10.7")
     52         self.lion_expectations_path = self.lion_port.path_to_generic_test_expectations_file()
     53 
     54         # FIXME: we should override builders._exact_matches here to point to a set
     55         # of test ports and restore the value in tearDown(), and that way the
     56         # individual tests wouldn't have to worry about it.
     57 
     58     def _expand(self, path):
     59         if self.tool.filesystem.isabs(path):
     60             return path
     61         return self.tool.filesystem.join(self.lion_port.layout_tests_dir(), path)
     62 
     63     def _read(self, path):
     64         return self.tool.filesystem.read_text_file(self._expand(path))
     65 
     66     def _write(self, path, contents):
     67         self.tool.filesystem.write_text_file(self._expand(path), contents)
     68 
     69     def _zero_out_test_expectations(self):
     70         for port_name in self.tool.port_factory.all_port_names():
     71             port = self.tool.port_factory.get(port_name)
     72             for path in port.expectations_files():
     73                 self._write(path, '')
     74         self.tool.filesystem.written_files = {}
     75 
     76     def _setup_mock_builder_data(self):
     77         data = LayoutTestResults.results_from_string("""ADD_RESULTS({
     78     "tests": {
     79         "userscripts": {
     80             "first-test.html": {
     81                 "expected": "PASS",
     82                 "actual": "IMAGE+TEXT"
     83             },
     84             "second-test.html": {
     85                 "expected": "FAIL",
     86                 "actual": "IMAGE+TEXT"
     87             }
     88         }
     89     }
     90 });""")
     91         for builder in ['MOCK builder', 'MOCK builder (Debug)', 'WebKit Mac10.7']:
     92             self.command._builder_data[builder] = data
     93 
     94 
     95 class TestCopyExistingBaselinesInternal(_BaseTestCase):
     96     command_constructor = CopyExistingBaselinesInternal  # AKA webkit-patch rebaseline-test-internal
     97 
     98     def setUp(self):
     99         super(TestCopyExistingBaselinesInternal, self).setUp()
    100 
    101     def test_copying_overwritten_baseline(self):
    102         self.tool.executive = MockExecutive2()
    103 
    104         # FIXME: it's confusing that this is the test- port, and not the regular lion port. Really all of the tests should be using the test ports.
    105         port = self.tool.port_factory.get('test-mac-snowleopard')
    106         self._write(port._filesystem.join(port.layout_tests_dir(), 'platform/test-mac-snowleopard/failures/expected/image-expected.txt'), 'original snowleopard result')
    107 
    108         old_exact_matches = builders._exact_matches
    109         oc = OutputCapture()
    110         try:
    111             builders._exact_matches = {
    112                 "MOCK Leopard": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    113                 "MOCK SnowLeopard": {"port_name": "test-mac-snowleopard", "specifiers": set(["mock-specifier"])},
    114             }
    115 
    116             options = MockOptions(builder="MOCK SnowLeopard", suffixes="txt", verbose=True, test="failures/expected/image.html", results_directory=None)
    117 
    118             oc.capture_output()
    119             self.command.execute(options, [], self.tool)
    120         finally:
    121             out, _, _ = oc.restore_output()
    122             builders._exact_matches = old_exact_matches
    123 
    124         self.assertMultiLineEqual(self._read(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/test-mac-leopard/failures/expected/image-expected.txt')), 'original snowleopard result')
    125         self.assertMultiLineEqual(out, '{"add": [], "remove-lines": []}\n')
    126 
    127     def test_copying_overwritten_baseline_to_multiple_locations(self):
    128         self.tool.executive = MockExecutive2()
    129 
    130         # FIXME: it's confusing that this is the test- port, and not the regular win port. Really all of the tests should be using the test ports.
    131         port = self.tool.port_factory.get('test-win-win7')
    132         self._write(port._filesystem.join(port.layout_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt'), 'original win7 result')
    133 
    134         old_exact_matches = builders._exact_matches
    135         oc = OutputCapture()
    136         try:
    137             builders._exact_matches = {
    138                 "MOCK Leopard": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    139                 "MOCK Linux": {"port_name": "test-linux-x86_64", "specifiers": set(["mock-specifier"])},
    140                 "MOCK Win7": {"port_name": "test-win-win7", "specifiers": set(["mock-specifier"])},
    141             }
    142 
    143             options = MockOptions(builder="MOCK Win7", suffixes="txt", verbose=True, test="failures/expected/image.html", results_directory=None)
    144 
    145             oc.capture_output()
    146             self.command.execute(options, [], self.tool)
    147         finally:
    148             out, _, _ = oc.restore_output()
    149             builders._exact_matches = old_exact_matches
    150 
    151         self.assertMultiLineEqual(self._read(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/test-linux-x86_64/failures/expected/image-expected.txt')), 'original win7 result')
    152         self.assertFalse(self.tool.filesystem.exists(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/mac-leopard/userscripts/another-test-expected.txt')))
    153         self.assertMultiLineEqual(out, '{"add": [], "remove-lines": []}\n')
    154 
    155     def test_no_copy_existing_baseline(self):
    156         self.tool.executive = MockExecutive2()
    157 
    158         # FIXME: it's confusing that this is the test- port, and not the regular win port. Really all of the tests should be using the test ports.
    159         port = self.tool.port_factory.get('test-win-win7')
    160         self._write(port._filesystem.join(port.layout_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt'), 'original win7 result')
    161 
    162         old_exact_matches = builders._exact_matches
    163         oc = OutputCapture()
    164         try:
    165             builders._exact_matches = {
    166                 "MOCK Leopard": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    167                 "MOCK Linux": {"port_name": "test-linux-x86_64", "specifiers": set(["mock-specifier"])},
    168                 "MOCK Win7": {"port_name": "test-win-win7", "specifiers": set(["mock-specifier"])},
    169             }
    170 
    171             options = MockOptions(builder="MOCK Win7", suffixes="txt", verbose=True, test="failures/expected/image.html", results_directory=None)
    172 
    173             oc.capture_output()
    174             self.command.execute(options, [], self.tool)
    175         finally:
    176             out, _, _ = oc.restore_output()
    177             builders._exact_matches = old_exact_matches
    178 
    179         self.assertMultiLineEqual(self._read(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/test-linux-x86_64/failures/expected/image-expected.txt')), 'original win7 result')
    180         self.assertMultiLineEqual(self._read(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt')), 'original win7 result')
    181         self.assertFalse(self.tool.filesystem.exists(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/mac-leopard/userscripts/another-test-expected.txt')))
    182         self.assertMultiLineEqual(out, '{"add": [], "remove-lines": []}\n')
    183 
    184 
    185 class TestRebaselineTest(_BaseTestCase):
    186     command_constructor = RebaselineTest  # AKA webkit-patch rebaseline-test-internal
    187 
    188     def setUp(self):
    189         super(TestRebaselineTest, self).setUp()
    190         self.options = MockOptions(builder="WebKit Mac10.7", test="userscripts/another-test.html", suffixes="txt", results_directory=None)
    191 
    192     def test_baseline_directory(self):
    193         command = self.command
    194         self.assertMultiLineEqual(command._baseline_directory("WebKit Mac10.7"), "/mock-checkout/LayoutTests/platform/mac-lion")
    195         self.assertMultiLineEqual(command._baseline_directory("WebKit Mac10.6"), "/mock-checkout/LayoutTests/platform/mac-snowleopard")
    196 
    197     def test_rebaseline_updates_expectations_file_noop(self):
    198         self._zero_out_test_expectations()
    199         self._write(self.lion_expectations_path, """Bug(B) [ Mac Linux XP Debug ] fast/dom/Window/window-postmessage-clone-really-deep-array.html [ Pass ]
    200 Bug(A) [ Debug ] : fast/css/large-list-of-rules-crash.html [ Failure ]
    201 """)
    202         self._write("fast/dom/Window/window-postmessage-clone-really-deep-array.html", "Dummy test contents")
    203         self._write("fast/css/large-list-of-rules-crash.html", "Dummy test contents")
    204         self._write("userscripts/another-test.html", "Dummy test contents")
    205 
    206         self.options.suffixes = "png,wav,txt"
    207         self.command._rebaseline_test_and_update_expectations(self.options)
    208 
    209         self.assertItemsEqual(self.tool.web.urls_fetched,
    210             [self.WEB_PREFIX + '/userscripts/another-test-actual.png',
    211              self.WEB_PREFIX + '/userscripts/another-test-actual.wav',
    212              self.WEB_PREFIX + '/userscripts/another-test-actual.txt'])
    213         new_expectations = self._read(self.lion_expectations_path)
    214         self.assertMultiLineEqual(new_expectations, """Bug(B) [ Mac Linux XP Debug ] fast/dom/Window/window-postmessage-clone-really-deep-array.html [ Pass ]
    215 Bug(A) [ Debug ] : fast/css/large-list-of-rules-crash.html [ Failure ]
    216 """)
    217 
    218     def test_rebaseline_test(self):
    219         self.command._rebaseline_test("WebKit Linux", "userscripts/another-test.html", "txt", self.WEB_PREFIX)
    220         self.assertItemsEqual(self.tool.web.urls_fetched, [self.WEB_PREFIX + '/userscripts/another-test-actual.txt'])
    221 
    222     def test_rebaseline_test_with_results_directory(self):
    223         self._write("userscripts/another-test.html", "test data")
    224         self._write(self.lion_expectations_path, "Bug(x) [ Mac ] userscripts/another-test.html [ ImageOnlyFailure ]\nbug(z) [ Linux ] userscripts/another-test.html [ ImageOnlyFailure ]\n")
    225         self.options.results_directory = '/tmp'
    226         self.command._rebaseline_test_and_update_expectations(self.options)
    227         self.assertItemsEqual(self.tool.web.urls_fetched, ['file:///tmp/userscripts/another-test-actual.txt'])
    228 
    229     def test_rebaseline_reftest(self):
    230         self._write("userscripts/another-test.html", "test data")
    231         self._write("userscripts/another-test-expected.html", "generic result")
    232         OutputCapture().assert_outputs(self, self.command._rebaseline_test_and_update_expectations, args=[self.options],
    233             expected_logs="Cannot rebaseline reftest: userscripts/another-test.html\n")
    234         self.assertDictEqual(self.command._scm_changes, {'add': [], 'remove-lines': []})
    235 
    236     def test_rebaseline_test_and_print_scm_changes(self):
    237         self.command._print_scm_changes = True
    238         self.command._scm_changes = {'add': [], 'delete': []}
    239         self.tool._scm.exists = lambda x: False
    240 
    241         self.command._rebaseline_test("WebKit Linux", "userscripts/another-test.html", "txt", None)
    242 
    243         self.assertDictEqual(self.command._scm_changes, {'add': ['/mock-checkout/LayoutTests/platform/linux/userscripts/another-test-expected.txt'], 'delete': []})
    244 
    245     def test_rebaseline_test_internal_with_port_that_lacks_buildbot(self):
    246         self.tool.executive = MockExecutive2()
    247 
    248         # FIXME: it's confusing that this is the test- port, and not the regular win port. Really all of the tests should be using the test ports.
    249         port = self.tool.port_factory.get('test-win-win7')
    250         self._write(port._filesystem.join(port.layout_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt'), 'original win7 result')
    251 
    252         old_exact_matches = builders._exact_matches
    253         oc = OutputCapture()
    254         try:
    255             builders._exact_matches = {
    256                 "MOCK XP": {"port_name": "test-win-xp"},
    257                 "MOCK Win7": {"port_name": "test-win-win7"},
    258             }
    259 
    260             options = MockOptions(optimize=True, builder="MOCK Win7", suffixes="txt",
    261                 verbose=True, test="failures/expected/image.html", results_directory=None)
    262 
    263             oc.capture_output()
    264             self.command.execute(options, [], self.tool)
    265         finally:
    266             out, _, _ = oc.restore_output()
    267             builders._exact_matches = old_exact_matches
    268 
    269         self.assertMultiLineEqual(self._read(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/test-win-win7/failures/expected/image-expected.txt')), 'MOCK Web result, convert 404 to None=True')
    270         self.assertFalse(self.tool.filesystem.exists(self.tool.filesystem.join(port.layout_tests_dir(), 'platform/test-win-xp/failures/expected/image-expected.txt')))
    271         self.assertMultiLineEqual(out, '{"add": [], "remove-lines": [{"test": "failures/expected/image.html", "builder": "MOCK Win7"}]}\n')
    272 
    273 
    274 class TestAbstractParallelRebaselineCommand(_BaseTestCase):
    275     command_constructor = AbstractParallelRebaselineCommand
    276 
    277     def test_builders_to_fetch_from(self):
    278         old_exact_matches = builders._exact_matches
    279         try:
    280             builders._exact_matches = {
    281                 "MOCK XP": {"port_name": "test-win-xp"},
    282                 "MOCK Win7": {"port_name": "test-win-win7"},
    283                 "MOCK Win7 (dbg)(1)": {"port_name": "test-win-win7"},
    284                 "MOCK Win7 (dbg)(2)": {"port_name": "test-win-win7"},
    285             }
    286 
    287             builders_to_fetch = self.command._builders_to_fetch_from(["MOCK XP", "MOCK Win7 (dbg)(1)", "MOCK Win7 (dbg)(2)", "MOCK Win7"])
    288             self.assertEqual(builders_to_fetch, ["MOCK XP", "MOCK Win7"])
    289         finally:
    290             builders._exact_matches = old_exact_matches
    291 
    292 
    293 class TestRebaselineJson(_BaseTestCase):
    294     command_constructor = RebaselineJson
    295 
    296     def setUp(self):
    297         super(TestRebaselineJson, self).setUp()
    298         self.tool.executive = MockExecutive2()
    299         self.old_exact_matches = builders._exact_matches
    300         builders._exact_matches = {
    301             "MOCK builder": {"port_name": "test-mac-snowleopard"},
    302             "MOCK builder (Debug)": {"port_name": "test-mac-snowleopard"},
    303         }
    304 
    305     def tearDown(self):
    306         builders._exact_matches = self.old_exact_matches
    307         super(TestRebaselineJson, self).tearDown()
    308 
    309     def test_rebaseline_all(self):
    310         self._setup_mock_builder_data()
    311 
    312         options = MockOptions(optimize=True, verbose=True, results_directory=None)
    313         self._write("userscripts/first-test.html", "Dummy test contents")
    314         self.command._rebaseline(options,  {"userscripts/first-test.html": {"MOCK builder": ["txt", "png"]}})
    315 
    316         # Note that we have one run_in_parallel() call followed by a run_command()
    317         self.assertEqual(self.tool.executive.calls,
    318             [[['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--verbose']],
    319              [['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--verbose']],
    320              ['echo', '--verbose', 'optimize-baselines', '--suffixes', 'txt,png', 'userscripts/first-test.html']])
    321 
    322     def test_rebaseline_debug(self):
    323         self._setup_mock_builder_data()
    324 
    325         options = MockOptions(optimize=True, verbose=True, results_directory=None)
    326         self._write("userscripts/first-test.html", "Dummy test contents")
    327         self.command._rebaseline(options,  {"userscripts/first-test.html": {"MOCK builder (Debug)": ["txt", "png"]}})
    328 
    329         # Note that we have one run_in_parallel() call followed by a run_command()
    330         self.assertEqual(self.tool.executive.calls,
    331             [[['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder (Debug)', '--test', 'userscripts/first-test.html', '--verbose']],
    332              [['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder (Debug)', '--test', 'userscripts/first-test.html', '--verbose']],
    333              ['echo', '--verbose', 'optimize-baselines', '--suffixes', 'txt,png', 'userscripts/first-test.html']])
    334 
    335     def test_no_optimize(self):
    336         self._setup_mock_builder_data()
    337 
    338         options = MockOptions(optimize=False, verbose=True, results_directory=None)
    339         self._write("userscripts/first-test.html", "Dummy test contents")
    340         self.command._rebaseline(options,  {"userscripts/first-test.html": {"MOCK builder (Debug)": ["txt", "png"]}})
    341 
    342         # Note that we have only one run_in_parallel() call
    343         self.assertEqual(self.tool.executive.calls,
    344             [[['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder (Debug)', '--test', 'userscripts/first-test.html', '--verbose']],
    345              [['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder (Debug)', '--test', 'userscripts/first-test.html', '--verbose']]])
    346 
    347     def test_results_directory(self):
    348         self._setup_mock_builder_data()
    349 
    350         options = MockOptions(optimize=False, verbose=True, results_directory='/tmp')
    351         self._write("userscripts/first-test.html", "Dummy test contents")
    352         self.command._rebaseline(options,  {"userscripts/first-test.html": {"MOCK builder": ["txt", "png"]}})
    353 
    354         # Note that we have only one run_in_parallel() call
    355         self.assertEqual(self.tool.executive.calls,
    356             [[['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--results-directory', '/tmp', '--verbose']],
    357              [['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--results-directory', '/tmp', '--verbose']]])
    358 
    359 class TestRebaselineJsonUpdatesExpectationsFiles(_BaseTestCase):
    360     command_constructor = RebaselineJson
    361 
    362     def setUp(self):
    363         super(TestRebaselineJsonUpdatesExpectationsFiles, self).setUp()
    364         self.tool.executive = MockExecutive2()
    365 
    366         def mock_run_command(args,
    367                              cwd=None,
    368                              input=None,
    369                              error_handler=None,
    370                              return_exit_code=False,
    371                              return_stderr=True,
    372                              decode_output=False,
    373                              env=None):
    374             return '{"add": [], "remove-lines": [{"test": "userscripts/first-test.html", "builder": "WebKit Mac10.7"}]}\n'
    375         self.tool.executive.run_command = mock_run_command
    376 
    377     def test_rebaseline_updates_expectations_file(self):
    378         options = MockOptions(optimize=False, verbose=True, results_directory=None)
    379 
    380         self._write(self.lion_expectations_path, "Bug(x) [ Mac ] userscripts/first-test.html [ ImageOnlyFailure ]\nbug(z) [ Linux ] userscripts/first-test.html [ ImageOnlyFailure ]\n")
    381         self._write("userscripts/first-test.html", "Dummy test contents")
    382         self._setup_mock_builder_data()
    383 
    384         self.command._rebaseline(options,  {"userscripts/first-test.html": {"WebKit Mac10.7": ["txt", "png"]}})
    385 
    386         new_expectations = self._read(self.lion_expectations_path)
    387         self.assertMultiLineEqual(new_expectations, "Bug(x) [ MountainLion SnowLeopard ] userscripts/first-test.html [ ImageOnlyFailure ]\nbug(z) [ Linux ] userscripts/first-test.html [ ImageOnlyFailure ]\n")
    388 
    389     def test_rebaseline_updates_expectations_file_all_platforms(self):
    390         options = MockOptions(optimize=False, verbose=True, results_directory=None)
    391 
    392         self._write(self.lion_expectations_path, "Bug(x) userscripts/first-test.html [ ImageOnlyFailure ]\n")
    393         self._write("userscripts/first-test.html", "Dummy test contents")
    394         self._setup_mock_builder_data()
    395 
    396         self.command._rebaseline(options,  {"userscripts/first-test.html": {"WebKit Mac10.7": ["txt", "png"]}})
    397 
    398         new_expectations = self._read(self.lion_expectations_path)
    399         self.assertMultiLineEqual(new_expectations, "Bug(x) [ Linux MountainLion SnowLeopard Win ] userscripts/first-test.html [ ImageOnlyFailure ]\n")
    400 
    401 
    402 class TestRebaseline(_BaseTestCase):
    403     # This command shares most of its logic with RebaselineJson, so these tests just test what is different.
    404 
    405     command_constructor = Rebaseline  # AKA webkit-patch rebaseline
    406 
    407     def test_rebaseline(self):
    408         self.command._builders_to_pull_from = lambda: [MockBuilder('MOCK builder')]
    409 
    410         self._write("userscripts/first-test.html", "test data")
    411 
    412         self._zero_out_test_expectations()
    413         self._setup_mock_builder_data()
    414 
    415         old_exact_matches = builders._exact_matches
    416         try:
    417             builders._exact_matches = {
    418                 "MOCK builder": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    419             }
    420             self.command.execute(MockOptions(results_directory=False, optimize=False, builders=None, suffixes="txt,png", verbose=True), ['userscripts/first-test.html'], self.tool)
    421         finally:
    422             builders._exact_matches = old_exact_matches
    423 
    424         calls = filter(lambda x: x != ['qmake', '-v'] and x[0] != 'perl', self.tool.executive.calls)
    425         self.assertEqual(calls,
    426             [[['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--verbose']],
    427              [['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--verbose']]])
    428 
    429     def test_rebaseline_directory(self):
    430         self.command._builders_to_pull_from = lambda: [MockBuilder('MOCK builder')]
    431 
    432         self._write("userscripts/first-test.html", "test data")
    433         self._write("userscripts/second-test.html", "test data")
    434 
    435         self._setup_mock_builder_data()
    436 
    437         old_exact_matches = builders._exact_matches
    438         try:
    439             builders._exact_matches = {
    440                 "MOCK builder": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    441             }
    442             self.command.execute(MockOptions(results_directory=False, optimize=False, builders=None, suffixes="txt,png", verbose=True), ['userscripts'], self.tool)
    443         finally:
    444             builders._exact_matches = old_exact_matches
    445 
    446         calls = filter(lambda x: x != ['qmake', '-v'] and x[0] != 'perl', self.tool.executive.calls)
    447         self.assertEqual(calls,
    448             [[['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--verbose'],
    449               ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/second-test.html', '--verbose']],
    450              [['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--verbose'],
    451               ['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/second-test.html', '--verbose']]])
    452 
    453 
    454 class TestRebaselineExpectations(_BaseTestCase):
    455     command_constructor = RebaselineExpectations
    456 
    457     def setUp(self):
    458         super(TestRebaselineExpectations, self).setUp()
    459         self.options = MockOptions(optimize=False, builders=None, suffixes=['txt'], verbose=False, platform=None, results_directory=None)
    460 
    461     def test_rebaseline_expectations(self):
    462         self._zero_out_test_expectations()
    463 
    464         self.tool.executive = MockExecutive2()
    465 
    466         def builder_data():
    467             self.command._builder_data['MOCK SnowLeopard'] = self.command._builder_data['MOCK Leopard'] = LayoutTestResults.results_from_string("""ADD_RESULTS({
    468     "tests": {
    469         "userscripts": {
    470             "another-test.html": {
    471                 "expected": "PASS",
    472                 "actual": "PASS TEXT"
    473             },
    474             "images.svg": {
    475                 "expected": "FAIL",
    476                 "actual": "IMAGE+TEXT"
    477             }
    478         }
    479     }
    480 });""")
    481             return self.command._builder_data
    482 
    483         self.command.builder_data = builder_data
    484 
    485         self._write("userscripts/another-test.html", "Dummy test contents")
    486         self._write("userscripts/images.svg", "Dummy test contents")
    487         self.command._tests_to_rebaseline = lambda port: {
    488             'userscripts/another-test.html': set(['txt']),
    489             'userscripts/images.svg': set(['png']),
    490             'userscripts/not-actually-failing.html': set(['txt', 'png', 'wav']),
    491         }
    492 
    493         old_exact_matches = builders._exact_matches
    494         try:
    495             builders._exact_matches = {
    496                 "MOCK Leopard": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    497                 "MOCK SnowLeopard": {"port_name": "test-mac-snowleopard", "specifiers": set(["mock-specifier"])},
    498             }
    499             self.command.execute(self.options, [], self.tool)
    500         finally:
    501             builders._exact_matches = old_exact_matches
    502 
    503         # FIXME: change this to use the test- ports.
    504         calls = filter(lambda x: x != ['qmake', '-v'], self.tool.executive.calls)
    505         self.assertEqual(self.tool.executive.calls, [
    506             [
    507                 ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', '--builder', 'MOCK Leopard', '--test', 'userscripts/another-test.html'],
    508                 ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', '--builder', 'MOCK SnowLeopard', '--test', 'userscripts/another-test.html'],
    509                 ['echo', 'copy-existing-baselines-internal', '--suffixes', 'png', '--builder', 'MOCK Leopard', '--test', 'userscripts/images.svg'],
    510                 ['echo', 'copy-existing-baselines-internal', '--suffixes', 'png', '--builder', 'MOCK SnowLeopard', '--test', 'userscripts/images.svg']
    511             ],
    512             [
    513                 ['echo', 'rebaseline-test-internal', '--suffixes', 'txt', '--builder', 'MOCK Leopard', '--test', 'userscripts/another-test.html'],
    514                 ['echo', 'rebaseline-test-internal', '--suffixes', 'txt', '--builder', 'MOCK SnowLeopard', '--test', 'userscripts/another-test.html'],
    515                 ['echo', 'rebaseline-test-internal', '--suffixes', 'png', '--builder', 'MOCK Leopard', '--test', 'userscripts/images.svg'],
    516                 ['echo', 'rebaseline-test-internal', '--suffixes', 'png', '--builder', 'MOCK SnowLeopard', '--test', 'userscripts/images.svg']
    517             ]
    518         ])
    519 
    520     def test_rebaseline_expectations_noop(self):
    521         self._zero_out_test_expectations()
    522 
    523         oc = OutputCapture()
    524         try:
    525             oc.capture_output()
    526             self.command.execute(self.options, [], self.tool)
    527         finally:
    528             _, _, logs = oc.restore_output()
    529             self.assertEqual(self.tool.filesystem.written_files, {})
    530             self.assertEqual(logs, 'Did not find any tests marked Rebaseline.\n')
    531 
    532     def disabled_test_overrides_are_included_correctly(self):
    533         # This tests that the any tests marked as REBASELINE in the overrides are found, but
    534         # that the overrides do not get written into the main file.
    535         self._zero_out_test_expectations()
    536 
    537         self._write(self.lion_expectations_path, '')
    538         self.lion_port.expectations_dict = lambda: {
    539             self.lion_expectations_path: '',
    540             'overrides': ('Bug(x) userscripts/another-test.html [ Failure Rebaseline ]\n'
    541                           'Bug(y) userscripts/test.html [ Crash ]\n')}
    542         self._write('/userscripts/another-test.html', '')
    543 
    544         self.assertDictEqual(self.command._tests_to_rebaseline(self.lion_port), {'userscripts/another-test.html': set(['png', 'txt', 'wav'])})
    545         self.assertEqual(self._read(self.lion_expectations_path), '')
    546 
    547     def test_rebaseline_without_other_expectations(self):
    548         self._write("userscripts/another-test.html", "Dummy test contents")
    549         self._write(self.lion_expectations_path, "Bug(x) userscripts/another-test.html [ Rebaseline ]\n")
    550         self.assertDictEqual(self.command._tests_to_rebaseline(self.lion_port), {'userscripts/another-test.html': ('png', 'wav', 'txt')})
    551 
    552 
    553 class _FakeOptimizer(BaselineOptimizer):
    554     def read_results_by_directory(self, baseline_name):
    555         if baseline_name.endswith('txt'):
    556             return {'LayoutTests/passes/text.html': '123456'}
    557         return {}
    558 
    559 
    560 class TestAnalyzeBaselines(_BaseTestCase):
    561     command_constructor = AnalyzeBaselines
    562 
    563     def setUp(self):
    564         super(TestAnalyzeBaselines, self).setUp()
    565         self.port = self.tool.port_factory.get('test')
    566         self.tool.port_factory.get = (lambda port_name=None, options=None: self.port)
    567         self.lines = []
    568         self.command._optimizer_class = _FakeOptimizer
    569         self.command._write = (lambda msg: self.lines.append(msg))  # pylint bug warning about unnecessary lambda? pylint: disable=W0108
    570 
    571     def test_default(self):
    572         self.command.execute(MockOptions(suffixes='txt', missing=False, platform=None), ['passes/text.html'], self.tool)
    573         self.assertEqual(self.lines,
    574             ['passes/text-expected.txt:',
    575              '  (generic): 123456'])
    576 
    577     def test_missing_baselines(self):
    578         self.command.execute(MockOptions(suffixes='png,txt', missing=True, platform=None), ['passes/text.html'], self.tool)
    579         self.assertEqual(self.lines,
    580             ['passes/text-expected.png: (no baselines found)',
    581              'passes/text-expected.txt:',
    582              '  (generic): 123456'])
    583 
    584 
    585 class TestAutoRebaseline(_BaseTestCase):
    586     command_constructor = AutoRebaseline
    587 
    588     def _write_test_file(self, port, path, contents):
    589         abs_path = self.tool.filesystem.join(port.layout_tests_dir(), path)
    590         self.tool.filesystem.write_text_file(abs_path, contents)
    591 
    592     def setUp(self):
    593         super(TestAutoRebaseline, self).setUp()
    594         self.command.latest_revision_processed_on_all_bots = lambda: 9000
    595 
    596     def test_tests_to_rebaseline(self):
    597         def blame(path):
    598             return """
    599 624c3081c0 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/norebaseline.html [ ImageOnlyFailure ]
    600 624c3081c0 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-04-28 04:52:41 +0000   13) Bug(foo) path/to/rebaseline-without-bug-number.html [ NeedsRebaseline ]
    601 624c3081c0 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/rebaseline-with-modifiers.html [ NeedsRebaseline ]
    602 624c3081c0 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-04-28 04:52:41 +0000   12) crbug.com/24182 crbug.com/234 path/to/rebaseline-without-modifiers.html [ NeedsRebaseline ]
    603 6469e754a1 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/rebaseline-new-revision.html [ NeedsRebaseline ]
    604 624caaaaaa path/to/TestExpectations                   (foo (at] chromium.org        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
    605 0000000000 path/to/TestExpectations                   (foo (at] chromium.org        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
    606 """
    607         self.tool.scm().blame = blame
    608 
    609         min_revision = 9000
    610         self.assertEqual(self.command.tests_to_rebaseline(self.tool, min_revision, print_revisions=False), (
    611                 set(['path/to/rebaseline-without-bug-number.html', 'path/to/rebaseline-with-modifiers.html', 'path/to/rebaseline-without-modifiers.html']),
    612                 5678,
    613                 'foobarbaz1 (at] chromium.org',
    614                 set(['24182', '234'])))
    615 
    616     def test_tests_to_rebaseline_over_limit(self):
    617         def blame(path):
    618             result = ""
    619             for i in range(0, self.command.MAX_LINES_TO_REBASELINE + 1):
    620                 result += "624c3081c0 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-04-28 04:52:41 +0000   13) crbug.com/24182 path/to/rebaseline-%s.html [ NeedsRebaseline ]\n" % i
    621             return result
    622         self.tool.scm().blame = blame
    623 
    624         expected_list_of_tests = []
    625         for i in range(0, self.command.MAX_LINES_TO_REBASELINE):
    626             expected_list_of_tests.append("path/to/rebaseline-%s.html" % i)
    627 
    628         min_revision = 9000
    629         self.assertEqual(self.command.tests_to_rebaseline(self.tool, min_revision, print_revisions=False), (
    630                 set(expected_list_of_tests),
    631                 5678,
    632                 'foobarbaz1 (at] chromium.org',
    633                 set(['24182'])))
    634 
    635     def test_commit_message(self):
    636         author = "foo (at] chromium.org"
    637         revision = 1234
    638         bugs = set()
    639         self.assertEqual(self.command.commit_message(author, revision, bugs),
    640             """Auto-rebaseline for r1234
    641 
    642 http://src.chromium.org/viewvc/blink?view=revision&revision=1234
    643 
    644 TBR=foo (at] chromium.org
    645 """)
    646 
    647         bugs = set(["234", "345"])
    648         self.assertEqual(self.command.commit_message(author, revision, bugs),
    649             """Auto-rebaseline for r1234
    650 
    651 http://src.chromium.org/viewvc/blink?view=revision&revision=1234
    652 
    653 BUG=234,345
    654 TBR=foo (at] chromium.org
    655 """)
    656 
    657     def test_no_needs_rebaseline_lines(self):
    658         def blame(path):
    659             return """
    660 6469e754a1 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/norebaseline.html [ ImageOnlyFailure ]
    661 """
    662         self.tool.scm().blame = blame
    663 
    664         self.command.execute(MockOptions(optimize=True, verbose=False, move_overwritten_baselines=False, results_directory=False), [], self.tool)
    665         self.assertEqual(self.tool.executive.calls, [])
    666 
    667     def test_execute(self):
    668         def blame(path):
    669             return """
    670 6469e754a1 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/norebaseline.html [ ImageOnlyFailure ]
    671 6469e754a1 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
    672 6469e754a1 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ SnowLeopard ] fast/dom/prototype-strawberry.html [ NeedsRebaseline ]
    673 6469e754a1 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-04-28 04:52:41 +0000   12) crbug.com/24182 fast/dom/prototype-chocolate.html [ NeedsRebaseline ]
    674 624caaaaaa path/to/TestExpectations                   (foo (at] chromium.org        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
    675 0000000000 path/to/TestExpectations                   (foo (at] chromium.org        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
    676 """
    677         self.tool.scm().blame = blame
    678 
    679         test_port = self.tool.port_factory.get('test')
    680         original_get = self.tool.port_factory.get
    681 
    682         def get_test_port(port_name=None, options=None, **kwargs):
    683             if not port_name:
    684                 return test_port
    685             return original_get(port_name, options, **kwargs)
    686         # Need to make sure all the ports grabbed use the test checkout path instead of the mock checkout path.
    687         self.tool.port_factory.get = get_test_port
    688 
    689         old_builder_data = self.command.builder_data
    690 
    691         def builder_data():
    692             old_builder_data()
    693             # have prototype-chocolate only fail on "MOCK Leopard".
    694             self.command._builder_data['MOCK SnowLeopard'] = LayoutTestResults.results_from_string("""ADD_RESULTS({
    695     "tests": {
    696         "fast": {
    697             "dom": {
    698                 "prototype-taco.html": {
    699                     "expected": "PASS",
    700                     "actual": "PASS TEXT",
    701                     "is_unexpected": true
    702                 },
    703                 "prototype-chocolate.html": {
    704                     "expected": "FAIL",
    705                     "actual": "PASS"
    706                 },
    707                 "prototype-strawberry.html": {
    708                     "expected": "PASS",
    709                     "actual": "IMAGE PASS",
    710                     "is_unexpected": true
    711                 }
    712             }
    713         }
    714     }
    715 });""")
    716             return self.command._builder_data
    717 
    718         self.command.builder_data = builder_data
    719 
    720         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
    721 crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Rebaseline ]
    722 Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
    723 crbug.com/24182 [ SnowLeopard ] fast/dom/prototype-strawberry.html [ NeedsRebaseline ]
    724 crbug.com/24182 fast/dom/prototype-chocolate.html [ NeedsRebaseline ]
    725 crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
    726 crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
    727 """)
    728 
    729         self._write_test_file(test_port, 'fast/dom/prototype-taco.html', "Dummy test contents")
    730         self._write_test_file(test_port, 'fast/dom/prototype-strawberry.html', "Dummy test contents")
    731         self._write_test_file(test_port, 'fast/dom/prototype-chocolate.html', "Dummy test contents")
    732 
    733         old_exact_matches = builders._exact_matches
    734         try:
    735             builders._exact_matches = {
    736                 "MOCK Leopard": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    737                 "MOCK SnowLeopard": {"port_name": "test-mac-snowleopard", "specifiers": set(["mock-specifier"])},
    738             }
    739 
    740             self.command.tree_status = lambda: 'closed'
    741             self.command.execute(MockOptions(optimize=True, verbose=False, move_overwritten_baselines=False, results_directory=False), [], self.tool)
    742             self.assertEqual(self.tool.executive.calls, [])
    743 
    744             self.command.tree_status = lambda: 'open'
    745 
    746             self.tool.executive.calls = []
    747             self.command.execute(MockOptions(optimize=True, verbose=False, move_overwritten_baselines=False, results_directory=False), [], self.tool)
    748             self.assertEqual(self.tool.executive.calls, [
    749                 [
    750                     ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png', '--builder', 'MOCK Leopard', '--test', 'fast/dom/prototype-chocolate.html'],
    751                     ['echo', 'copy-existing-baselines-internal', '--suffixes', 'png', '--builder', 'MOCK SnowLeopard', '--test', 'fast/dom/prototype-strawberry.html'],
    752                     ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', '--builder', 'MOCK Leopard', '--test', 'fast/dom/prototype-taco.html'],
    753                     ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', '--builder', 'MOCK SnowLeopard', '--test', 'fast/dom/prototype-taco.html'],
    754                 ],
    755                 [
    756                     ['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK Leopard', '--test', 'fast/dom/prototype-chocolate.html'],
    757                     ['echo', 'rebaseline-test-internal', '--suffixes', 'png', '--builder', 'MOCK SnowLeopard', '--test', 'fast/dom/prototype-strawberry.html'],
    758                     ['echo', 'rebaseline-test-internal', '--suffixes', 'txt', '--builder', 'MOCK Leopard', '--test', 'fast/dom/prototype-taco.html'],
    759                     ['echo', 'rebaseline-test-internal', '--suffixes', 'txt', '--builder', 'MOCK SnowLeopard', '--test', 'fast/dom/prototype-taco.html'],
    760                 ],
    761                 ['echo', 'optimize-baselines', '--suffixes', 'txt,png', 'fast/dom/prototype-chocolate.html'],
    762                 ['echo', 'optimize-baselines', '--suffixes', 'png', 'fast/dom/prototype-strawberry.html'],
    763                 ['echo', 'optimize-baselines', '--suffixes', 'txt', 'fast/dom/prototype-taco.html'],
    764                 ['git', 'pull'],
    765             ])
    766 
    767             # The mac ports should both be removed since they're the only ones in builders._exact_matches.
    768             self.assertEqual(self.tool.filesystem.read_text_file(test_port.path_to_generic_test_expectations_file()), """
    769 crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Rebaseline ]
    770 Bug(foo) [ Linux Win ] fast/dom/prototype-taco.html [ NeedsRebaseline ]
    771 crbug.com/24182 [ Linux Win ] fast/dom/prototype-chocolate.html [ NeedsRebaseline ]
    772 crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
    773 crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
    774 """)
    775         finally:
    776             builders._exact_matches = old_exact_matches
    777 
    778     def test_execute_test_passes_everywhere(self):
    779         def blame(path):
    780             return """
    781 6469e754a1 path/to/TestExpectations                   (foobarbaz1 (at] chromium.org 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
    782 """
    783         self.tool.scm().blame = blame
    784 
    785         test_port = self.tool.port_factory.get('test')
    786         original_get = self.tool.port_factory.get
    787 
    788         def get_test_port(port_name=None, options=None, **kwargs):
    789             if not port_name:
    790                 return test_port
    791             return original_get(port_name, options, **kwargs)
    792         # Need to make sure all the ports grabbed use the test checkout path instead of the mock checkout path.
    793         self.tool.port_factory.get = get_test_port
    794 
    795         old_builder_data = self.command.builder_data
    796 
    797         def builder_data():
    798             self.command._builder_data['MOCK Leopard'] = self.command._builder_data['MOCK SnowLeopard'] = LayoutTestResults.results_from_string("""ADD_RESULTS({
    799     "tests": {
    800         "fast": {
    801             "dom": {
    802                 "prototype-taco.html": {
    803                     "expected": "PASS",
    804                     "actual": "PASS TEXT",
    805                     "is_unexpected": true
    806                 }
    807             }
    808         }
    809     }
    810 });""")
    811             return self.command._builder_data
    812 
    813         self.command.builder_data = builder_data
    814 
    815         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
    816 Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
    817 """)
    818 
    819         self._write_test_file(test_port, 'fast/dom/prototype-taco.html', "Dummy test contents")
    820 
    821         old_exact_matches = builders._exact_matches
    822         try:
    823             builders._exact_matches = {
    824                 "MOCK Leopard": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
    825                 "MOCK SnowLeopard": {"port_name": "test-mac-snowleopard", "specifiers": set(["mock-specifier"])},
    826             }
    827 
    828             self.command.tree_status = lambda: 'open'
    829             self.command.execute(MockOptions(optimize=True, verbose=False, move_overwritten_baselines=False, results_directory=False), [], self.tool)
    830             self.assertEqual(self.tool.executive.calls, [
    831                 [
    832                     ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', '--builder', 'MOCK Leopard', '--test', 'fast/dom/prototype-taco.html'],
    833                     ['echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', '--builder', 'MOCK SnowLeopard', '--test', 'fast/dom/prototype-taco.html'],
    834                 ],
    835                 [
    836                     ['echo', 'rebaseline-test-internal', '--suffixes', 'txt', '--builder', 'MOCK Leopard', '--test', 'fast/dom/prototype-taco.html'],
    837                     ['echo', 'rebaseline-test-internal', '--suffixes', 'txt', '--builder', 'MOCK SnowLeopard', '--test', 'fast/dom/prototype-taco.html'],
    838                 ],
    839                 ['echo', 'optimize-baselines', '--suffixes', 'txt', 'fast/dom/prototype-taco.html'],
    840                 ['git', 'pull'],
    841             ])
    842 
    843             # The mac ports should both be removed since they're the only ones in builders._exact_matches.
    844             self.assertEqual(self.tool.filesystem.read_text_file(test_port.path_to_generic_test_expectations_file()), """
    845 Bug(foo) [ Linux Win ] fast/dom/prototype-taco.html [ NeedsRebaseline ]
    846 """)
    847         finally:
    848             builders._exact_matches = old_exact_matches
    849