67bc5d1b625cdf1b8800a59d3f31952be5be30c3
[WebKit-https.git] / Tools / Scripts / webkitpy / port / ios_device.py
1 # Copyright (C) 2014-2017 Apple 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
5 # are met:
6 # 1.  Redistributions of source code must retain the above copyright
7 #     notice, this list of conditions and the following disclaimer.
8 # 2.  Redistributions in binary form must reproduce the above copyright
9 #     notice, this list of conditions and the following disclaimer in the
10 #     documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23 import logging
24
25 from webkitpy.common.memoized import memoized
26 from webkitpy.common.system.crashlogs import CrashLogs
27 from webkitpy.common.version import Version
28 from webkitpy.common.version_name_map import VersionNameMap
29 from webkitpy.port.config import apple_additions
30 from webkitpy.port.ios import IOSPort
31
32 _log = logging.getLogger(__name__)
33
34
35 class IOSDevicePort(IOSPort):
36     port_name = 'ios-device'
37
38     ARCHITECTURES = ['armv7', 'armv7s', 'arm64']
39     DEFAULT_ARCHITECTURE = 'arm64'
40     VERSION_FALLBACK_ORDER = ['ios-7', 'ios-8', 'ios-9', 'ios-10']
41     SDK = apple_additions().get_sdk('iphoneos') if apple_additions() else 'iphoneos'
42     NO_ON_DEVICE_TESTING = 'On-device testing is not supported on this machine'
43
44     @memoized
45     def default_child_processes(self):
46         if apple_additions():
47             return apple_additions().ios_device_default_child_processes(self)
48         return 1
49
50     def _device_for_worker_number_map(self):
51         if not apple_additions():
52             raise RuntimeError(self.NO_ON_DEVICE_TESTING)
53         return apple_additions().ios_device_for_worker_number_map(self)
54
55     def _driver_class(self):
56         if apple_additions():
57             return apple_additions().ios_device_driver()
58         return super(IOSDevicePort, self)._driver_class()
59
60     @classmethod
61     def determine_full_port_name(cls, host, options, port_name):
62         if port_name == cls.port_name:
63             iphoneos_sdk_version = host.platform.xcode_sdk_version(cls.SDK)
64             if not iphoneos_sdk_version:
65                 raise Exception("Please install the iOS SDK.")
66             port_name = port_name + '-' + str(iphoneos_sdk_version.major)
67         return port_name
68
69     def path_to_crash_logs(self):
70         if not apple_additions():
71             raise RuntimeError(self.NO_ON_DEVICE_TESTING)
72         return apple_additions().ios_crash_log_path()
73
74     def _look_for_all_crash_logs_in_log_dir(self, newer_than):
75         log_list = {}
76         for device in self._device_for_worker_number_map():
77             crash_log = CrashLogs(device, self.path_to_crash_logs(), crash_logs_to_skip=self._crash_logs_to_skip_for_host.get(device, []))
78             log_list.update(crash_log.find_all_logs(include_errors=True, newer_than=newer_than))
79         return log_list
80
81     def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=None, sleep_fn=None, wait_for_log=True, target_host=None):
82         if target_host:
83             return super(IOSDevicePort, self)._get_crash_log(name, pid, stdout, stderr, newer_than, time_fn=time_fn, sleep_fn=sleep_fn, wait_for_log=wait_for_log, target_host=target_host)
84
85         # We need to search every device since one was not specified.
86         for device in self._device_for_worker_number_map():
87             stderr_out, crashlog = super(IOSDevicePort, self)._get_crash_log(name, pid, stdout, stderr, newer_than, time_fn=time_fn, sleep_fn=sleep_fn, wait_for_log=False, target_host=device)
88             if crashlog:
89                 return (stderr, crashlog)
90         return (stderr, None)
91
92     @memoized
93     def ios_version(self):
94         if self.get_option('version'):
95             return Version.from_string(self.get_option('version'))
96
97         if not apple_additions():
98             raise RuntimeError(self.NO_ON_DEVICE_TESTING)
99
100         if not self._device_for_worker_number_map():
101             raise RuntimeError('No devices are available')
102         version = None
103         for device in self._device_for_worker_number_map():
104             if not version:
105                 version = device.platform.os_version
106             else:
107                 if device.platform.os_version != version:
108                     raise RuntimeError('Multiple connected devices have different iOS versions')
109         return version
110
111     # FIXME: These need device implementations <rdar://problem/30497991>.
112     def check_for_leaks(self, process_name, process_pid):
113         pass
114
115     # Despite their names, these flags do not actually get passed all the way down to webkit-build.
116     def _build_driver_flags(self):
117         return ['--sdk', self.SDK] + (['ARCHS=%s' % self.architecture()] if self.architecture() else [])
118
119     def operating_system(self):
120         return 'ios-device'
121
122     def _create_devices(self, device_class):
123         if not apple_additions():
124             raise RuntimeError(self.NO_ON_DEVICE_TESTING)
125         if not self._device_for_worker_number_map():
126             raise RuntimeError('No devices are available for testing')
127
128         if self.default_child_processes() < self.child_processes():
129             raise RuntimeError('Not enought connected devices for {} processes'.format(self.child_processes()))
130
131     def clean_up_test_run(self):
132         super(IOSDevicePort, self).clean_up_test_run()
133         apple_additions().ios_device_clean_up_test_run(self, self._path_to_driver(), self._build_path())