blob: 9868210ea2f6e701175f7c95ee62cb66010fc9b4 [file] [log] [blame]
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +00001# 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
31import errno
32import logging
33import os
34import socket
35import sys
36import time
Ben Murdoch7757ec22013-07-23 11:17:36 +010037import webkitpy.thirdparty.unittest2 as unittest
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000038
39from webkitpy.common.system.executive_mock import MockExecutive
40from webkitpy.common.system.filesystem_mock import MockFileSystem
41from webkitpy.common.system.outputcapture import OutputCapture
42from webkitpy.common.system.systemhost_mock import MockSystemHost
43from webkitpy.layout_tests.port.base import Port
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000044from webkitpy.layout_tests.port.server_process_mock import MockServerProcess
45from webkitpy.layout_tests.servers import http_server_base
46from webkitpy.tool.mocktool import MockOptions
47
48
49# FIXME: get rid of this fixture
50class TestWebKitPort(Port):
51 port_name = "testwebkitport"
52
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000053 def __init__(self, port_name=None, symbols_string=None,
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000054 expectations_file=None, skips_file=None, host=None, config=None,
55 **kwargs):
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000056 port_name = port_name or TestWebKitPort.port_name
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000057 self.symbols_string = symbols_string # Passing "" disables all staticly-detectable features.
58 host = host or MockSystemHost()
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000059 super(TestWebKitPort, self).__init__(host, port_name=port_name, **kwargs)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000060
61 def all_test_configurations(self):
62 return [self.test_configuration()]
63
64 def _symbols_string(self):
65 return self.symbols_string
66
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000067 def _tests_for_disabled_features(self):
68 return ["accessibility", ]
69
70
71class PortTestCase(unittest.TestCase):
72 """Tests that all Port implementations must pass."""
73 HTTP_PORTS = (8000, 8080, 8443)
74 WEBSOCKET_PORTS = (8880,)
75
76 # Subclasses override this to point to their Port subclass.
77 os_name = None
78 os_version = None
79 port_maker = TestWebKitPort
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000080 port_name = None
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000081
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000082 def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=None, **kwargs):
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000083 host = host or MockSystemHost(os_name=(os_name or self.os_name), os_version=(os_version or self.os_version))
84 options = options or MockOptions(configuration='Release')
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000085 port_name = port_name or self.port_name
86 port_name = self.port_maker.determine_full_port_name(host, options, port_name)
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000087 port = self.port_maker(host, port_name, options=options, **kwargs)
88 port._config.build_directory = lambda configuration: '/mock-build'
89 return port
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000090
Ben Murdoch83750172013-07-24 10:36:59 +010091 def make_wdiff_available(self, port):
92 port._wdiff_available = True
93
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000094 def test_default_max_locked_shards(self):
95 port = self.make_port()
96 port.default_child_processes = lambda: 16
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000097 self.assertEqual(port.default_max_locked_shards(), 1)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000098 port.default_child_processes = lambda: 2
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000099 self.assertEqual(port.default_max_locked_shards(), 1)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000100
101 def test_default_timeout_ms(self):
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100102 self.assertEqual(self.make_port(options=MockOptions(configuration='Release')).default_timeout_ms(), 6000)
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100103 self.assertEqual(self.make_port(options=MockOptions(configuration='Debug')).default_timeout_ms(), 36000)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000104
105 def test_default_pixel_tests(self):
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100106 self.assertEqual(self.make_port().default_pixel_tests(), True)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000107
108 def test_driver_cmd_line(self):
109 port = self.make_port()
110 self.assertTrue(len(port.driver_cmd_line()))
111
112 options = MockOptions(additional_drt_flag=['--foo=bar', '--foo=baz'])
113 port = self.make_port(options=options)
114 cmd_line = port.driver_cmd_line()
115 self.assertTrue('--foo=bar' in cmd_line)
116 self.assertTrue('--foo=baz' in cmd_line)
117
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000118 def test_uses_apache(self):
119 self.assertTrue(self.make_port()._uses_apache())
120
121 def assert_servers_are_down(self, host, ports):
122 for port in ports:
123 try:
124 test_socket = socket.socket()
125 test_socket.connect((host, port))
126 self.fail()
127 except IOError, e:
128 self.assertTrue(e.errno in (errno.ECONNREFUSED, errno.ECONNRESET))
129 finally:
130 test_socket.close()
131
132 def assert_servers_are_up(self, host, ports):
133 for port in ports:
134 try:
135 test_socket = socket.socket()
136 test_socket.connect((host, port))
137 except IOError, e:
138 self.fail('failed to connect to %s:%d' % (host, port))
139 finally:
140 test_socket.close()
141
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000142 def test_diff_image__missing_both(self):
143 port = self.make_port()
Ben Murdoch591b9582013-07-10 11:41:44 +0100144 self.assertEqual(port.diff_image(None, None), (None, None))
145 self.assertEqual(port.diff_image(None, ''), (None, None))
146 self.assertEqual(port.diff_image('', None), (None, None))
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000147
Ben Murdoch591b9582013-07-10 11:41:44 +0100148 self.assertEqual(port.diff_image('', ''), (None, None))
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000149
150 def test_diff_image__missing_actual(self):
151 port = self.make_port()
Ben Murdoch591b9582013-07-10 11:41:44 +0100152 self.assertEqual(port.diff_image(None, 'foo'), ('foo', None))
153 self.assertEqual(port.diff_image('', 'foo'), ('foo', None))
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000154
155 def test_diff_image__missing_expected(self):
156 port = self.make_port()
Ben Murdoch591b9582013-07-10 11:41:44 +0100157 self.assertEqual(port.diff_image('foo', None), ('foo', None))
158 self.assertEqual(port.diff_image('foo', ''), ('foo', None))
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000159
160 def test_diff_image(self):
161 port = self.make_port()
162 self.proc = None
163
164 def make_proc(port, nm, cmd, env):
165 self.proc = MockServerProcess(port, nm, cmd, env, lines=['diff: 100% failed\n', 'diff: 100% failed\n'])
166 return self.proc
167
168 port._server_process_constructor = make_proc
169 port.setup_test_run()
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000170 self.assertEqual(port.diff_image('foo', 'bar'), ('', 100.0, None))
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000171
172 port.clean_up_test_run()
173 self.assertTrue(self.proc.stopped)
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000174 self.assertEqual(port._image_differ, None)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000175
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000176 def test_check_wdiff(self):
177 port = self.make_port()
178 port.check_wdiff()
179
Ben Murdoch83750172013-07-24 10:36:59 +0100180 def test_wdiff_text_fails(self):
181 host = MockSystemHost(os_name=self.os_name, os_version=self.os_version)
182 host.executive = MockExecutive(should_throw=True)
183 port = self.make_port(host=host)
184 port._executive = host.executive # AndroidPortTest.make_port sets its own executive, so reset that as well.
185
186 # This should raise a ScriptError that gets caught and turned into the
187 # error text, and also mark wdiff as not available.
188 self.make_wdiff_available(port)
189 self.assertTrue(port.wdiff_available())
190 diff_txt = port.wdiff_text("/tmp/foo.html", "/tmp/bar.html")
191 self.assertEqual(diff_txt, port._wdiff_error_html)
192 self.assertFalse(port.wdiff_available())
193
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000194 def test_test_configuration(self):
195 port = self.make_port()
196 self.assertTrue(port.test_configuration())
197
198 def test_all_test_configurations(self):
199 port = self.make_port()
200 self.assertTrue(len(port.all_test_configurations()) > 0)
201 self.assertTrue(port.test_configuration() in port.all_test_configurations(), "%s not in %s" % (port.test_configuration(), port.all_test_configurations()))
202
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000203 def test_get_crash_log(self):
204 port = self.make_port()
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000205 self.assertEqual(port._get_crash_log(None, None, None, None, newer_than=None),
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000206 (None,
207 'crash log for <unknown process name> (pid <unknown>):\n'
208 'STDOUT: <empty>\n'
209 'STDERR: <empty>\n'))
210
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000211 self.assertEqual(port._get_crash_log('foo', 1234, 'out bar\nout baz', 'err bar\nerr baz\n', newer_than=None),
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000212 ('err bar\nerr baz\n',
213 'crash log for foo (pid 1234):\n'
214 'STDOUT: out bar\n'
215 'STDOUT: out baz\n'
216 'STDERR: err bar\n'
217 'STDERR: err baz\n'))
218
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000219 self.assertEqual(port._get_crash_log('foo', 1234, 'foo\xa6bar', 'foo\xa6bar', newer_than=None),
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000220 ('foo\xa6bar',
221 u'crash log for foo (pid 1234):\n'
222 u'STDOUT: foo\ufffdbar\n'
223 u'STDERR: foo\ufffdbar\n'))
224
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000225 self.assertEqual(port._get_crash_log('foo', 1234, 'foo\xa6bar', 'foo\xa6bar', newer_than=1.0),
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000226 ('foo\xa6bar',
227 u'crash log for foo (pid 1234):\n'
228 u'STDOUT: foo\ufffdbar\n'
229 u'STDERR: foo\ufffdbar\n'))
230
231 def assert_build_path(self, options, dirs, expected_path):
232 port = self.make_port(options=options)
233 for directory in dirs:
234 port.host.filesystem.maybe_make_directory(directory)
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000235 self.assertEqual(port._build_path(), expected_path)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000236
237 def test_expectations_ordering(self):
238 port = self.make_port()
239 for path in port.expectations_files():
240 port._filesystem.write_text_file(path, '')
241 ordered_dict = port.expectations_dict()
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000242 self.assertEqual(port.path_to_generic_test_expectations_file(), ordered_dict.keys()[0])
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000243
244 options = MockOptions(additional_expectations=['/tmp/foo', '/tmp/bar'])
245 port = self.make_port(options=options)
246 for path in port.expectations_files():
247 port._filesystem.write_text_file(path, '')
248 port._filesystem.write_text_file('/tmp/foo', 'foo')
249 port._filesystem.write_text_file('/tmp/bar', 'bar')
250 ordered_dict = port.expectations_dict()
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000251 self.assertEqual(ordered_dict.keys()[-2:], options.additional_expectations) # pylint: disable=E1101
252 self.assertEqual(ordered_dict.values()[-2:], ['foo', 'bar'])
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000253
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000254 def test_skipped_directories_for_symbols(self):
255 # This first test confirms that the commonly found symbols result in the expected skipped directories.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100256 symbols_string = " ".join(["fooSymbol"])
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000257 expected_directories = set([
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100258 "webaudio/codec-tests/mp3",
259 "webaudio/codec-tests/aac",
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000260 ])
261
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100262 result_directories = set(TestWebKitPort(symbols_string=symbols_string)._skipped_tests_for_unsupported_features(test_list=['webaudio/codec-tests/mp3/foo.html']))
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000263 self.assertEqual(result_directories, expected_directories)
264
265 # Test that the nm string parsing actually works:
266 symbols_string = """
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100267000000000124f498 s __ZZN7WebCore13ff_mp3_decoder12replaceChildEPS0_S1_E19__PRETTY_FUNCTION__
268000000000124f500 s __ZZN7WebCore13ff_mp3_decoder13addChildAboveEPS0_S1_E19__PRETTY_FUNCTION__
269000000000124f670 s __ZZN7WebCore13ff_mp3_decoder13addChildBelowEPS0_S1_E19__PRETTY_FUNCTION__
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000270"""
271 # Note 'compositing' is not in the list of skipped directories (hence the parsing of GraphicsLayer worked):
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100272 expected_directories = set([
273 "webaudio/codec-tests/aac",
274 ])
275 result_directories = set(TestWebKitPort(symbols_string=symbols_string)._skipped_tests_for_unsupported_features(test_list=['webaudio/codec-tests/mp3/foo.html']))
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000276 self.assertEqual(result_directories, expected_directories)
277
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000278 def test_expectations_files(self):
279 port = TestWebKitPort()
280
281 def platform_dirs(port):
282 return [port.host.filesystem.basename(port.host.filesystem.dirname(f)) for f in port.expectations_files()]
283
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000284 self.assertEqual(platform_dirs(port), ['LayoutTests', 'testwebkitport'])
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000285
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000286 port = TestWebKitPort(port_name="testwebkitport-version")
287 self.assertEqual(platform_dirs(port), ['LayoutTests', 'testwebkitport', 'testwebkitport-version'])
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000288
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000289 port = TestWebKitPort(port_name="testwebkitport-version",
290 options=MockOptions(additional_platform_directory=["internal-testwebkitport"]))
291 self.assertEqual(platform_dirs(port), ['LayoutTests', 'testwebkitport', 'testwebkitport-version', 'internal-testwebkitport'])
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000292
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000293 def test_test_expectations(self):
294 # Check that we read the expectations file
295 host = MockSystemHost()
296 host.filesystem.write_text_file('/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations',
297 'BUG_TESTEXPECTATIONS SKIP : fast/html/article-element.html = FAIL\n')
298 port = TestWebKitPort(host=host)
299 self.assertEqual(''.join(port.expectations_dict().values()), 'BUG_TESTEXPECTATIONS SKIP : fast/html/article-element.html = FAIL\n')
300
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000301 def _assert_config_file_for_platform(self, port, platform, config_file):
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000302 self.assertEqual(port._apache_config_file_name_for_platform(platform), config_file)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000303
304 def test_linux_distro_detection(self):
305 port = TestWebKitPort()
306 self.assertFalse(port._is_redhat_based())
307 self.assertFalse(port._is_debian_based())
308
309 port._filesystem = MockFileSystem({'/etc/redhat-release': ''})
310 self.assertTrue(port._is_redhat_based())
311 self.assertFalse(port._is_debian_based())
312
313 port._filesystem = MockFileSystem({'/etc/debian_version': ''})
314 self.assertFalse(port._is_redhat_based())
315 self.assertTrue(port._is_debian_based())
316
317 def test_apache_config_file_name_for_platform(self):
318 port = TestWebKitPort()
319 self._assert_config_file_for_platform(port, 'cygwin', 'cygwin-httpd.conf')
320
321 self._assert_config_file_for_platform(port, 'linux2', 'apache2-httpd.conf')
322 self._assert_config_file_for_platform(port, 'linux3', 'apache2-httpd.conf')
323
324 port._is_redhat_based = lambda: True
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000325 port._apache_version = lambda: '2.2'
326 self._assert_config_file_for_platform(port, 'linux2', 'fedora-httpd-2.2.conf')
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000327
328 port = TestWebKitPort()
329 port._is_debian_based = lambda: True
330 self._assert_config_file_for_platform(port, 'linux2', 'apache2-debian-httpd.conf')
331
332 self._assert_config_file_for_platform(port, 'mac', 'apache2-httpd.conf')
333 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.
334 self._assert_config_file_for_platform(port, 'barf', 'apache2-httpd.conf')
335
336 def test_path_to_apache_config_file(self):
337 port = TestWebKitPort()
338
339 saved_environ = os.environ.copy()
340 try:
341 os.environ['WEBKIT_HTTP_SERVER_CONF_PATH'] = '/path/to/httpd.conf'
342 self.assertRaises(IOError, port._path_to_apache_config_file)
343 port._filesystem.write_text_file('/existing/httpd.conf', 'Hello, world!')
344 os.environ['WEBKIT_HTTP_SERVER_CONF_PATH'] = '/existing/httpd.conf'
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000345 self.assertEqual(port._path_to_apache_config_file(), '/existing/httpd.conf')
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000346 finally:
347 os.environ = saved_environ.copy()
348
349 # Mock out _apache_config_file_name_for_platform to ignore the passed sys.platform value.
350 port._apache_config_file_name_for_platform = lambda platform: 'httpd.conf'
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000351 self.assertEqual(port._path_to_apache_config_file(), '/mock-checkout/LayoutTests/http/conf/httpd.conf')
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000352
353 # Check that even if we mock out _apache_config_file_name, the environment variable takes precedence.
354 saved_environ = os.environ.copy()
355 try:
356 os.environ['WEBKIT_HTTP_SERVER_CONF_PATH'] = '/existing/httpd.conf'
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000357 self.assertEqual(port._path_to_apache_config_file(), '/existing/httpd.conf')
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000358 finally:
359 os.environ = saved_environ.copy()
360
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000361 def test_additional_platform_directory(self):
362 port = self.make_port(options=MockOptions(additional_platform_directory=['/tmp/foo']))
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000363 self.assertEqual(port.baseline_search_path()[0], '/tmp/foo')