cd8aeadebf7bddb6cc110bc8c123555d14d9469e
[WebKit-https.git] / Tools / Scripts / webkitpy / port / mac.py
1 # Copyright (C) 2011 Google Inc. All rights reserved.
2 # Copyright (C) 2012, 2013, 2016 Apple Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 #     * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 #     * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 #     * Neither the Google name nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 import logging
31 import os
32 import time
33 import re
34
35 from webkitpy.common.memoized import memoized
36 from webkitpy.common.system.executive import ScriptError
37 from webkitpy.port.config import apple_additions
38 from webkitpy.port.darwin import DarwinPort
39
40 _log = logging.getLogger(__name__)
41
42
43 class MacPort(DarwinPort):
44     port_name = "mac"
45
46     VERSION_FALLBACK_ORDER = ['mac-snowleopard', 'mac-lion', 'mac-mountainlion', 'mac-mavericks', 'mac-yosemite', 'mac-elcapitan', 'mac-sierra', 'mac-highsierra']
47     SDK = 'macosx'
48
49     ARCHITECTURES = ['x86_64', 'x86']
50
51     DEFAULT_ARCHITECTURE = 'x86_64'
52
53     def __init__(self, host, port_name, **kwargs):
54         DarwinPort.__init__(self, host, port_name, **kwargs)
55         self._os_version = port_name.split('-')[1] if port_name.split('-') > 1 else self.host.platform.os_version
56
57     def _build_driver_flags(self):
58         return ['ARCHS=i386'] if self.architecture() == 'x86' else []
59
60     def _apple_additions_path(self, name):
61         if name == 'wk2':
62             return None
63         split_name = name.split('-')
64         os_index = -1
65         if split_name[-1] == 'wk1' or split_name[-1] == 'wk2':
66             os_index = -2
67         if split_name[os_index] != split_name[0]:
68             os_name = apple_additions().mac_os_name(split_name[os_index])
69             if not os_name:
70                 return None
71             split_name[os_index] = os_name
72         name = '-'.join(split_name)
73         return self._filesystem.join(apple_additions().layout_tests_path(), name)
74
75     @memoized
76     def default_baseline_search_path(self):
77         wk_string = 'wk1'
78         if self.get_option('webkit_test_runner'):
79             wk_string = 'wk2'
80         fallback_names = [
81             '{}-{}-{}'.format(self.port_name, self._os_version, wk_string),
82             '{}-{}'.format(self.port_name, self._os_version),
83             '{}-{}'.format(self.port_name, wk_string),
84             self.port_name,
85         ]
86         if self.get_option('webkit_test_runner'):
87             fallback_names.append('wk2')
88
89         webkit_expectations = map(self._webkit_baseline_path, fallback_names)
90         if apple_additions() and getattr(apple_additions(), "layout_tests_path", None):
91             apple_expectations = map(self._apple_additions_path, fallback_names)
92             result = []
93             for i in xrange(len(webkit_expectations)):
94                 if apple_expectations[i]:
95                     result.append(apple_expectations[i])
96                 result.append(webkit_expectations[i])
97             return result
98         return webkit_expectations
99
100     def configuration_specifier_macros(self):
101         return {
102             "highsierra+": ["highsierra", "future"],
103             "sierra+": ["sierra", "highsierra", "future"],
104             "elcapitan+": ["elcapitan", "sierra", "highsierra", "future"],
105             "yosemite+": ["yosemite", "elcapitan", "sierra", "highsierra", "future"],
106         }
107
108     def setup_environ_for_server(self, server_name=None):
109         env = super(MacPort, self).setup_environ_for_server(server_name)
110         if server_name == self.driver_name():
111             if self.get_option('leaks'):
112                 env['MallocStackLogging'] = '1'
113                 env['__XPC_MallocStackLogging'] = '1'
114                 env['MallocScribble'] = '1'
115                 env['__XPC_MallocScribble'] = '1'
116             if self.get_option('guard_malloc'):
117                 self._append_value_colon_separated(env, 'DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
118                 self._append_value_colon_separated(env, '__XPC_DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
119             self._append_value_colon_separated(env, 'DYLD_INSERT_LIBRARIES', self._build_path("libWebCoreTestShim.dylib"))
120         env['XML_CATALOG_FILES'] = ''  # work around missing /etc/catalog <rdar://problem/4292995>
121         return env
122
123     def _clear_global_caches_and_temporary_files(self):
124         self._filesystem.rmtree(os.path.expanduser('~/Library/' + self.driver_name()))
125         self._filesystem.rmtree(os.path.expanduser('~/Library/Application Support/' + self.driver_name()))
126         self._filesystem.rmtree(os.path.expanduser('~/Library/Caches/' + self.driver_name()))
127         self._filesystem.rmtree(os.path.expanduser('~/Library/WebKit/' + self.driver_name()))
128
129     def _path_to_user_cache_directory(self, suffix=None):
130         DIRHELPER_USER_DIR_SUFFIX = 'DIRHELPER_USER_DIR_SUFFIX'
131         CS_DARWIN_USER_CACHE_DIR = 65538
132
133         # The environment variable DIRHELPER_USER_DIR_SUFFIX is only honored on systems with
134         # System Integrity Protection disabled or with an Apple-Internal OS. To make this code
135         # work for all system configurations we compute the path with respect to the suffix
136         # by hand and temporarily unset the environment variable DIRHELPER_USER_DIR_SUFFIX (if set)
137         # to avoid it influencing confstr() on systems that honor DIRHELPER_USER_DIR_SUFFIX.
138         saved_suffix = None
139         if DIRHELPER_USER_DIR_SUFFIX in os.environ:
140             saved_suffix = os.environ[DIRHELPER_USER_DIR_SUFFIX]
141             del os.environ[DIRHELPER_USER_DIR_SUFFIX]
142         result = os.path.join(os.confstr(CS_DARWIN_USER_CACHE_DIR), suffix or '')
143         if saved_suffix is not None:
144             os.environ[DIRHELPER_USER_DIR_SUFFIX] = saved_suffix
145         return result
146
147     def operating_system(self):
148         return 'mac'
149
150     # Belongs on a Platform object.
151     def is_mavericks(self):
152         return self._version == 'mavericks'
153
154     def default_child_processes(self):
155         default_count = super(MacPort, self).default_child_processes()
156
157         # FIXME: https://bugs.webkit.org/show_bug.cgi?id=95906  With too many WebProcess WK2 tests get stuck in resource contention.
158         # To alleviate the issue reduce the number of running processes
159         # Anecdotal evidence suggests that a 4 core/8 core logical machine may run into this, but that a 2 core/4 core logical machine does not.
160         should_throttle_for_wk2 = self.get_option('webkit_test_runner') and default_count > 4
161         # We also want to throttle for leaks bots.
162         if should_throttle_for_wk2 or self.get_option('leaks'):
163             default_count = int(.75 * default_count)
164
165         if should_throttle_for_wk2 and self.get_option('guard_malloc'):
166             # Some 12 core Macs get a lot of tests time out when running 18 WebKitTestRunner processes (it's not clear what this depends on).
167             # <rdar://problem/25750302>
168             default_count = min(default_count, 12)
169
170         # Make sure we have enough ram to support that many instances:
171         total_memory = self.host.platform.total_bytes_memory()
172         if total_memory:
173             bytes_per_drt = 256 * 1024 * 1024  # Assume each DRT needs 256MB to run.
174             overhead = 2048 * 1024 * 1024  # Assume we need 2GB free for the O/S
175             supportable_instances = max((total_memory - overhead) / bytes_per_drt, 1)  # Always use one process, even if we don't have space for it.
176             if supportable_instances < default_count:
177                 _log.warning("This machine could support %s child processes, but only has enough memory for %s." % (default_count, supportable_instances))
178         else:
179             _log.warning("Cannot determine available memory for child processes, using default child process count of %s." % default_count)
180             supportable_instances = default_count
181         return min(supportable_instances, default_count)
182
183     def _build_java_test_support(self):
184         # FIXME: This is unused. Remove.
185         java_tests_path = self._filesystem.join(self.layout_tests_dir(), "java")
186         build_java = [self.make_command(), "-C", java_tests_path]
187         if self._executive.run_command(build_java, return_exit_code=True):  # Paths are absolute, so we don't need to set a cwd.
188             _log.error("Failed to build Java support files: %s" % build_java)
189             return False
190         return True
191
192     def _check_port_build(self):
193         return not self.get_option('java') or self._build_java_test_support()
194
195     def start_helper(self, pixel_tests=False):
196         helper_path = self._path_to_helper()
197         if not helper_path:
198             _log.error("No path to LayoutTestHelper binary")
199             return False
200         _log.debug("Starting layout helper %s" % helper_path)
201         arguments = [helper_path, '--install-color-profile']
202         self._helper = self._executive.popen(arguments,
203             stdin=self._executive.PIPE, stdout=self._executive.PIPE, stderr=None)
204         is_ready = self._helper.stdout.readline()
205         if not is_ready.startswith('ready'):
206             _log.error("LayoutTestHelper could not start")
207             return False
208         return True
209
210     def reset_preferences(self):
211         _log.debug("Resetting persistent preferences")
212
213         for domain in ["DumpRenderTree", "WebKitTestRunner"]:
214             try:
215                 self._executive.run_command(["defaults", "delete", domain])
216             except ScriptError, e:
217                 # 'defaults' returns 1 if the domain did not exist
218                 if e.exit_code != 1:
219                     raise e
220
221     def stop_helper(self):
222         if self._helper:
223             _log.debug("Stopping LayoutTestHelper")
224             try:
225                 self._helper.stdin.write("x\n")
226                 self._helper.stdin.close()
227                 self._helper.wait()
228             except IOError, e:
229                 _log.debug("IOError raised while stopping helper: %s" % str(e))
230             self._helper = None
231
232     def logging_patterns_to_strip(self):
233         # FIXME: Remove this after <rdar://problem/15605007> is fixed
234         return [(re.compile('(AVF|GVA) info:.*\n'), '')]
235
236     def stderr_patterns_to_strip(self):
237         worthless_patterns = []
238         worthless_patterns.append((re.compile('.*(Fig|fig|itemasync|vt|mv_|PullParamSetSPS|ccrp_|client).* signalled err=.*\n'), ''))
239         worthless_patterns.append((re.compile('.*<<<< FigFilePlayer >>>>.*\n'), ''))
240         worthless_patterns.append((re.compile('.*<<<< FigFile >>>>.*\n'), ''))
241         worthless_patterns.append((re.compile('.*<<<< FAQ >>>>.*\n'), ''))
242         worthless_patterns.append((re.compile('.*<<<< MediaValidator >>>>.*\n'), ''))
243         worthless_patterns.append((re.compile('.*<<<< VMC >>>>.*\n'), ''))
244         worthless_patterns.append((re.compile('.*<<< FFR_Common >>>.*\n'), ''))
245         return worthless_patterns