Skip to content

Commit

Permalink
[run-webkit-tests] Add visionOS
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=268567
rdar://112615351

Reviewed by Ryan Haddad.

* Tools/Scripts/webkitpy/common/version_name_map.py:
(VersionNameMap.__init__): Add visionOS.
* Tools/Scripts/webkitpy/port/factory.py:
(platform_options): Add --visionos-simulator flag.
(PortFactory): Add visionOS port.
* Tools/Scripts/webkitpy/port/visionos.py: Added.
(VisionOSPort): Added.
* Tools/Scripts/webkitpy/port/visionos_simulator.py: Added.
(VisionOSSimulatorPort): Added.
* Tools/Scripts/webkitpy/port/visionos_simulator_unittest.py: Added.
(VisionOSSimulatorTest): Added.
* Tools/Scripts/webkitpy/port/visionos_testcase.py: Added.
(VisionOSTest): Added.
* Tools/Scripts/webkitpy/xcode/device_type.py:
(DeviceType._define_software_variant_from_hardware_family): Handle Vision Pro.
(DeviceType.standardize_hardware_type): Strip 'Apple' from 'Apple Vision Pro'
to match naming conventions of other simulated hardware.
* Tools/Scripts/webkitpy/xcode/device_type_unittest.py:
(DeviceTypeTest.test_visionos): Added.

Canonical link: https://commits.webkit.org/274484@main
  • Loading branch information
