webkitpy: Add watchOS ports
authorjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Nov 2018 00:29:40 +0000 (00:29 +0000)
committerjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Nov 2018 00:29:40 +0000 (00:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=191974
<rdar://problem/46251051>

Reviewed by Aakash Jain.

* Scripts/webkitpy/port/factory.py:
(PortFactory): Add WatchDevice and WatchSimulator ports.
* Scripts/webkitpy/port/watch.py: Added.
(WatchPort): Base class for watchOS ports.
* Scripts/webkitpy/port/watch_device.py: Added.
(WatchDevicePort): Class for running layout tests on a watchOS device.
* Scripts/webkitpy/port/watch_simulator.py: Added.
(WatchSimulatorPort): Class for running layout tests on a watchOS simulator.
* Scripts/webkitpy/port/watch_simulator_unittest.py: Added.
(WatchSimulatorTest):
* Scripts/webkitpy/port/watch_testcase.py: Added.
(WatchTest):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@238590 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/webkitpy/port/factory.py
Tools/Scripts/webkitpy/port/watch.py [new file with mode: 0644]
Tools/Scripts/webkitpy/port/watch_device.py [new file with mode: 0644]
Tools/Scripts/webkitpy/port/watch_simulator.py [new file with mode: 0644]
Tools/Scripts/webkitpy/port/watch_simulator_unittest.py [new file with mode: 0644]
Tools/Scripts/webkitpy/port/watch_testcase.py [new file with mode: 0644]

index c720144..45cac9b 100644 (file)
@@ -1,3 +1,24 @@
+2018-11-27  Jonathan Bedard  <jbedard@apple.com>
+
+        webkitpy: Add watchOS ports
+        https://bugs.webkit.org/show_bug.cgi?id=191974
+        <rdar://problem/46251051>
+
+        Reviewed by Aakash Jain.
+
+        * Scripts/webkitpy/port/factory.py:
+        (PortFactory): Add WatchDevice and WatchSimulator ports.
+        * Scripts/webkitpy/port/watch.py: Added.
+        (WatchPort): Base class for watchOS ports.
+        * Scripts/webkitpy/port/watch_device.py: Added.
+        (WatchDevicePort): Class for running layout tests on a watchOS device.
+        * Scripts/webkitpy/port/watch_simulator.py: Added.
+        (WatchSimulatorPort): Class for running layout tests on a watchOS simulator.
+        * Scripts/webkitpy/port/watch_simulator_unittest.py: Added.
+        (WatchSimulatorTest):
+        * Scripts/webkitpy/port/watch_testcase.py: Added.
+        (WatchTest):
+
 2018-11-27  Alex Christensen  <achristensen@webkit.org>
 
         Safe browsing warning text needs to be visible on High Sierra
index 1195e80..989f88d 100644 (file)
@@ -1,5 +1,5 @@
 # Copyright (C) 2010 Google Inc. All rights reserved.
-# Copyright (C) 2013 Apple Inc. All rights reserved.
+# Copyright (C) 2013-2018 Apple Inc. All rights reserved.
 # Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
 #
 # Redistribution and use in source and binary forms, with or without
@@ -91,6 +91,8 @@ class PortFactory(object):
         'gtk.GtkPort',
         'ios_simulator.IOSSimulatorPort',
         'ios_device.IOSDevicePort',
+        'watch_simulator.WatchSimulatorPort',
+        'watch_device.WatchDevicePort',
         'jsc_only.JscOnlyPort',
         'mac.MacPort',
         'mock_drt.MockDRTPort',
diff --git a/Tools/Scripts/webkitpy/port/watch.py b/Tools/Scripts/webkitpy/port/watch.py
new file mode 100644 (file)
index 0000000..cfbe875
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (C) 2018 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+from webkitpy.common.memoized import memoized
+from webkitpy.common.version import Version
+from webkitpy.common.version_name_map import VersionNameMap, INTERNAL_TABLE
+from webkitpy.port.config import apple_additions
+from webkitpy.port.device_port import DevicePort
+
+
+_log = logging.getLogger(__name__)
+
+
+class WatchPort(DevicePort):
+    port_name = 'watchos'
+
+    CURRENT_VERSION = Version(5)
+
+    def __init__(self, *args, **kwargs):
+        super(WatchPort, self).__init__(*args, **kwargs)
+
+        if self.get_option('webkit_test_runner', False) == False:
+            raise RuntimeError('DumpRenderTree is not supported on this platform.')
+
+    def driver_name(self):
+        if self.get_option('driver_name'):
+            return self.get_option('driver_name')
+        return 'WebKitTestRunnerApp.app'
+
+    def version_name(self):
+        if self._os_version is None:
+            return None
+        return VersionNameMap.map(self.host.platform).to_name(self._os_version, platform=WatchPort.port_name)
+
+    def test_expectations_file_position(self):
+        return 4
+
+    @memoized
+    def default_baseline_search_path(self):
+        versions_to_fallback = []
+        if self.watchos_version() == self.CURRENT_VERSION:
+            versions_to_fallback = [self.CURRENT_VERSION]
+        elif self.watchos_version():
+            temp_version = Version(self.watchos_version().major)
+            while temp_version.major != self.CURRENT_VERSION.major:
+                versions_to_fallback.append(Version.from_iterable(temp_version))
+                if temp_version < self.CURRENT_VERSION:
+                    temp_version.major += 1
+                else:
+                    temp_version.major -= 1
+
+        expectations = []
+        for version in versions_to_fallback:
+            if apple_additions():
+                apple_name = VersionNameMap.map(self.host.platform).to_name(version, platform=WatchPort.port_name, table=INTERNAL_TABLE)
+                expectations.append(self._apple_baseline_path('{}-{}'.format(self.port_name, apple_name.lower().replace(' ', ''))))
+            expectations.append(self._webkit_baseline_path('{}-{}'.format(self.port_name, version.major)))
+
+        if apple_additions():
+            expectations.append(self._apple_baseline_path(self.port_name))
+        expectations.append(self._webkit_baseline_path(self.port_name))
+
+        for version in versions_to_fallback:
+            apple_name = None
+            if apple_additions():
+                apple_name = VersionNameMap.map(self.host.platform).to_name(version, platform=WatchPort.port_name, table=INTERNAL_TABLE)
+            if apple_name:
+                expectations.append(
+                    self._apple_baseline_path('{}-{}'.format(WatchPort.port_name, apple_name.lower().replace(' ', ''))))
+            expectations.append(self._webkit_baseline_path('{}-{}'.format(WatchPort.port_name, version.major)))
+
+        if apple_additions():
+            expectations.append(self._apple_baseline_path(WatchPort.port_name))
+        expectations.append(self._webkit_baseline_path(WatchPort.port_name))
+
+        expectations.append(self._webkit_baseline_path('wk2'))
+
+        return expectations
+
+    def watchos_version(self):
+        # The implementation of this function differs between on-device and simulator testing.
+        raise NotImplementedError
diff --git a/Tools/Scripts/webkitpy/port/watch_device.py b/Tools/Scripts/webkitpy/port/watch_device.py
new file mode 100644 (file)
index 0000000..1d20230
--- /dev/null
@@ -0,0 +1,124 @@
+# Copyright (C) 2018 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+from webkitpy.common.memoized import memoized
+from webkitpy.common.system.crashlogs import CrashLogs
+from webkitpy.common.version import Version
+from webkitpy.port.config import apple_additions
+from webkitpy.port.watch import WatchPort
+
+_log = logging.getLogger(__name__)
+
+
+class WatchDevicePort(WatchPort):
+    port_name = 'watchos-device'
+
+    ARCHITECTURES = ['armv7k', 'arm64e', 'arm64_32']
+    DEFAULT_ARCHITECTURE = 'armv7k'
+
+    SDK = apple_additions().get_sdk('watchos') if apple_additions() else 'watchos'
+    DEVICE_MANAGER = apple_additions().device_manager() if apple_additions() else None
+    NO_ON_DEVICE_TESTING = 'On-device testing is not supported in this configuration'
+
+    @memoized
+    def default_child_processes(self):
+        if apple_additions():
+            return len(apple_additions().device_for_worker_number_map(self, software_variant='watchOS'))
+        return 1
+
+    def _driver_class(self):
+        if apple_additions():
+            return apple_additions().device_driver()
+        return super(WatchDevicePort, self)._driver_class()
+
+    @classmethod
+    def determine_full_port_name(cls, host, options, port_name):
+        if port_name == cls.port_name:
+            watchos_sdk_version = host.platform.xcode_sdk_version(cls.SDK)
+            if not watchos_sdk_version:
+                raise Exception("Please install the watchOS SDK.")
+            port_name = port_name + '-' + str(watchos_sdk_version.major)
+        return port_name
+
+    def path_to_crash_logs(self):
+        if not apple_additions():
+            raise RuntimeError(self.NO_ON_DEVICE_TESTING)
+        return apple_additions().device_crash_log_path()
+
+    def _look_for_all_crash_logs_in_log_dir(self, newer_than):
+        log_list = {}
+        for device in self.devices():
+            crash_log = CrashLogs(device, self.path_to_crash_logs(), crash_logs_to_skip=self._crash_logs_to_skip_for_host.get(device, []))
+            log_list.update(crash_log.find_all_logs(include_errors=True, newer_than=newer_than))
+        return log_list
+
+    def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=None, sleep_fn=None, wait_for_log=True, target_host=None):
+        if target_host:
+            return super(WatchDevicePort, 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)
+
+        # We need to search every device since one was not specified.
+        for device in self.devices():
+            stderr_out, crashlog = super(WatchDevicePort, 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)
+            if crashlog:
+                return (stderr, crashlog)
+        return (stderr, None)
+
+    @memoized
+    def watchos_version(self):
+        if self.get_option('version'):
+            return Version.from_string(self.get_option('version'))
+
+        if not apple_additions():
+            raise RuntimeError(self.NO_ON_DEVICE_TESTING)
+
+        if not apple_additions().device_for_worker_number_map(self, software_variant='watchOS'):
+            raise RuntimeError('No devices are available')
+        version = None
+        for device in self.devices():
+            if not version:
+                version = device.platform.os_version
+            else:
+                if device.platform.os_version != version:
+                    raise RuntimeError('Multiple connected devices have different watchOS versions')
+        return version
+
+    # FIXME: These need device implementations <rdar://problem/30497991>.
+    def check_for_leaks(self, process_name, process_pid):
+        pass
+
+    def operating_system(self):
+        return 'watchos-device'
+
+    def _create_devices(self, device_class):
+        if not apple_additions():
+            raise RuntimeError(self.NO_ON_DEVICE_TESTING)
+        if not apple_additions().device_for_worker_number_map(self, software_variant='watchOS'):
+            raise RuntimeError('No devices are available for testing')
+
+        if self.default_child_processes() < self.child_processes():
+            raise RuntimeError('Not enought connected devices for {} processes'.format(self.child_processes()))
+
+    def clean_up_test_run(self):
+        super(WatchDevicePort, self).clean_up_test_run()
+        apple_additions().device_clean_up_test_run(self, self._path_to_driver(), self._build_path())
diff --git a/Tools/Scripts/webkitpy/port/watch_simulator.py b/Tools/Scripts/webkitpy/port/watch_simulator.py
new file mode 100644 (file)
index 0000000..82f1389
--- /dev/null
@@ -0,0 +1,147 @@
+# Copyright (C) 2018 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+from webkitpy.common.memoized import memoized
+from webkitpy.common.version import Version
+from webkitpy.port.config import apple_additions
+from webkitpy.port.watch import WatchPort
+from webkitpy.xcode.device_type import DeviceType
+from webkitpy.xcode.simulated_device import DeviceRequest, SimulatedDeviceManager
+
+_log = logging.getLogger(__name__)
+
+
+class WatchSimulatorPort(WatchPort):
+    port_name = 'watchos-simulator'
+
+    ARCHITECTURES = ['i386']
+    DEFAULT_ARCHITECTURE = 'i386'
+
+    DEVICE_MANAGER = SimulatedDeviceManager
+
+    DEFAULT_DEVICE_CLASS = 'Apple Watch Series 3 - 42mm'
+    CUSTOM_DEVICE_CLASSES = []
+    SDK = apple_additions().get_sdk('watchsimulator') if apple_additions() else 'watchsimulator'
+
+    def __init__(self, *args, **kwargs):
+        super(WatchSimulatorPort, self).__init__(*args, **kwargs)
+
+        self._set_device_class(self.get_option('device_class'))
+        _log.debug('WatchSimulatorPort _device_class is %s', self._device_class)
+
+    def architecture(self):
+        return self.DEFAULT_ARCHITECTURE
+
+    # This supports the mapping of a port name such as watchos-simulator-5 to the construction of a port
+    # using watchOS 5.
+    @staticmethod
+    def _version_from_name(name):
+        if len(name.split('-')) > 2 and name.split('-')[2].isdigit():
+            return Version.from_string(name.split('-')[2])
+        return None
+
+    @memoized
+    def watchos_version(self):
+        if self.get_option('version'):
+            return Version.from_string(self.get_option('version'))
+        return WatchSimulatorPort._version_from_name(self._name) or self.host.platform.xcode_sdk_version('watchsimulator')
+
+    def environment_for_api_tests(self):
+        inherited_env = super(WatchSimulatorPort, self).environment_for_api_tests()
+        new_environment = {}
+        SIMCTL_ENV_PREFIX = 'SIMCTL_CHILD_'
+        for value in inherited_env:
+            if not value.startswith(SIMCTL_ENV_PREFIX):
+                new_environment[SIMCTL_ENV_PREFIX + value] = inherited_env[value]
+            else:
+                new_environment[value] = inherited_env[value]
+        return new_environment
+
+    @memoized
+    def default_child_processes(self):
+        def filter_booted_watchos_devices(device):
+            if not device.platform_device.is_booted_or_booting():
+                return False
+            return device.platform_device.device_type in DeviceType(software_variant='watchOS', software_version=self.watchos_version())
+
+        if not self.get_option('dedicated_simulators', False):
+            num_booted_sims = len(SimulatedDeviceManager.device_by_filter(filter_booted_watchos_devices, host=self.host))
+            if num_booted_sims:
+                return num_booted_sims
+        return SimulatedDeviceManager.max_supported_simulators(self.host)
+
+    def _set_device_class(self, device_class):
+        self._device_class = device_class or self.DEFAULT_DEVICE_CLASS
+
+    def _create_devices(self, device_class):
+        self._set_device_class(device_class)
+        device_type = DeviceType.from_string(self._device_class, self.watchos_version())
+
+        _log.debug('\nCreating devices for {}'.format(device_type))
+
+        request = DeviceRequest(
+            device_type,
+            use_booted_simulator=not self.get_option('dedicated_simulators', False),
+            use_existing_simulator=False,
+            allow_incomplete_match=True,
+        )
+        SimulatedDeviceManager.initialize_devices([request] * self.child_processes(), self.host)
+
+    def operating_system(self):
+        return 'watchos-simulator'
+
+    def check_sys_deps(self):
+        target_device_type = DeviceType(software_variant='watchOS', software_version=self.watchos_version())
+        for device in SimulatedDeviceManager.available_devices(self.host):
+            if device.platform_device.device_type in target_device_type:
+                return super(WatchSimulatorPort, self).check_sys_deps()
+        _log.error('No simulated device matching "{}" found in watchOS SDK'.format(str(target_device_type)))
+        return False
+
+    def setup_environ_for_server(self, server_name=None):
+        _log.debug('Setting up environment for server on {}'.format(self.operating_system()))
+        env = super(WatchSimulatorPort, self).setup_environ_for_server(server_name)
+        if server_name == self.driver_name() and self.get_option('leaks'):
+            env['MallocStackLogging'] = '1'
+            env['__XPC_MallocStackLogging'] = '1'
+            env['MallocScribble'] = '1'
+            env['__XPC_MallocScribble'] = '1'
+        return env
+
+    def reset_preferences(self):
+        SimulatedDeviceManager.tear_down(self.host)
+
+    def nm_command(self):
+        return self.xcrun_find('nm')
+
+    @property
+    @memoized
+    def developer_dir(self):
+        return self._executive.run_command(['xcode-select', '--print-path']).rstrip()
+
+    def logging_patterns_to_strip(self):
+        return []
+
+    def stderr_patterns_to_strip(self):
+        return []
diff --git a/Tools/Scripts/webkitpy/port/watch_simulator_unittest.py b/Tools/Scripts/webkitpy/port/watch_simulator_unittest.py
new file mode 100644 (file)
index 0000000..8a77581
--- /dev/null
@@ -0,0 +1,76 @@
+# Copyright (C) 2018 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.common.system.executive_mock import MockExecutive2, ScriptError
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.common.version import Version
+from webkitpy.port.watch_simulator import WatchSimulatorPort
+from webkitpy.port import watch_testcase
+from webkitpy.tool.mocktool import MockOptions
+
+
+class WatchSimulatorTest(watch_testcase.WatchTest):
+    # FIXME: https://bugs.webkit.org/show_bug.cgi?id=173107
+    os_name = 'mac'
+    os_version = None
+    port_name = 'watch-simulator'
+    port_maker = WatchSimulatorPort
+
+    def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=Version(5), **kwargs):
+        port = super(WatchSimulatorTest, self).make_port(host=host, port_name=port_name, options=options, os_name=os_name, os_version=os_version, kwargs=kwargs)
+        port.set_option('child_processes', 1)
+        return port
+
+    def test_setup_environ_for_server(self):
+        port = self.make_port(options=MockOptions(leaks=True, guard_malloc=True))
+        env = port.setup_environ_for_server(port.driver_name())
+        self.assertEqual(env['MallocStackLogging'], '1')
+        self.assertEqual(env['MallocScribble'], '1')
+        self.assertEqual(env['DYLD_INSERT_LIBRARIES'], '/usr/lib/libgmalloc.dylib')
+
+    def test_operating_system(self):
+        self.assertEqual('watchos-simulator', self.make_port().operating_system())
+
+    def test_32bit(self):
+        port = self.make_port(options=MockOptions(architecture='i386'))
+
+        def run_script(script, args=None, env=None):
+            self.args = args
+
+        port._run_script = run_script
+        self.assertEqual(port.architecture(), 'i386')
+        port._build_driver()
+        self.assertEqual(self.args, ['--sdk', 'watchsimulator', 'ARCHS=i386'])
+
+    def test_sdk_name(self):
+        port = self.make_port()
+        self.assertEqual(port.SDK, 'watchsimulator')
+
+    def test_xcrun(self):
+        def throwing_run_command(args):
+            print(args)
+            raise ScriptError("MOCK script error")
+
+        port = self.make_port(options=MockOptions(architecture='i386'))
+        port._executive = MockExecutive2(run_command_fn=throwing_run_command)
+        expected_stdout = "['xcrun', '--sdk', 'watchsimulator', '-find', 'test']\n"
+        OutputCapture().assert_outputs(self, port.xcrun_find, args=['test', 'falling'], expected_stdout=expected_stdout)
diff --git a/Tools/Scripts/webkitpy/port/watch_testcase.py b/Tools/Scripts/webkitpy/port/watch_testcase.py
new file mode 100644 (file)
index 0000000..9dbcc19
--- /dev/null
@@ -0,0 +1,25 @@
+from webkitpy.common.version import Version
+from webkitpy.port import darwin_testcase
+from webkitpy.tool.mocktool import MockOptions
+
+
+class WatchTest(darwin_testcase.DarwinTest):
+    disable_setup = True
+
+    def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=Version(5), **kwargs):
+        if options:
+            options.architecture = 'x86'
+            options.webkit_test_runner = True
+        else:
+            options = MockOptions(architecture='x86', webkit_test_runner=True, configuration='Release')
+        port = super(WatchTest, self).make_port(host=host, port_name=port_name, options=options, os_name=os_name, os_version=None, kwargs=kwargs)
+        port.set_option('version', str(os_version))
+        return port
+
+    def test_driver_name(self):
+        self.assertEqual(self.make_port().driver_name(), 'WebKitTestRunnerApp.app')
+
+    def test_baseline_searchpath(self):
+        search_path = self.make_port().default_baseline_search_path()
+        self.assertEqual(search_path[-1], '/mock-checkout/LayoutTests/platform/wk2')
+        self.assertEqual(search_path[-2], '/mock-checkout/LayoutTests/platform/watchos')