Unreviewed followup to r136545, manually removing the unnecessary executable bit...
[WebKit-https.git] / Tools / Scripts / webkitpy / layout_tests / port / port_testcase.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 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 """Unit testing base class for Port implementations."""
30
31 import errno
32 import logging
33 import os
34 import socket
35 import sys
36 import time
37 import unittest
38
39 from webkitpy.common.system.executive_mock import MockExecutive
40 from webkitpy.common.system.filesystem_mock import MockFileSystem
41 from webkitpy.common.system.outputcapture import OutputCapture
42 from webkitpy.common.system.systemhost_mock import MockSystemHost
43 from webkitpy.layout_tests.port.base import Port
44 from webkitpy.layout_tests.port.server_process_mock import MockServerProcess
45 from webkitpy.layout_tests.servers import http_server_base
46 from webkitpy.tool.mocktool import MockOptions
47
48
49 # FIXME: get rid of this fixture
50 class TestWebKitPort(Port):
51     port_name = "testwebkitport"
52
53     def __init__(self, symbols_string=None,
54                  expectations_file=None, skips_file=None, host=None, config=None,
55                  **kwargs):
56         self.symbols_string = symbols_string  # Passing "" disables all staticly-detectable features.
57         host = host or MockSystemHost()
58         super(TestWebKitPort, self).__init__(host=host, **kwargs)
59
60     def all_test_configurations(self):
61         return [self.test_configuration()]
62
63     def _symbols_string(self):
64         return self.symbols_string
65
66     def _tests_for_other_platforms(self):
67         return ["media", ]
68
69     def _tests_for_disabled_features(self):
70         return ["accessibility", ]
71
72
73 class PortTestCase(unittest.TestCase):
74     """Tests that all Port implementations must pass."""
75     HTTP_PORTS = (8000, 8080, 8443)
76     WEBSOCKET_PORTS = (8880,)
77
78     # Subclasses override this to point to their Port subclass.
79     os_name = None
80     os_version = None
81     port_maker = TestWebKitPort
82     port_name = None
83
84     def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=None, **kwargs):
85         host = host or MockSystemHost(os_name=(os_name or self.os_name), os_version=(os_version or self.os_version))
86         options = options or MockOptions(configuration='Release')
87         port_name = port_name or self.port_name
88         port_name = self.port_maker.determine_full_port_name(host, options, port_name)
89         port = self.port_maker(host, port_name, options=options, **kwargs)
90         port._config.build_directory = lambda configuration: '/mock-build'
91         return port
92
93     def test_default_max_locked_shards(self):
94         port = self.make_port()
95         port.default_child_processes = lambda: 16
96         self.assertEqual(port.default_max_locked_shards(), 1)
97         port.default_child_processes = lambda: 2
98         self.assertEqual(port.default_max_locked_shards(), 1)
99
100     def test_default_timeout_ms(self):
101         self.assertEqual(self.make_port(options=MockOptions(configuration='Release')).default_timeout_ms(), 35000)
102         self.assertEqual(self.make_port(options=MockOptions(configuration='Debug')).default_timeout_ms(), 35000)
103
104     def test_default_pixel_tests(self):
105         self.assertEqual(self.make_port().default_pixel_tests(), False)
106
107     def test_driver_cmd_line(self):
108         port = self.make_port()
109         self.assertTrue(len(port.driver_cmd_line()))
110
111         options = MockOptions(additional_drt_flag=['--foo=bar', '--foo=baz'])
112         port = self.make_port(options=options)
113         cmd_line = port.driver_cmd_line()
114         self.assertTrue('--foo=bar' in cmd_line)
115         self.assertTrue('--foo=baz' in cmd_line)
116
117     def test_uses_apache(self):
118         self.assertTrue(self.make_port()._uses_apache())
119
120     def assert_servers_are_down(self, host, ports):
121         for port in ports:
122             try:
123                 test_socket = socket.socket()
124                 test_socket.connect((host, port))
125                 self.fail()
126             except IOError, e:
127                 self.assertTrue(e.errno in (errno.ECONNREFUSED, errno.ECONNRESET))
128             finally:
129                 test_socket.close()
130
131     def assert_servers_are_up(self, host, ports):
132         for port in ports:
133             try:
134                 test_socket = socket.socket()
135                 test_socket.connect((host, port))
136             except IOError, e:
137                 self.fail('failed to connect to %s:%d' % (host, port))
138             finally:
139                 test_socket.close()
140
141     def integration_test_http_lock(self):
142         port = self.make_port()
143         # Only checking that no exception is raised.
144         port.acquire_http_lock()
145         port.release_http_lock()
146
147     def integration_test_check_sys_deps(self):
148         port = self.make_port()
149         # Only checking that no exception is raised.
150         port.check_sys_deps(True)
151
152     def integration_test_helper(self):
153         port = self.make_port()
154         # Only checking that no exception is raised.
155         port.start_helper()
156         port.stop_helper()
157
158     def integration_test_http_server__normal(self):
159         port = self.make_port()
160         self.assert_servers_are_down('localhost', self.HTTP_PORTS)
161         port.start_http_server()
162         self.assert_servers_are_up('localhost', self.HTTP_PORTS)
163         port.stop_http_server()
164         self.assert_servers_are_down('localhost', self.HTTP_PORTS)
165
166     def integration_test_http_server__fails(self):
167         port = self.make_port()
168         # Test that if a port isn't available, the call fails.
169         for port_number in self.HTTP_PORTS:
170             test_socket = socket.socket()
171             try:
172                 try:
173                     test_socket.bind(('localhost', port_number))
174                 except socket.error, e:
175                     if e.errno in (errno.EADDRINUSE, errno.EALREADY):
176                         self.fail('could not bind to port %d' % port_number)
177                     raise
178                 try:
179                     port.start_http_server()
180                     self.fail('should not have been able to start the server while bound to %d' % port_number)
181                 except http_server_base.ServerError, e:
182                     pass
183             finally:
184                 port.stop_http_server()
185                 test_socket.close()
186
187         # Test that calling start() twice fails.
188         try:
189             port.start_http_server()
190             self.assertRaises(AssertionError, port.start_http_server)
191         finally:
192             port.stop_http_server()
193
194     def integration_test_http_server__two_servers(self):
195         # Test that calling start() on two different ports causes the
196         # first port to be treated as stale and killed.
197         port = self.make_port()
198         # Test that if a port isn't available, the call fails.
199         port.start_http_server()
200         new_port = self.make_port()
201         try:
202             new_port.start_http_server()
203
204             # Check that the first server was killed.
205             self.assertFalse(port._executive.check_running_pid(port._http_server._pid))
206
207             # Check that there is something running.
208             self.assert_servers_are_up('localhost', self.HTTP_PORTS)
209
210             # Test that calling stop() on a killed server is harmless.
211             port.stop_http_server()
212         finally:
213             port.stop_http_server()
214             new_port.stop_http_server()
215
216             # Test that calling stop() twice is harmless.
217             new_port.stop_http_server()
218
219     def integration_test_image_diff(self):
220         port = self.make_port()
221         # FIXME: This test will never run since we are using a MockFilesystem for these tests!?!?
222         if not port.check_image_diff():
223             # The port hasn't been built - don't run the tests.
224             return
225
226         dir = port.layout_tests_dir()
227         file1 = port._filesystem.join(dir, 'fast', 'css', 'button_center.png')
228         contents1 = port._filesystem.read_binary_file(file1)
229         file2 = port._filesystem.join(dir, 'fast', 'css',
230                                       'remove-shorthand-expected.png')
231         contents2 = port._filesystem.read_binary_file(file2)
232         tmpfd, tmpfile = port._filesystem.open_binary_tempfile('')
233         tmpfd.close()
234
235         self.assertFalse(port.diff_image(contents1, contents1)[0])
236         self.assertTrue(port.diff_image(contents1, contents2)[0])
237
238         self.assertTrue(port.diff_image(contents1, contents2, tmpfile)[0])
239
240         port._filesystem.remove(tmpfile)
241
242     def test_diff_image__missing_both(self):
243         port = self.make_port()
244         self.assertFalse(port.diff_image(None, None)[0])
245         self.assertFalse(port.diff_image(None, '')[0])
246         self.assertFalse(port.diff_image('', None)[0])
247
248         self.assertFalse(port.diff_image('', '')[0])
249
250     def test_diff_image__missing_actual(self):
251         port = self.make_port()
252         self.assertTrue(port.diff_image(None, 'foo')[0])
253         self.assertTrue(port.diff_image('', 'foo')[0])
254
255     def test_diff_image__missing_expected(self):
256         port = self.make_port()
257         self.assertTrue(port.diff_image('foo', None)[0])
258         self.assertTrue(port.diff_image('foo', '')[0])
259
260     def test_diff_image(self):
261         port = self.make_port()
262         self.proc = None
263
264         def make_proc(port, nm, cmd, env):
265             self.proc = MockServerProcess(port, nm, cmd, env, lines=['diff: 100% failed\n', 'diff: 100% failed\n'])
266             return self.proc
267
268         port._server_process_constructor = make_proc
269         port.setup_test_run()
270         self.assertEqual(port.diff_image('foo', 'bar'), ('', 100.0, None))
271         self.assertEqual(self.proc.cmd[1:3], ["--tolerance", "0.1"])
272
273         self.assertEqual(port.diff_image('foo', 'bar', None), ('', 100.0, None))
274         self.assertEqual(self.proc.cmd[1:3], ["--tolerance", "0.1"])
275
276         self.assertEqual(port.diff_image('foo', 'bar', 0), ('', 100.0, None))
277         self.assertEqual(self.proc.cmd[1:3], ["--tolerance", "0"])
278
279         port.clean_up_test_run()
280         self.assertTrue(self.proc.stopped)
281         self.assertEqual(port._image_differ, None)
282
283     def test_diff_image_crashed(self):
284         port = self.make_port()
285         self.proc = None
286
287         def make_proc(port, nm, cmd, env):
288             self.proc = MockServerProcess(port, nm, cmd, env, crashed=True)
289             return self.proc
290
291         port._server_process_constructor = make_proc
292         port.setup_test_run()
293         self.assertEqual(port.diff_image('foo', 'bar'), ('', 0, 'ImageDiff crashed\n'))
294         port.clean_up_test_run()
295
296     def test_check_wdiff(self):
297         port = self.make_port()
298         port.check_wdiff()
299
300     def integration_test_websocket_server__normal(self):
301         port = self.make_port()
302         self.assert_servers_are_down('localhost', self.WEBSOCKET_PORTS)
303         port.start_websocket_server()
304         self.assert_servers_are_up('localhost', self.WEBSOCKET_PORTS)
305         port.stop_websocket_server()
306         self.assert_servers_are_down('localhost', self.WEBSOCKET_PORTS)
307
308     def integration_test_websocket_server__fails(self):
309         port = self.make_port()
310
311         # Test that start() fails if a port isn't available.
312         for port_number in self.WEBSOCKET_PORTS:
313             test_socket = socket.socket()
314             try:
315                 test_socket.bind(('localhost', port_number))
316                 try:
317                     port.start_websocket_server()
318                     self.fail('should not have been able to start the server while bound to %d' % port_number)
319                 except http_server_base.ServerError, e:
320                     pass
321             finally:
322                 port.stop_websocket_server()
323                 test_socket.close()
324
325         # Test that calling start() twice fails.
326         try:
327             port.start_websocket_server()
328             self.assertRaises(AssertionError, port.start_websocket_server)
329         finally:
330             port.stop_websocket_server()
331
332     def integration_test_websocket_server__two_servers(self):
333         port = self.make_port()
334
335         # Test that calling start() on two different ports causes the
336         # first port to be treated as stale and killed.
337         port.start_websocket_server()
338         new_port = self.make_port()
339         try:
340             new_port.start_websocket_server()
341
342             # Check that the first server was killed.
343             self.assertFalse(port._executive.check_running_pid(port._websocket_server._pid))
344
345             # Check that there is something running.
346             self.assert_servers_are_up('localhost', self.WEBSOCKET_PORTS)
347
348             # Test that calling stop() on a killed server is harmless.
349             port.stop_websocket_server()
350         finally:
351             port.stop_websocket_server()
352             new_port.stop_websocket_server()
353
354             # Test that calling stop() twice is harmless.
355             new_port.stop_websocket_server()
356
357     def test_test_configuration(self):
358         port = self.make_port()
359         self.assertTrue(port.test_configuration())
360
361     def test_all_test_configurations(self):
362         port = self.make_port()
363         self.assertTrue(len(port.all_test_configurations()) > 0)
364         self.assertTrue(port.test_configuration() in port.all_test_configurations(), "%s not in %s" % (port.test_configuration(), port.all_test_configurations()))
365
366     def integration_test_http_server__loop(self):
367         port = self.make_port()
368
369         i = 0
370         while i < 10:
371             self.assert_servers_are_down('localhost', self.HTTP_PORTS)
372             port.start_http_server()
373
374             # We sleep in between alternating runs to ensure that this
375             # test handles both back-to-back starts and stops and
376             # starts and stops separated by a delay.
377             if i % 2:
378                 time.sleep(0.1)
379
380             self.assert_servers_are_up('localhost', self.HTTP_PORTS)
381             port.stop_http_server()
382             if i % 2:
383                 time.sleep(0.1)
384
385             i += 1
386
387     def test_get_crash_log(self):
388         port = self.make_port()
389         self.assertEqual(port._get_crash_log(None, None, None, None, newer_than=None),
390            (None,
391             'crash log for <unknown process name> (pid <unknown>):\n'
392             'STDOUT: <empty>\n'
393             'STDERR: <empty>\n'))
394
395         self.assertEqual(port._get_crash_log('foo', 1234, 'out bar\nout baz', 'err bar\nerr baz\n', newer_than=None),
396             ('err bar\nerr baz\n',
397              'crash log for foo (pid 1234):\n'
398              'STDOUT: out bar\n'
399              'STDOUT: out baz\n'
400              'STDERR: err bar\n'
401              'STDERR: err baz\n'))
402
403         self.assertEqual(port._get_crash_log('foo', 1234, 'foo\xa6bar', 'foo\xa6bar', newer_than=None),
404             ('foo\xa6bar',
405              u'crash log for foo (pid 1234):\n'
406              u'STDOUT: foo\ufffdbar\n'
407              u'STDERR: foo\ufffdbar\n'))
408
409         self.assertEqual(port._get_crash_log('foo', 1234, 'foo\xa6bar', 'foo\xa6bar', newer_than=1.0),
410             ('foo\xa6bar',
411              u'crash log for foo (pid 1234):\n'
412              u'STDOUT: foo\ufffdbar\n'
413              u'STDERR: foo\ufffdbar\n'))
414
415     def assert_build_path(self, options, dirs, expected_path):
416         port = self.make_port(options=options)
417         for directory in dirs:
418             port.host.filesystem.maybe_make_directory(directory)
419         self.assertEqual(port._build_path(), expected_path)
420
421     def test_expectations_ordering(self):
422         port = self.make_port()
423         for path in port.expectations_files():
424             port._filesystem.write_text_file(path, '')
425         ordered_dict = port.expectations_dict()
426         self.assertEqual(port.path_to_test_expectations_file(), ordered_dict.keys()[0])
427
428         options = MockOptions(additional_expectations=['/tmp/foo', '/tmp/bar'])
429         port = self.make_port(options=options)
430         for path in port.expectations_files():
431             port._filesystem.write_text_file(path, '')
432         port._filesystem.write_text_file('/tmp/foo', 'foo')
433         port._filesystem.write_text_file('/tmp/bar', 'bar')
434         ordered_dict = port.expectations_dict()
435         self.assertEqual(ordered_dict.keys()[-2:], options.additional_expectations)  # pylint: disable-msg=E1101
436         self.assertEqual(ordered_dict.values()[-2:], ['foo', 'bar'])
437
438     def test_path_to_test_expectations_file(self):
439         port = TestWebKitPort()
440         port._options = MockOptions(webkit_test_runner=False)
441         self.assertEqual(port.path_to_test_expectations_file(), '/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations')
442
443         port = TestWebKitPort()
444         port._options = MockOptions(webkit_test_runner=True)
445         self.assertEqual(port.path_to_test_expectations_file(), '/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations')
446
447         port = TestWebKitPort()
448         port.host.filesystem.files['/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations'] = 'some content'
449         port._options = MockOptions(webkit_test_runner=False)
450         self.assertEqual(port.path_to_test_expectations_file(), '/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations')
451
452     def test_skipped_directories_for_symbols(self):
453         # This first test confirms that the commonly found symbols result in the expected skipped directories.
454         symbols_string = " ".join(["GraphicsLayer", "WebCoreHas3DRendering", "isXHTMLMPDocument", "fooSymbol"])
455         expected_directories = set([
456             "mathml",  # Requires MathMLElement
457             "fast/canvas/webgl",  # Requires WebGLShader
458             "compositing/webgl",  # Requires WebGLShader
459             "http/tests/canvas/webgl",  # Requires WebGLShader
460             "mhtml",  # Requires MHTMLArchive
461             "fast/css/variables",  # Requires CSS Variables
462             "inspector/styles/variables",  # Requires CSS Variables
463         ])
464
465         result_directories = set(TestWebKitPort(symbols_string, None)._skipped_tests_for_unsupported_features(test_list=['mathml/foo.html']))
466         self.assertEqual(result_directories, expected_directories)
467
468         # Test that the nm string parsing actually works:
469         symbols_string = """
470 000000000124f498 s __ZZN7WebCore13GraphicsLayer12replaceChildEPS0_S1_E19__PRETTY_FUNCTION__
471 000000000124f500 s __ZZN7WebCore13GraphicsLayer13addChildAboveEPS0_S1_E19__PRETTY_FUNCTION__
472 000000000124f670 s __ZZN7WebCore13GraphicsLayer13addChildBelowEPS0_S1_E19__PRETTY_FUNCTION__
473 """
474         # Note 'compositing' is not in the list of skipped directories (hence the parsing of GraphicsLayer worked):
475         expected_directories = set(['mathml', 'transforms/3d', 'compositing/webgl', 'fast/canvas/webgl', 'animations/3d', 'mhtml', 'http/tests/canvas/webgl', 'fast/css/variables', 'inspector/styles/variables'])
476         result_directories = set(TestWebKitPort(symbols_string, None)._skipped_tests_for_unsupported_features(test_list=['mathml/foo.html']))
477         self.assertEqual(result_directories, expected_directories)
478
479     def test_skipped_directories_for_features(self):
480         supported_features = ["Accelerated Compositing", "Foo Feature"]
481         expected_directories = set(["animations/3d", "transforms/3d"])
482         port = TestWebKitPort(None, supported_features)
483         port._runtime_feature_list = lambda: supported_features
484         result_directories = set(port._skipped_tests_for_unsupported_features(test_list=["animations/3d/foo.html"]))
485         self.assertEqual(result_directories, expected_directories)
486
487     def test_skipped_directories_for_features_no_matching_tests_in_test_list(self):
488         supported_features = ["Accelerated Compositing", "Foo Feature"]
489         expected_directories = set([])
490         result_directories = set(TestWebKitPort(None, supported_features)._skipped_tests_for_unsupported_features(test_list=['foo.html']))
491         self.assertEqual(result_directories, expected_directories)
492
493     def test_skipped_tests_for_unsupported_features_empty_test_list(self):
494         supported_features = ["Accelerated Compositing", "Foo Feature"]
495         expected_directories = set([])
496         result_directories = set(TestWebKitPort(None, supported_features)._skipped_tests_for_unsupported_features(test_list=None))
497         self.assertEqual(result_directories, expected_directories)
498
499     def test_skipped_layout_tests(self):
500         self.assertEqual(TestWebKitPort(None, None).skipped_layout_tests(test_list=[]), set(['media']))
501
502     def test_expectations_files(self):
503         port = TestWebKitPort()
504
505         def platform_dirs(port):
506             return [port.host.filesystem.basename(port.host.filesystem.dirname(f)) for f in port.expectations_files()]
507
508         self.assertEqual(platform_dirs(port), ['testwebkitport'])
509
510         port._name = "testwebkitport-version"
511         self.assertEqual(platform_dirs(port), ['testwebkitport', 'testwebkitport-version'])
512
513         port._options = MockOptions(webkit_test_runner=True)
514         self.assertEqual(platform_dirs(port), ['testwebkitport', 'testwebkitport-version', 'testwebkitport-wk2', 'wk2'])
515
516         port._options = MockOptions(additional_platform_directory=["internal-testwebkitport"])
517         self.assertEqual(platform_dirs(port), ['testwebkitport', 'testwebkitport-version', 'internal-testwebkitport'])
518
519     def test_root_option(self):
520         port = TestWebKitPort()
521         port._options = MockOptions(root='/foo')
522         self.assertEqual(port._path_to_driver(), "/foo/DumpRenderTree")
523
524     def test_test_expectations(self):
525         # Check that we read the expectations file
526         host = MockSystemHost()
527         host.filesystem.write_text_file('/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations',
528             'BUG_TESTEXPECTATIONS SKIP : fast/html/article-element.html = FAIL\n')
529         port = TestWebKitPort(host=host)
530         self.assertEqual(''.join(port.expectations_dict().values()), 'BUG_TESTEXPECTATIONS SKIP : fast/html/article-element.html = FAIL\n')
531
532     def test_build_driver(self):
533         output = OutputCapture()
534         port = TestWebKitPort()
535         # Delay setting _executive to avoid logging during construction
536         port._executive = MockExecutive(should_log=True)
537         port._options = MockOptions(configuration="Release")  # This should not be necessary, but I think TestWebKitPort is actually reading from disk (and thus detects the current configuration).
538         expected_logs = "MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}\n"
539         self.assertTrue(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
540
541         # Make sure when passed --webkit-test-runner we build the right tool.
542         port._options = MockOptions(webkit_test_runner=True, configuration="Release")
543         expected_logs = "MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}\nMOCK run_command: ['Tools/Scripts/build-webkittestrunner', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}\n"
544         self.assertTrue(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
545
546         # Make sure we show the build log when --verbose is passed, which we simulate by setting the logging level to DEBUG.
547         output.set_log_level(logging.DEBUG)
548         port._options = MockOptions(configuration="Release")
549         expected_logs = """MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}
550 Output of ['Tools/Scripts/build-dumprendertree', '--release']:
551 MOCK output of child process
552 """
553         self.assertTrue(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
554         output.set_log_level(logging.INFO)
555
556         # Make sure that failure to build returns False.
557         port._executive = MockExecutive(should_log=True, should_throw=True)
558         # Because WK2 currently has to build both webkittestrunner and DRT, if DRT fails, that's the only one it tries.
559         expected_logs = """MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}
560 MOCK ScriptError
561
562 MOCK output of child process
563 """
564         self.assertFalse(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
565
566     def _assert_config_file_for_platform(self, port, platform, config_file):
567         self.assertEqual(port._apache_config_file_name_for_platform(platform), config_file)
568
569     def test_linux_distro_detection(self):
570         port = TestWebKitPort()
571         self.assertFalse(port._is_redhat_based())
572         self.assertFalse(port._is_debian_based())
573
574         port._filesystem = MockFileSystem({'/etc/redhat-release': ''})
575         self.assertTrue(port._is_redhat_based())
576         self.assertFalse(port._is_debian_based())
577
578         port._filesystem = MockFileSystem({'/etc/debian_version': ''})
579         self.assertFalse(port._is_redhat_based())
580         self.assertTrue(port._is_debian_based())
581
582     def test_apache_config_file_name_for_platform(self):
583         port = TestWebKitPort()
584         self._assert_config_file_for_platform(port, 'cygwin', 'cygwin-httpd.conf')
585
586         self._assert_config_file_for_platform(port, 'linux2', 'apache2-httpd.conf')
587         self._assert_config_file_for_platform(port, 'linux3', 'apache2-httpd.conf')
588
589         port._is_redhat_based = lambda: True
590         self._assert_config_file_for_platform(port, 'linux2', 'fedora-httpd.conf')
591
592         port = TestWebKitPort()
593         port._is_debian_based = lambda: True
594         self._assert_config_file_for_platform(port, 'linux2', 'apache2-debian-httpd.conf')
595
596         self._assert_config_file_for_platform(port, 'mac', 'apache2-httpd.conf')
597         self._assert_config_file_for_platform(port, 'win32', 'apache2-httpd.conf')  # win32 isn't a supported sys.platform.  AppleWin/WinCairo/WinCE ports all use cygwin.
598         self._assert_config_file_for_platform(port, 'barf', 'apache2-httpd.conf')
599
600     def test_path_to_apache_config_file(self):
601         port = TestWebKitPort()
602
603         saved_environ = os.environ.copy()
604         try:
605             os.environ['WEBKIT_HTTP_SERVER_CONF_PATH'] = '/path/to/httpd.conf'
606             self.assertRaises(IOError, port._path_to_apache_config_file)
607             port._filesystem.write_text_file('/existing/httpd.conf', 'Hello, world!')
608             os.environ['WEBKIT_HTTP_SERVER_CONF_PATH'] = '/existing/httpd.conf'
609             self.assertEqual(port._path_to_apache_config_file(), '/existing/httpd.conf')
610         finally:
611             os.environ = saved_environ.copy()
612
613         # Mock out _apache_config_file_name_for_platform to ignore the passed sys.platform value.
614         port._apache_config_file_name_for_platform = lambda platform: 'httpd.conf'
615         self.assertEqual(port._path_to_apache_config_file(), '/mock-checkout/LayoutTests/http/conf/httpd.conf')
616
617         # Check that even if we mock out _apache_config_file_name, the environment variable takes precedence.
618         saved_environ = os.environ.copy()
619         try:
620             os.environ['WEBKIT_HTTP_SERVER_CONF_PATH'] = '/existing/httpd.conf'
621             self.assertEqual(port._path_to_apache_config_file(), '/existing/httpd.conf')
622         finally:
623             os.environ = saved_environ.copy()
624
625     def test_check_build(self):
626         port = self.make_port(options=MockOptions(build=True))
627         self.build_called = False
628
629         def build_driver_called():
630             self.build_called = True
631             return True
632
633         port._build_driver = build_driver_called
634         port.check_build(False)
635         self.assertTrue(self.build_called)
636
637         port = self.make_port(options=MockOptions(root='/tmp', build=True))
638         self.build_called = False
639         port._build_driver = build_driver_called
640         port.check_build(False)
641         self.assertFalse(self.build_called, None)
642
643         port = self.make_port(options=MockOptions(build=False))
644         self.build_called = False
645         port._build_driver = build_driver_called
646         port.check_build(False)
647         self.assertFalse(self.build_called, None)
648
649     def test_additional_platform_directory(self):
650         port = self.make_port(options=MockOptions(additional_platform_directory=['/tmp/foo']))
651         self.assertEqual(port.baseline_search_path()[0], '/tmp/foo')