JonWBedard committed Feb 12, 2024
1 parent 1941b54 commit 3159d80
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 1 deletion.
1 change: 1 addition & 0 deletions Tools/Scripts/webkitpy/common/version_name_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def __init__(self, platform=None):
'ios': self._automap_to_major_version('iOS', minimum=Version(10), maximum=Version(17)),
'tvos': self._automap_to_major_version('tvOS', minimum=Version(10), maximum=Version(17)),
'watchos': self._automap_to_major_version('watchOS', minimum=Version(1), maximum=Version(10)),
'visionos': self._automap_to_major_version('visionOS', minimum=Version(1), maximum=Version(1)),
'win': {
'Win10': Version(10),
'8.1': Version(6, 3),
Expand Down
5 changes: 5 additions & 0 deletions Tools/Scripts/webkitpy/common/version_name_map_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,8 @@ def test__automap_to_major_version(self):
self.assertEqual(
{"iOS 1": Version(1), "iOS 2": Version(2), "iOS 3": Version(3)}, r
)

def test_visionos_name_by_version(self):
map = VersionNameMap()
self.assertEqual(('visionos', Version(1)), map.from_name('visionOS 1'))
self.assertEqual('visionOS 1', map.to_name(version=Version(1), platform='visionos'))
4 changes: 4 additions & 0 deletions Tools/Scripts/webkitpy/port/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def platform_options(use_globs=False):
optparse.make_option('--ipad-simulator', action='store_const', dest='platform',
const=('ipad-simulator'),
help=('Alias for --platform=ipad-simulator')),
optparse.make_option('--visionos-simulator', action='store_const', dest='platform',
const=('visionos-simulator'),
help=('Alias for --platform=visionos-simulator')),
optparse.make_option('--simulator', action='store_const', dest='platform',
const=('ios-simulator'),
help=('DEPRECATED alias for --platform=ios-simulator')),
Expand Down Expand Up @@ -103,6 +106,7 @@ class PortFactory(object):
'ios_device.IOSDevicePort',
'watch_simulator.WatchSimulatorPort',
'watch_device.WatchDevicePort',
'visionos_simulator.VisionOSSimulatorPort',
'jsc_only.JscOnlyPort',
'mac.MacCatalystPort',
'mac.MacPort',
Expand Down
97 changes: 97 additions & 0 deletions Tools/Scripts/webkitpy/port/visionos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Copyright (C) 2024 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 webkitcorepy 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
from webkitpy.xcode.device_type import DeviceType


_log = logging.getLogger(__name__)


class VisionOSPort(DevicePort):
port_name = 'visionos'

CURRENT_VERSION = Version(1)
DEVICE_TYPE = DeviceType(software_variant='visionOS')

def __init__(self, *args, **kwargs):
super(VisionOSPort, self).__init__(*args, **kwargs)

if not self.get_option('webkit_test_runner', False):
raise ValueError('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=VisionOSPort.port_name)

def default_baseline_search_path(self, **kwargs):
versions_to_fallback = []
if self.device_version() == self.CURRENT_VERSION:
versions_to_fallback = [self.CURRENT_VERSION]
elif self.device_version():
temp_version = Version(self.device_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=VisionOSPort.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=VisionOSPort.port_name, table=INTERNAL_TABLE)
if apple_name:
expectations.append(
self._apple_baseline_path('{}-{}'.format(VisionOSPort.port_name, apple_name.lower().replace(' ', ''))))
expectations.append(self._webkit_baseline_path('{}-{}'.format(VisionOSPort.port_name, version.major)))

if apple_additions():
expectations.append(self._apple_baseline_path(VisionOSPort.port_name))
expectations.append(self._webkit_baseline_path(VisionOSPort.port_name))

expectations.append(self._webkit_baseline_path('wk2'))

return expectations
95 changes: 95 additions & 0 deletions Tools/Scripts/webkitpy/port/visionos_simulator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright (C) 2024 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 webkitcorepy import Version

from webkitpy.common.memoized import memoized
from webkitpy.port.config import apple_additions
from webkitpy.port.visionos import VisionOSPort
from webkitpy.xcode.device_type import DeviceType
from webkitpy.xcode.simulated_device import SimulatedDeviceManager

_log = logging.getLogger(__name__)


class VisionOSSimulatorPort(VisionOSPort):
port_name = 'visionos-simulator'

ARCHITECTURES = ['arm64']
DEFAULT_ARCHITECTURE = 'arm64'

DEVICE_MANAGER = SimulatedDeviceManager

DEFAULT_DEVICE_TYPES = [DeviceType(software_variant='visionOS', hardware_family='Vision', hardware_type='Pro')]
SDK = apple_additions().get_sdk('xrsimulator') if apple_additions() else 'xrsimulator'

def architecture(self):
result = self.get_option('architecture') or self.host.platform.architecture()
if result in ('arm64', 'arm64e'):
return 'arm64'
return self.DEFAULT_ARCHITECTURE

@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 device_version(self):
if self.get_option('version'):
return Version.from_string(self.get_option('version'))
return VisionOSSimulatorPort._version_from_name(self._name) if VisionOSSimulatorPort._version_from_name(self._name) else self.host.platform.xcode_sdk_version('xrsimulator')

def environment_for_api_tests(self):
inherited_env = super(VisionOSSimulatorPort, 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

def operating_system(self):
return 'visionos-simulator'

def setup_environ_for_server(self, server_name=None):
_log.debug('Setting up environment for server on {}'.format(self.operating_system()))
env = super(VisionOSSimulatorPort, 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)

@property
@memoized
def developer_dir(self):
return self._executive.run_command(['xcode-select', '--print-path']).rstrip()
70 changes: 70 additions & 0 deletions Tools/Scripts/webkitpy/port/visionos_simulator_unittest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright (C) 2024 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 webkitcorepy import Version

from webkitpy.common.system.executive_mock import MockExecutive2, ScriptError
from webkitpy.port.visionos_simulator import VisionOSSimulatorPort
from webkitpy.port import visionos_testcase
from webkitpy.tool.mocktool import MockOptions
from webkitpy.xcode.device_type import DeviceType

from webkitcorepy import OutputCapture


class VisionOSSimulatorTest(visionos_testcase.VisionOSTest):
os_name = 'mac'
os_version = None
port_name = 'visionos-simulator'
port_maker = VisionOSSimulatorPort

def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=Version(1), **kwargs):
port = super(VisionOSSimulatorTest, 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('visionos-simulator', self.make_port().operating_system())

def test_sdk_name(self):
port = self.make_port()
self.assertEqual(port.SDK, 'xrsimulator')

def test_max_child_processes(self):
port = self.make_port()
self.assertEqual(port.max_child_processes(DeviceType.from_string('iPhone')), 0)

def test_default_upload_configuration(self):
port = self.make_port()
configuration = port.configuration_for_upload()
self.assertEqual(configuration['architecture'], port.architecture())
self.assertEqual(configuration['is_simulator'], True)
self.assertEqual(configuration['platform'], 'visionos')
self.assertEqual(configuration['style'], 'release')
self.assertEqual(configuration['version_name'], 'visionOS {}'.format(port.device_version()))
48 changes: 48 additions & 0 deletions Tools/Scripts/webkitpy/port/visionos_testcase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (C) 2024 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 webkitcorepy import Version

from webkitpy.port import darwin_testcase
from webkitpy.tool.mocktool import MockOptions


class VisionOSTest(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 = 'arm64'
options.webkit_test_runner = True
else:
options = MockOptions(architecture='arm64', webkit_test_runner=True, configuration='Release')
port = super(VisionOSTest, 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/visionos')
1 change: 1 addition & 0 deletions Tools/Scripts/webkitpy/test/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ def main():
"webkitpy.port.linux_get_crash_log_unittest",
"webkitpy.port.mac_unittest",
"webkitpy.port.server_process_unittest",
"webkitpy.port.visionos_simulator_unittest",
"webkitpy.port.watch_simulator_unittest",
"webkitpy.port.waylanddriver_unittest",
"webkitpy.port.westondriver_unittest",
Expand Down
6 changes: 5 additions & 1 deletion Tools/Scripts/webkitpy/xcode/device_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
class DeviceType(object):
FIRST_GENERATION = ' (1st generation)'
SIZE_RE = re.compile(r'(?P<series>.+ )\((?P<size>\d\d)mm\)')
APPLE_VISION_PREFIX = 'Apple Vision'

@classmethod
def from_string(cls, device_string, version=None):
Expand Down Expand Up @@ -76,6 +77,8 @@ def _define_software_variant_from_hardware_family(self):
self.software_variant = 'tvOS'
elif self.hardware_family.lower().startswith('ipad') or self.hardware_family.lower().startswith('iphone'):
self.software_variant = 'iOS'
elif self.hardware_family.lower().split(' ')[-1].startswith('vision'):
self.software_variant = 'visionOS'

def check_consistency(self):
if self.hardware_family is not None:
Expand Down Expand Up @@ -121,7 +124,8 @@ def standardize_hardware_type(cls, hardware_type):
size_match = cls.SIZE_RE.match(hardware_type)
if size_match:
return '{}- {}mm'.format(size_match.group('series'), size_match.group('size'))

if hardware_type.lower().startswith(cls.APPLE_VISION_PREFIX.lower()):
return hardware_type[len('Apple '):]
return hardware_type

@property
Expand Down
6 changes: 6 additions & 0 deletions Tools/Scripts/webkitpy/xcode/device_type_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,9 @@ def test_watch_standardization(self):
self.assertEqual(DeviceType.from_string('Apple Watch Series 5 (44mm)').standardized_hardware_type, 'Series 5 - 44mm')
self.assertTrue(DeviceType.from_string('Apple Watch Series 5 (44mm)') == DeviceType.from_string('Apple Watch Series 5 - 44mm'))
self.assertTrue(DeviceType.from_string('Apple Watch Series 5 (38mm)') != DeviceType.from_string('Apple Watch Series 5 - 44mm'))

def test_visionos(self):
type = DeviceType.from_string('Apple Vision Pro')
self.assertEqual('Vision', type.hardware_family)
self.assertEqual('Pro', type.hardware_type)
self.assertEqual('visionOS', type.software_variant)

0 comments on commit 3159d80

Please sign in to comment.