Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / Scripts / webkitpy / layout_tests / port / test.py
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 Google name 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 base64
30 import copy
31 import sys
32 import time
33
34 from webkitpy.layout_tests.port import DeviceFailure, Driver, DriverOutput, Port
35 from webkitpy.layout_tests.port.base import VirtualTestSuite
36 from webkitpy.layout_tests.models.test_configuration import TestConfiguration
37 from webkitpy.layout_tests.models import test_run_results
38 from webkitpy.common.system.filesystem_mock import MockFileSystem
39 from webkitpy.common.system.crashlogs import CrashLogs
40
41
42 # This sets basic expectations for a test. Each individual expectation
43 # can be overridden by a keyword argument in TestList.add().
44 class TestInstance(object):
45     def __init__(self, name):
46         self.name = name
47         self.base = name[(name.rfind("/") + 1):name.rfind(".")]
48         self.crash = False
49         self.web_process_crash = False
50         self.exception = False
51         self.keyboard = False
52         self.error = ''
53         self.timeout = False
54         self.is_reftest = False
55         self.device_failure = False
56         self.leak = False
57
58         # The values of each field are treated as raw byte strings. They
59         # will be converted to unicode strings where appropriate using
60         # FileSystem.read_text_file().
61         self.actual_text = self.base + '-txt'
62         self.actual_checksum = self.base + '-checksum'
63
64         # We add the '\x8a' for the image file to prevent the value from
65         # being treated as UTF-8 (the character is invalid)
66         self.actual_image = self.base + '\x8a' + '-png' + 'tEXtchecksum\x00' + self.actual_checksum
67
68         self.expected_text = self.actual_text
69         self.expected_image = self.actual_image
70
71         self.actual_audio = None
72         self.expected_audio = None
73
74
75 # This is an in-memory list of tests, what we want them to produce, and
76 # what we want to claim are the expected results.
77 class TestList(object):
78     def __init__(self):
79         self.tests = {}
80
81     def add(self, name, **kwargs):
82         test = TestInstance(name)
83         for key, value in kwargs.items():
84             test.__dict__[key] = value
85         self.tests[name] = test
86
87     def add_reftest(self, name, reference_name, same_image, crash=False):
88         self.add(name, actual_checksum='xxx', actual_image='XXX', is_reftest=True, crash=crash)
89         if same_image:
90             self.add(reference_name, actual_checksum='xxx', actual_image='XXX', is_reftest=True)
91         else:
92             self.add(reference_name, actual_checksum='yyy', actual_image='YYY', is_reftest=True)
93
94     def keys(self):
95         return self.tests.keys()
96
97     def __contains__(self, item):
98         return item in self.tests
99
100     def __getitem__(self, item):
101         return self.tests[item]
102
103 #
104 # These numbers may need to be updated whenever we add or delete tests. This includes virtual tests.
105 #
106 TOTAL_TESTS = 117
107 TOTAL_SKIPS = 30
108
109 UNEXPECTED_PASSES = 1
110 UNEXPECTED_FAILURES = 26
111
112 def unit_test_list():
113     tests = TestList()
114     tests.add('failures/expected/crash.html', crash=True)
115     tests.add('failures/expected/exception.html', exception=True)
116     tests.add('failures/expected/device_failure.html', device_failure=True)
117     tests.add('failures/expected/timeout.html', timeout=True)
118     tests.add('failures/expected/leak.html', leak=True)
119     tests.add('failures/expected/missing_text.html', expected_text=None)
120     tests.add('failures/expected/needsrebaseline.html', actual_text='needsrebaseline text')
121     tests.add('failures/expected/needsmanualrebaseline.html', actual_text='needsmanualrebaseline text')
122     tests.add('failures/expected/image.html',
123               actual_image='image_fail-pngtEXtchecksum\x00checksum_fail',
124               expected_image='image-pngtEXtchecksum\x00checksum-png')
125     tests.add('failures/expected/image_checksum.html',
126               actual_checksum='image_checksum_fail-checksum',
127               actual_image='image_checksum_fail-png')
128     tests.add('failures/expected/audio.html',
129               actual_audio=base64.b64encode('audio_fail-wav'), expected_audio='audio-wav',
130               actual_text=None, expected_text=None,
131               actual_image=None, expected_image=None,
132               actual_checksum=None)
133     tests.add('failures/expected/keyboard.html', keyboard=True)
134     tests.add('failures/expected/missing_check.html',
135               expected_image='missing_check-png')
136     tests.add('failures/expected/missing_image.html', expected_image=None)
137     tests.add('failures/expected/missing_audio.html', expected_audio=None,
138               actual_text=None, expected_text=None,
139               actual_image=None, expected_image=None,
140               actual_checksum=None)
141     tests.add('failures/expected/missing_text.html', expected_text=None)
142     tests.add('failures/expected/newlines_leading.html',
143               expected_text="\nfoo\n", actual_text="foo\n")
144     tests.add('failures/expected/newlines_trailing.html',
145               expected_text="foo\n\n", actual_text="foo\n")
146     tests.add('failures/expected/newlines_with_excess_CR.html',
147               expected_text="foo\r\r\r\n", actual_text="foo\n")
148     tests.add('failures/expected/testharness.html',
149             actual_text='This is a testharness.js-based test.\nFAIL: assert fired\n.Harness: the test ran to completion.\n\n', expected_text=None,
150               actual_image=None, expected_image=None,
151               actual_checksum=None)
152     tests.add('failures/expected/testharness.html',
153             actual_text='CONSOLE LOG: error.\nThis is a testharness.js-based test.\nPASS: things are fine.\n.Harness: the test ran to completion.\n\n', expected_text=None,
154               actual_image=None, expected_image=None,
155               actual_checksum=None)
156     tests.add('failures/expected/text.html', actual_text='text_fail-png')
157     tests.add('failures/expected/crash_then_text.html')
158     tests.add('failures/expected/skip_text.html', actual_text='text diff')
159     tests.add('failures/flaky/text.html')
160     tests.add('failures/unexpected/missing_text.html', expected_text=None)
161     tests.add('failures/unexpected/missing_check.html', expected_image='missing-check-png')
162     tests.add('failures/unexpected/missing_image.html', expected_image=None)
163     tests.add('failures/unexpected/missing_render_tree_dump.html', actual_text="""layer at (0,0) size 800x600
164   RenderView at (0,0) size 800x600
165 layer at (0,0) size 800x34
166   RenderBlock {HTML} at (0,0) size 800x34
167     RenderBody {BODY} at (8,8) size 784x18
168       RenderText {#text} at (0,0) size 133x18
169         text run at (0,0) width 133: "This is an image test!"
170 """, expected_text=None)
171     tests.add('failures/unexpected/crash.html', crash=True)
172     tests.add('failures/unexpected/crash-with-stderr.html', crash=True,
173               error="mock-std-error-output")
174     tests.add('failures/unexpected/web-process-crash-with-stderr.html', web_process_crash=True,
175               error="mock-std-error-output")
176     tests.add('failures/unexpected/pass.html')
177     tests.add('failures/unexpected/text-checksum.html',
178               actual_text='text-checksum_fail-txt',
179               actual_checksum='text-checksum_fail-checksum')
180     tests.add('failures/unexpected/text-image-checksum.html',
181               actual_text='text-image-checksum_fail-txt',
182               actual_image='text-image-checksum_fail-pngtEXtchecksum\x00checksum_fail',
183               actual_checksum='text-image-checksum_fail-checksum')
184     tests.add('failures/unexpected/checksum-with-matching-image.html',
185               actual_checksum='text-image-checksum_fail-checksum')
186     tests.add('failures/unexpected/skip_pass.html')
187     tests.add('failures/unexpected/text.html', actual_text='text_fail-txt')
188     tests.add('failures/unexpected/text_then_crash.html')
189     tests.add('failures/unexpected/timeout.html', timeout=True)
190     tests.add('failures/unexpected/leak.html', leak=True)
191     tests.add('http/tests/passes/text.html')
192     tests.add('http/tests/passes/image.html')
193     tests.add('http/tests/ssl/text.html')
194     tests.add('passes/args.html')
195     tests.add('passes/error.html', error='stuff going to stderr')
196     tests.add('passes/image.html')
197     tests.add('passes/audio.html',
198               actual_audio=base64.b64encode('audio-wav'), expected_audio='audio-wav',
199               actual_text=None, expected_text=None,
200               actual_image=None, expected_image=None,
201               actual_checksum=None)
202     tests.add('passes/platform_image.html')
203     tests.add('passes/checksum_in_image.html',
204               expected_image='tEXtchecksum\x00checksum_in_image-checksum')
205     tests.add('passes/skipped/skip.html')
206     tests.add('passes/testharness.html',
207             actual_text='This is a testharness.js-based test.\nPASS: assert is fine\nHarness: the test ran to completion.\n\n', expected_text=None,
208               actual_image=None, expected_image=None,
209               actual_checksum=None)
210
211     # Note that here the checksums don't match but the images do, so this test passes "unexpectedly".
212     # See https://bugs.webkit.org/show_bug.cgi?id=69444 .
213     tests.add('failures/unexpected/checksum.html', actual_checksum='checksum_fail-checksum')
214
215     # Text output files contain "\r\n" on Windows.  This may be
216     # helpfully filtered to "\r\r\n" by our Python/Cygwin tooling.
217     tests.add('passes/text.html',
218               expected_text='\nfoo\n\n', actual_text='\nfoo\r\n\r\r\n')
219
220     # For reftests.
221     tests.add_reftest('passes/reftest.html', 'passes/reftest-expected.html', same_image=True)
222
223     # This adds a different virtual reference to ensure that that also works.
224     tests.add('virtual/passes/reftest-expected.html', actual_checksum='xxx', actual_image='XXX', is_reftest=True)
225
226     tests.add_reftest('passes/mismatch.html', 'passes/mismatch-expected-mismatch.html', same_image=False)
227     tests.add_reftest('passes/svgreftest.svg', 'passes/svgreftest-expected.svg', same_image=True)
228     tests.add_reftest('passes/xhtreftest.xht', 'passes/xhtreftest-expected.html', same_image=True)
229     tests.add_reftest('passes/phpreftest.php', 'passes/phpreftest-expected-mismatch.svg', same_image=False)
230     tests.add_reftest('failures/expected/reftest.html', 'failures/expected/reftest-expected.html', same_image=False)
231     tests.add_reftest('failures/expected/mismatch.html', 'failures/expected/mismatch-expected-mismatch.html', same_image=True)
232     tests.add_reftest('failures/unexpected/crash-reftest.html', 'failures/unexpected/crash-reftest-expected.html', same_image=True, crash=True)
233     tests.add_reftest('failures/unexpected/reftest.html', 'failures/unexpected/reftest-expected.html', same_image=False)
234     tests.add_reftest('failures/unexpected/mismatch.html', 'failures/unexpected/mismatch-expected-mismatch.html', same_image=True)
235     tests.add('failures/unexpected/reftest-nopixel.html', actual_checksum=None, actual_image=None, is_reftest=True)
236     tests.add('failures/unexpected/reftest-nopixel-expected.html', actual_checksum=None, actual_image=None, is_reftest=True)
237     tests.add('reftests/foo/test.html')
238     tests.add('reftests/foo/test-ref.html')
239
240     tests.add('reftests/foo/multiple-match-success.html', actual_checksum='abc', actual_image='abc')
241     tests.add('reftests/foo/multiple-match-failure.html', actual_checksum='abc', actual_image='abc')
242     tests.add('reftests/foo/multiple-mismatch-success.html', actual_checksum='abc', actual_image='abc')
243     tests.add('reftests/foo/multiple-mismatch-failure.html', actual_checksum='abc', actual_image='abc')
244     tests.add('reftests/foo/multiple-both-success.html', actual_checksum='abc', actual_image='abc')
245     tests.add('reftests/foo/multiple-both-failure.html', actual_checksum='abc', actual_image='abc')
246
247     tests.add('reftests/foo/matching-ref.html', actual_checksum='abc', actual_image='abc')
248     tests.add('reftests/foo/mismatching-ref.html', actual_checksum='def', actual_image='def')
249     tests.add('reftests/foo/second-mismatching-ref.html', actual_checksum='ghi', actual_image='ghi')
250
251     # The following files shouldn't be treated as reftests
252     tests.add_reftest('reftests/foo/unlistedtest.html', 'reftests/foo/unlistedtest-expected.html', same_image=True)
253     tests.add('reftests/foo/reference/bar/common.html')
254     tests.add('reftests/foo/reftest/bar/shared.html')
255
256     tests.add('websocket/tests/passes/text.html')
257
258     # For testing that we don't run tests under platform/. Note that these don't contribute to TOTAL_TESTS.
259     tests.add('platform/test-mac-leopard/http/test.html')
260     tests.add('platform/test-win-win7/http/test.html')
261
262     # For testing if perf tests are running in a locked shard.
263     tests.add('perf/foo/test.html')
264     tests.add('perf/foo/test-ref.html')
265
266     # For testing --pixel-test-directories.
267     tests.add('failures/unexpected/pixeldir/image_in_pixeldir.html',
268         actual_image='image_in_pixeldir-pngtEXtchecksum\x00checksum_fail',
269         expected_image='image_in_pixeldir-pngtEXtchecksum\x00checksum-png')
270     tests.add('failures/unexpected/image_not_in_pixeldir.html',
271         actual_image='image_not_in_pixeldir-pngtEXtchecksum\x00checksum_fail',
272         expected_image='image_not_in_pixeldir-pngtEXtchecksum\x00checksum-png')
273
274     # For testing that virtual test suites don't expand names containing themselves
275     # See webkit.org/b/97925 and base_unittest.PortTest.test_tests().
276     tests.add('passes/test-virtual-passes.html')
277     tests.add('passes/passes/test-virtual-passes.html')
278
279     return tests
280
281
282 # Here we use a non-standard location for the layout tests, to ensure that
283 # this works. The path contains a '.' in the name because we've seen bugs
284 # related to this before.
285
286 LAYOUT_TEST_DIR = '/test.checkout/LayoutTests'
287 PERF_TEST_DIR = '/test.checkout/PerformanceTests'
288
289
290 # Here we synthesize an in-memory filesystem from the test list
291 # in order to fully control the test output and to demonstrate that
292 # we don't need a real filesystem to run the tests.
293 def add_unit_tests_to_mock_filesystem(filesystem):
294     # Add the test_expectations file.
295     filesystem.maybe_make_directory('/mock-checkout/LayoutTests')
296     if not filesystem.exists('/mock-checkout/LayoutTests/TestExpectations'):
297         filesystem.write_text_file('/mock-checkout/LayoutTests/TestExpectations', """
298 Bug(test) failures/expected/crash.html [ Crash ]
299 Bug(test) failures/expected/crash_then_text.html [ Failure ]
300 Bug(test) failures/expected/image.html [ ImageOnlyFailure ]
301 Bug(test) failures/expected/needsrebaseline.html [ NeedsRebaseline ]
302 Bug(test) failures/expected/needsmanualrebaseline.html [ NeedsManualRebaseline ]
303 Bug(test) failures/expected/audio.html [ Failure ]
304 Bug(test) failures/expected/image_checksum.html [ ImageOnlyFailure ]
305 Bug(test) failures/expected/mismatch.html [ ImageOnlyFailure ]
306 Bug(test) failures/expected/missing_check.html [ Missing Pass ]
307 Bug(test) failures/expected/missing_image.html [ Missing Pass ]
308 Bug(test) failures/expected/missing_audio.html [ Missing Pass ]
309 Bug(test) failures/expected/missing_text.html [ Missing Pass ]
310 Bug(test) failures/expected/newlines_leading.html [ Failure ]
311 Bug(test) failures/expected/newlines_trailing.html [ Failure ]
312 Bug(test) failures/expected/newlines_with_excess_CR.html [ Failure ]
313 Bug(test) failures/expected/reftest.html [ ImageOnlyFailure ]
314 Bug(test) failures/expected/text.html [ Failure ]
315 Bug(test) failures/expected/testharness.html [ Failure ]
316 Bug(test) failures/expected/timeout.html [ Timeout ]
317 Bug(test) failures/expected/keyboard.html [ WontFix ]
318 Bug(test) failures/expected/exception.html [ WontFix ]
319 Bug(test) failures/expected/device_failure.html [ WontFix ]
320 Bug(test) failures/expected/leak.html [ Leak ]
321 Bug(test) failures/unexpected/pass.html [ Failure ]
322 Bug(test) passes/skipped/skip.html [ Skip ]
323 Bug(test) passes/text.html [ Pass ]
324 """)
325
326     filesystem.maybe_make_directory(LAYOUT_TEST_DIR + '/reftests/foo')
327     filesystem.write_text_file(LAYOUT_TEST_DIR + '/reftests/foo/reftest.list', """
328 == test.html test-ref.html
329
330 == multiple-match-success.html mismatching-ref.html
331 == multiple-match-success.html matching-ref.html
332 == multiple-match-failure.html mismatching-ref.html
333 == multiple-match-failure.html second-mismatching-ref.html
334 != multiple-mismatch-success.html mismatching-ref.html
335 != multiple-mismatch-success.html second-mismatching-ref.html
336 != multiple-mismatch-failure.html mismatching-ref.html
337 != multiple-mismatch-failure.html matching-ref.html
338 == multiple-both-success.html matching-ref.html
339 == multiple-both-success.html mismatching-ref.html
340 != multiple-both-success.html second-mismatching-ref.html
341 == multiple-both-failure.html matching-ref.html
342 != multiple-both-failure.html second-mismatching-ref.html
343 != multiple-both-failure.html matching-ref.html
344 """)
345
346     # FIXME: This test was only being ignored because of missing a leading '/'.
347     # Fixing the typo causes several tests to assert, so disabling the test entirely.
348     # Add in a file should be ignored by port.find_test_files().
349     #files[LAYOUT_TEST_DIR + '/userscripts/resources/iframe.html'] = 'iframe'
350
351     def add_file(test, suffix, contents):
352         dirname = filesystem.join(LAYOUT_TEST_DIR, test.name[0:test.name.rfind('/')])
353         base = test.base
354         filesystem.maybe_make_directory(dirname)
355         filesystem.write_binary_file(filesystem.join(dirname, base + suffix), contents)
356
357     # Add each test and the expected output, if any.
358     test_list = unit_test_list()
359     for test in test_list.tests.values():
360         add_file(test, test.name[test.name.rfind('.'):], '')
361         if test.is_reftest:
362             continue
363         if test.actual_audio:
364             add_file(test, '-expected.wav', test.expected_audio)
365             continue
366         add_file(test, '-expected.txt', test.expected_text)
367         add_file(test, '-expected.png', test.expected_image)
368
369     filesystem.write_text_file(filesystem.join(LAYOUT_TEST_DIR, 'virtual', 'passes', 'args-expected.txt'), 'args-txt --virtual-arg')
370     # Clear the list of written files so that we can watch what happens during testing.
371     filesystem.clear_written_files()
372
373
374 class TestPort(Port):
375     port_name = 'test'
376     default_port_name = 'test-mac-leopard'
377
378     """Test implementation of the Port interface."""
379     ALL_BASELINE_VARIANTS = (
380         'test-linux-x86_64',
381         'test-mac-snowleopard', 'test-mac-leopard',
382         'test-win-win7', 'test-win-xp',
383     )
384
385     FALLBACK_PATHS = {
386         'xp':          ['test-win-win7', 'test-win-xp'],
387         'win7':        ['test-win-win7'],
388         'leopard':     ['test-mac-leopard', 'test-mac-snowleopard'],
389         'snowleopard': ['test-mac-snowleopard'],
390         'lucid':       ['test-linux-x86_64', 'test-win-win7'],
391     }
392
393     @classmethod
394     def determine_full_port_name(cls, host, options, port_name):
395         if port_name == 'test':
396             return TestPort.default_port_name
397         return port_name
398
399     def __init__(self, host, port_name=None, **kwargs):
400         Port.__init__(self, host, port_name or TestPort.default_port_name, **kwargs)
401         self._tests = unit_test_list()
402         self._flakes = set()
403
404         # FIXME: crbug.com/279494. This needs to be in the "real layout tests
405         # dir" in a mock filesystem, rather than outside of the checkout, so
406         # that tests that want to write to a TestExpectations file can share
407         # this between "test" ports and "real" ports.  This is the result of
408         # rebaseline_unittest.py having tests that refer to "real" port names
409         # and real builders instead of fake builders that point back to the
410         # test ports. rebaseline_unittest.py needs to not mix both "real" ports
411         # and "test" ports
412
413         self._generic_expectations_path = '/mock-checkout/LayoutTests/TestExpectations'
414         self._results_directory = None
415
416         self._operating_system = 'mac'
417         if self._name.startswith('test-win'):
418             self._operating_system = 'win'
419         elif self._name.startswith('test-linux'):
420             self._operating_system = 'linux'
421
422         version_map = {
423             'test-win-xp': 'xp',
424             'test-win-win7': 'win7',
425             'test-mac-leopard': 'leopard',
426             'test-mac-snowleopard': 'snowleopard',
427             'test-linux-x86_64': 'lucid',
428         }
429         self._version = version_map[self._name]
430
431     def repository_paths(self):
432         """Returns a list of (repository_name, repository_path) tuples of its depending code base."""
433         # FIXME: We override this just to keep the perf tests happy.
434         return [('blink', self.layout_tests_dir())]
435
436     def buildbot_archives_baselines(self):
437         return self._name != 'test-win-xp'
438
439     def default_pixel_tests(self):
440         return True
441
442     def _path_to_driver(self):
443         # This routine shouldn't normally be called, but it is called by
444         # the mock_drt Driver. We return something, but make sure it's useless.
445         return 'MOCK _path_to_driver'
446
447     def default_child_processes(self):
448         return 1
449
450     def check_build(self, needs_http, printer):
451         return test_run_results.OK_EXIT_STATUS
452
453     def check_sys_deps(self, needs_http):
454         return test_run_results.OK_EXIT_STATUS
455
456     def default_configuration(self):
457         return 'Release'
458
459     def diff_image(self, expected_contents, actual_contents):
460         diffed = actual_contents != expected_contents
461         if not actual_contents and not expected_contents:
462             return (None, None)
463         if not actual_contents or not expected_contents:
464             return (True, None)
465         if diffed:
466             return ("< %s\n---\n> %s\n" % (expected_contents, actual_contents), None)
467         return (None, None)
468
469     def layout_tests_dir(self):
470         return LAYOUT_TEST_DIR
471
472     def perf_tests_dir(self):
473         return PERF_TEST_DIR
474
475     def webkit_base(self):
476         return '/test.checkout'
477
478     def _skipped_tests_for_unsupported_features(self, test_list):
479         return set(['failures/expected/skip_text.html',
480                     'failures/unexpected/skip_pass.html',
481                     'virtual/skipped'])
482
483     def name(self):
484         return self._name
485
486     def operating_system(self):
487         return self._operating_system
488
489     def _path_to_wdiff(self):
490         return None
491
492     def default_results_directory(self):
493         return '/tmp/layout-test-results'
494
495     def setup_test_run(self):
496         pass
497
498     def _driver_class(self):
499         return TestDriver
500
501     def start_http_server(self, additional_dirs, number_of_drivers):
502         pass
503
504     def start_websocket_server(self):
505         pass
506
507     def acquire_http_lock(self):
508         pass
509
510     def stop_http_server(self):
511         pass
512
513     def stop_websocket_server(self):
514         pass
515
516     def release_http_lock(self):
517         pass
518
519     def path_to_lighttpd(self):
520         return "/usr/sbin/lighttpd"
521
522     def path_to_lighttpd_modules(self):
523         return "/usr/lib/lighttpd"
524
525     def path_to_lighttpd_php(self):
526         return "/usr/bin/php-cgi"
527
528     def path_to_apache(self):
529         return "/usr/sbin/httpd"
530
531     def path_to_apache_config_file(self):
532         return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 'httpd.conf')
533
534     def path_to_generic_test_expectations_file(self):
535         return self._generic_expectations_path
536
537     def _port_specific_expectations_files(self):
538         return [self._filesystem.join(self._webkit_baseline_path(d), 'TestExpectations') for d in ['test', 'test-win-xp']]
539
540     def all_test_configurations(self):
541         """Returns a sequence of the TestConfigurations the port supports."""
542         # By default, we assume we want to test every graphics type in
543         # every configuration on every system.
544         test_configurations = []
545         for version, architecture in self._all_systems():
546             for build_type in self._all_build_types():
547                 test_configurations.append(TestConfiguration(
548                     version=version,
549                     architecture=architecture,
550                     build_type=build_type))
551         return test_configurations
552
553     def _all_systems(self):
554         return (('leopard', 'x86'),
555                 ('snowleopard', 'x86'),
556                 ('xp', 'x86'),
557                 ('win7', 'x86'),
558                 ('lucid', 'x86'),
559                 ('lucid', 'x86_64'))
560
561     def _all_build_types(self):
562         return ('debug', 'release')
563
564     def configuration_specifier_macros(self):
565         """To avoid surprises when introducing new macros, these are intentionally fixed in time."""
566         return {'mac': ['leopard', 'snowleopard'], 'win': ['xp', 'win7'], 'linux': ['lucid']}
567
568     def all_baseline_variants(self):
569         return self.ALL_BASELINE_VARIANTS
570
571     def virtual_test_suites(self):
572         return [
573             VirtualTestSuite('passes', 'passes', ['--virtual-arg'], use_legacy_naming=True),
574             VirtualTestSuite('skipped', 'failures/expected', ['--virtual-arg2'], use_legacy_naming=True),
575         ]
576
577
578 class TestDriver(Driver):
579     """Test/Dummy implementation of the driver interface."""
580     next_pid = 1
581
582     def __init__(self, *args, **kwargs):
583         super(TestDriver, self).__init__(*args, **kwargs)
584         self.started = False
585         self.pid = 0
586
587     def cmd_line(self, pixel_tests, per_test_args):
588         pixel_tests_flag = '-p' if pixel_tests else ''
589         return [self._port._path_to_driver()] + [pixel_tests_flag] + self._port.get_option('additional_drt_flag', []) + per_test_args
590
591     def run_test(self, driver_input, stop_when_done):
592         if not self.started:
593             self.started = True
594             self.pid = TestDriver.next_pid
595             TestDriver.next_pid += 1
596
597         start_time = time.time()
598         test_name = driver_input.test_name
599         test_args = driver_input.args or []
600         test = self._port._tests[test_name]
601         if test.keyboard:
602             raise KeyboardInterrupt
603         if test.exception:
604             raise ValueError('exception from ' + test_name)
605         if test.device_failure:
606             raise DeviceFailure('device failure in ' + test_name)
607
608         audio = None
609         actual_text = test.actual_text
610         crash = test.crash
611         web_process_crash = test.web_process_crash
612
613         if 'flaky/text.html' in test_name and not test_name in self._port._flakes:
614             self._port._flakes.add(test_name)
615             actual_text = 'flaky text failure'
616
617         if 'crash_then_text.html' in test_name:
618             if test_name in self._port._flakes:
619                 actual_text = 'text failure'
620             else:
621                 self._port._flakes.add(test_name)
622                 crashed_process_name = self._port.driver_name()
623                 crashed_pid = 1
624                 crash = True
625
626         if 'text_then_crash.html' in test_name:
627             if test_name in self._port._flakes:
628                 crashed_process_name = self._port.driver_name()
629                 crashed_pid = 1
630                 crash = True
631             else:
632                 self._port._flakes.add(test_name)
633                 actual_text = 'text failure'
634
635         if actual_text and test_args and test_name == 'passes/args.html':
636             actual_text = actual_text + ' ' + ' '.join(test_args)
637
638         if test.actual_audio:
639             audio = base64.b64decode(test.actual_audio)
640         crashed_process_name = None
641         crashed_pid = None
642         if crash:
643             crashed_process_name = self._port.driver_name()
644             crashed_pid = 1
645         elif web_process_crash:
646             crashed_process_name = 'WebProcess'
647             crashed_pid = 2
648
649         crash_log = ''
650         if crashed_process_name:
651             crash_logs = CrashLogs(self._port.host)
652             crash_log = crash_logs.find_newest_log(crashed_process_name, None) or ''
653
654         if stop_when_done:
655             self.stop()
656
657         if test.actual_checksum == driver_input.image_hash:
658             image = None
659         else:
660             image = test.actual_image
661         return DriverOutput(actual_text, image, test.actual_checksum, audio,
662             crash=(crash or web_process_crash), crashed_process_name=crashed_process_name,
663             crashed_pid=crashed_pid, crash_log=crash_log,
664             test_time=time.time() - start_time, timeout=test.timeout, error=test.error, pid=self.pid,
665             leak=test.leak)
666
667     def stop(self):
668         self.started = False