| #!/usr/bin/env vpython3 |
| # Copyright 2019 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Unittests for iossim_util.py.""" |
| |
| import mock |
| import unittest |
| |
| import iossim_util |
| import mac_util |
| import os |
| import subprocess |
| import test_runner |
| import test_runner_test |
| |
| SIMULATORS_LIST = { |
| 'devices': { |
| 'com.apple.CoreSimulator.SimRuntime.iOS-11-4': [{ |
| 'isAvailable': |
| True, |
| 'name': |
| 'iPhone 5s 11.4 test simulator', |
| 'deviceTypeIdentifier': |
| 'com.apple.CoreSimulator.SimDeviceType.iPhone-5s', |
| 'state': |
| 'Shutdown', |
| 'udid': |
| 'E4E66320-177A-450A-9BA1-488D85B7278E' |
| }], |
| 'com.apple.CoreSimulator.SimRuntime.iOS-13-2': [{ |
| 'isAvailable': |
| True, |
| 'name': |
| 'iPhone X 13.2.2 test simulator', |
| 'deviceTypeIdentifier': |
| 'com.apple.CoreSimulator.SimDeviceType.iPhone-X', |
| 'state': |
| 'Shutdown', |
| 'udid': |
| 'E4E66321-177A-450A-9BA1-488D85B7278E' |
| }, { |
| 'isAvailable': |
| True, |
| 'name': |
| 'iPhone 11 13.2.2 test simulator', |
| 'deviceTypeIdentifier': |
| 'com.apple.CoreSimulator.SimDeviceType.iPhone-11', |
| 'state': |
| 'Shutdown', |
| 'udid': |
| 'A4E66321-177A-450A-9BA1-488D85B7278E' |
| }] |
| }, |
| 'devicetypes': [ |
| { |
| 'name': 'iPhone 5s', |
| 'bundlePath': '/path/iPhone 4s/Content', |
| 'identifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-5s' |
| }, |
| { |
| 'name': 'iPhone X', |
| 'bundlePath': '/path/iPhone X/Content', |
| 'identifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-X' |
| }, |
| { |
| 'name': 'iPhone 11', |
| 'bundlePath': '/path/iPhone 11/Content', |
| 'identifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-11' |
| }, |
| ], |
| 'pairs': [], |
| 'runtimes': [ |
| { |
| "buildversion": "15F79", |
| "bundlePath": "/path/Runtimes/iOS 11.4.simruntime", |
| "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-11-4", |
| "isAvailable": True, |
| "name": "iOS 11.4", |
| "version": "11.4" |
| }, |
| { |
| "buildversion": "17A844", |
| "bundlePath": "/path/Runtimes/iOS 13.1.simruntime", |
| "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-1", |
| "isAvailable": True, |
| "name": "iOS 13.1", |
| "version": "13.1" |
| }, |
| { |
| "buildversion": "17B102", |
| "bundlePath": "/path/Runtimes/iOS.simruntime", |
| "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-2", |
| "isAvailable": True, |
| "name": "iOS 13.2", |
| "version": "13.2.2" |
| }, |
| ] |
| } |
| |
| RUNTIMES_LIST = { |
| "111111": { |
| "build": "21A111111", |
| "deletable": True, |
| "identifier": "111111", |
| "kind": "Disk Image", |
| "lastUsedAt": "2023-09-28T21:57:06Z", |
| "mountPath": "path/to/mount", |
| "path": "path/to/runtime/111111.dmg", |
| "platformIdentifier": "com.apple.platform.iphonesimulator", |
| "runtimeBundlePath": "path/to/bundle/runtime/111111.simruntime", |
| "runtimeIdentifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-1", |
| "signatureState": "Verified", |
| "sizeBytes": 3595537104, |
| "state": "Ready", |
| "version": "13.1" |
| }, |
| "222222": { |
| "build": "21A222222", |
| "deletable": False, |
| "identifier": "222222", |
| "kind": "Bundled with Xcode", |
| "path": "path/to/runtime/222222.simruntime", |
| "platformIdentifier": "com.apple.platform.iphonesimulator", |
| "runtimeBundlePath": "path/to/bundle/runtime/222222.simruntime", |
| "runtimeIdentifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-2", |
| "signatureState": "Unknown", |
| "sizeBytes": 14115082240, |
| "state": "Ready", |
| "version": "13.2" |
| }, |
| "333333": { |
| "build": "21A333333", |
| "deletable": True, |
| "identifier": "333333", |
| "kind": "Legacy Download", |
| "path": "path/to/runtime/333333.simruntime", |
| "platformIdentifier": "com.apple.platform.iphonesimulator", |
| "runtimeBundlePath": "path/to/bundle/runtime/333333.simruntime", |
| "runtimeIdentifier": "com.apple.CoreSimulator.SimRuntime.iOS-11-4", |
| "signatureState": "Unknown", |
| "sizeBytes": 12596879360, |
| "state": "Ready", |
| "version": "11.4" |
| }, |
| "444444": { |
| "build": "21A444444", |
| "deletable": True, |
| "identifier": "444444", |
| "kind": "Disk Image", |
| "lastUsedAt": "2022-09-28T21:57:06Z", |
| "path": "path/to/runtime/444444.simruntime", |
| "platformIdentifier": "com.apple.platform.iphonesimulator", |
| "runtimeBundlePath": "path/to/bundle/runtime/444444.simruntime", |
| "runtimeIdentifier": "com.apple.CoreSimulator.SimRuntime.iOS-14-1", |
| "signatureState": "Unknown", |
| "sizeBytes": 12596879361, |
| "state": "Ready", |
| "version": "14.1" |
| }, |
| "555555": { |
| "build": "555555", |
| "deletable": True, |
| "identifier": "555555", |
| "kind": "Disk Image", |
| "path": "path/to/runtime/555555.simruntime", |
| "platformIdentifier": "com.apple.platform.iphonesimulator", |
| "runtimeBundlePath": "path/to/bundle/runtime/555555.simruntime", |
| "runtimeIdentifier": "com.apple.CoreSimulator.SimRuntime.iOS-15-1", |
| "signatureState": "Unknown", |
| "sizeBytes": 12596879362, |
| "state": "Ready", |
| "version": "15.1" |
| } |
| } |
| |
| RUNTIMES_MATCH_LIST = { |
| "appletvos17.0": { |
| "chosenRuntimeBuild": "21J11111", |
| "defaultBuild": "21J11111", |
| "platform": "com.apple.platform.appletvos", |
| "preferredBuild": "21J11111", |
| "sdkBuild": "21J11111", |
| "sdkVersion": "13.1" |
| }, |
| "iphoneos17.0": { |
| "chosenRuntimeBuild": "21A111112", |
| "defaultBuild": "21A111112", |
| "platform": "com.apple.platform.iphoneos", |
| "preferredBuild": "21A111111", |
| "sdkBuild": "21A111112", |
| "sdkVersion": "13.1" |
| } |
| } |
| |
| ADD_RUNTIME_OUTPUT = "111111 (iOS17.0)" |
| |
| |
| @mock.patch.object( |
| iossim_util, 'get_simulator_list', return_value=SIMULATORS_LIST) |
| @mock.patch.object( |
| iossim_util, 'get_simulator_runtime_list', return_value=RUNTIMES_LIST) |
| class GetiOSSimUtil(test_runner_test.TestCase): |
| """Tests for iossim_util.py.""" |
| |
| def setUp(self): |
| super(GetiOSSimUtil, self).setUp() |
| |
| def test_get_simulator_runtime_by_version(self, _, _2): |
| """Ensures correctness of filter.""" |
| self.assertEqual( |
| 'com.apple.CoreSimulator.SimRuntime.iOS-13-2', |
| iossim_util.get_simulator_runtime_by_version( |
| iossim_util.get_simulator_list(), '13.2.2')) |
| |
| def test_get_simulator_runtime_by_version_not_found(self, _, _2): |
| """Ensures that SimulatorNotFoundError raises if no runtime.""" |
| with self.assertRaises(test_runner.SimulatorNotFoundError) as context: |
| iossim_util.get_simulator_runtime_by_version( |
| iossim_util.get_simulator_list(), '13.3') |
| expected_message = ('Simulator does not exist: Not found ' |
| '"13.3" SDK in runtimes') |
| self.assertTrue(expected_message in str(context.exception)) |
| |
| def test_get_simulator_device_type_by_platform(self, _, _2): |
| """Ensures correctness of filter.""" |
| self.assertEqual( |
| 'com.apple.CoreSimulator.SimDeviceType.iPhone-11', |
| iossim_util.get_simulator_device_type_by_platform( |
| iossim_util.get_simulator_list(), 'iPhone 11')) |
| |
| def test_get_simulator_device_type_by_platform_not_found(self, _, _2): |
| """Ensures that SimulatorNotFoundError raises if no platform.""" |
| with self.assertRaises(test_runner.SimulatorNotFoundError) as context: |
| iossim_util.get_simulator_device_type_by_platform( |
| iossim_util.get_simulator_list(), 'iPhone XI') |
| expected_message = ('Simulator does not exist: Not found device ' |
| '"iPhone XI" in devicetypes') |
| self.assertTrue(expected_message in str(context.exception)) |
| |
| def test_get_simulator_runtime_by_device_udid(self, _, _2): |
| """Ensures correctness of filter.""" |
| self.assertEqual( |
| 'com.apple.CoreSimulator.SimRuntime.iOS-13-2', |
| iossim_util.get_simulator_runtime_by_device_udid( |
| 'E4E66321-177A-450A-9BA1-488D85B7278E')) |
| |
| def test_get_simulator_runtime_by_device_udid_not_found(self, _, _2): |
| """Ensures that SimulatorNotFoundError raises if no device with UDID.""" |
| with self.assertRaises(test_runner.SimulatorNotFoundError) as context: |
| iossim_util.get_simulator_runtime_by_device_udid('non_existing_UDID') |
| expected_message = ('Simulator does not exist: Not found simulator with ' |
| '"non_existing_UDID" UDID in devices') |
| self.assertTrue(expected_message in str(context.exception)) |
| |
| def test_get_simulator_udids_by_platform_and_version(self, _, _2): |
| """Ensures correctness of filter.""" |
| self.assertEqual(['A4E66321-177A-450A-9BA1-488D85B7278E'], |
| iossim_util.get_simulator_udids_by_platform_and_version( |
| 'iPhone 11', '13.2.2')) |
| |
| def test_get_simulator_udids_by_platform_and_version_not_found(self, _, _2): |
| """Ensures that filter returns empty list if no device with version.""" |
| self.assertEqual([], |
| iossim_util.get_simulator_udids_by_platform_and_version( |
| 'iPhone 11', '13.1')) |
| |
| @mock.patch('subprocess.check_output', autospec=True) |
| def test_create_device_by_platform_and_version(self, subprocess_mock, _, _2): |
| """Ensures that command is correct.""" |
| subprocess_mock.return_value = b'NEW_UDID' |
| self.assertEqual( |
| 'NEW_UDID', |
| iossim_util.create_device_by_platform_and_version( |
| 'iPhone 11', '13.2.2')) |
| self.assertEqual([ |
| 'xcrun', 'simctl', 'create', 'iPhone 11 13.2.2 test simulator', |
| 'com.apple.CoreSimulator.SimDeviceType.iPhone-11', |
| 'com.apple.CoreSimulator.SimRuntime.iOS-13-2' |
| ], subprocess_mock.call_args[0][0]) |
| |
| @mock.patch('subprocess.check_output', autospec=True) |
| def test_delete_simulator_by_udid(self, subprocess_mock, _, _2): |
| """Ensures that command is correct.""" |
| iossim_util.delete_simulator_by_udid('UDID') |
| self.assertEqual(['xcrun', 'simctl', 'delete', 'UDID'], |
| subprocess_mock.call_args[0][0]) |
| |
| @mock.patch('subprocess.check_call', autospec=True) |
| def test_wipe_simulator_by_platform_and_version(self, subprocess_mock, _, _2): |
| """Ensures that command is correct.""" |
| iossim_util.wipe_simulator_by_udid('A4E66321-177A-450A-9BA1-488D85B7278E') |
| self.assertEqual( |
| ['xcrun', 'simctl', 'erase', 'A4E66321-177A-450A-9BA1-488D85B7278E'], |
| subprocess_mock.call_args[0][0]) |
| |
| @mock.patch('subprocess.check_output', autospec=True) |
| def test_get_home_directory(self, subprocess_mock, _, _2): |
| """Ensures that command is correct.""" |
| subprocess_mock.return_value = b'HOME_DIRECTORY' |
| self.assertEqual('HOME_DIRECTORY', |
| iossim_util.get_home_directory('iPhone 11', '13.2.2')) |
| self.assertEqual([ |
| 'xcrun', 'simctl', 'getenv', 'A4E66321-177A-450A-9BA1-488D85B7278E', |
| 'HOME' |
| ], subprocess_mock.call_args[0][0]) |
| |
| @mock.patch.object(iossim_util, 'create_device_by_platform_and_version') |
| def test_no_new_sim_created_when_one_exists(self, mock_create, _, _2): |
| """Ensures no simulator is created when one in desired dimension exists.""" |
| self.assertEqual('A4E66321-177A-450A-9BA1-488D85B7278E', |
| iossim_util.get_simulator('iPhone 11', '13.2.2')) |
| self.assertFalse(mock_create.called) |
| |
| def test_copy_cert(self, _, _2): |
| """Ensures right commands are issued to copy cert""" |
| self.mock(os.path, 'exists', lambda *args: True) |
| |
| check_call_mock = mock.Mock() |
| self.mock(subprocess, 'check_call', check_call_mock) |
| iossim_util.copy_trusted_certificate('test/cert', 'UDID') |
| |
| calls = [ |
| mock.call(['xcrun', 'simctl', 'boot', 'UDID']), |
| mock.call([ |
| 'xcrun', 'simctl', 'keychain', 'UDID', 'add-root-cert', 'test/cert' |
| ]), |
| mock.call(['xcrun', 'simctl', 'shutdown', 'UDID']) |
| ] |
| |
| check_call_mock.assert_has_calls(calls) |
| # ensure subprocess.check_call was only called 3 times |
| self.assertEqual(check_call_mock.call_count, 3) |
| |
| def test_get_simulator_runtime_info_by_build(self, _, _2): |
| runtime = iossim_util.get_simulator_runtime_info_by_build('21A111111') |
| self.assertIsNotNone(runtime) |
| self.assertEqual(runtime['version'], '13.1') |
| self.assertEqual(runtime['identifier'], '111111') |
| |
| def test_get_simulator_runtime_info_by_id(self, _, _2): |
| runtime = iossim_util.get_simulator_runtime_info_by_id('111111') |
| self.assertIsNotNone(runtime) |
| self.assertEqual(runtime['version'], '13.1') |
| self.assertEqual(runtime['identifier'], '111111') |
| |
| def test_get_simulator_runtime_info(self, _, _2): |
| runtime = iossim_util.get_simulator_runtime_info('13.1') |
| self.assertIsNotNone(runtime) |
| self.assertEqual(runtime['version'], '13.1') |
| |
| @mock.patch.object(iossim_util, 'get_simulator_runtime_match_list') |
| def test_override_default_iphonesim_runtime(self, override_runtime_mock, _, |
| _2): |
| check_call_mock = mock.Mock() |
| self.mock(subprocess, 'check_call', check_call_mock) |
| override_runtime_mock.return_value = RUNTIMES_MATCH_LIST |
| iossim_util.override_default_iphonesim_runtime(ADD_RUNTIME_OUTPUT, '17.0') |
| calls = [ |
| mock.call([ |
| 'xcrun', 'simctl', 'runtime', 'match', 'set', 'iphoneos17.0', |
| '21A111111', '--sdkBuild', '21A111112' |
| ]), |
| ] |
| check_call_mock.assert_has_calls(calls) |
| |
| @mock.patch.object(iossim_util, 'get_simulator_runtime_match_list') |
| def test_override_default_iphonesim_runtime_not_found(self, |
| override_runtime_mock, |
| _, _2): |
| check_call_mock = mock.Mock() |
| self.mock(subprocess, 'check_call', check_call_mock) |
| override_runtime_mock.return_value = RUNTIMES_MATCH_LIST |
| iossim_util.override_default_iphonesim_runtime('random string', '17.0') |
| check_call_mock.assert_not_called() |
| |
| def test_add_simulator_runtime(self, _, _2): |
| check_output_mock = mock.Mock() |
| self.mock(subprocess, 'check_output', check_output_mock) |
| dmg_path = 'path/to/dmg' |
| iossim_util.add_simulator_runtime(dmg_path) |
| |
| calls = [ |
| mock.call(['xcrun', 'simctl', 'runtime', 'add', dmg_path]), |
| ] |
| |
| check_output_mock.assert_has_calls(calls) |
| self.assertEqual(check_output_mock.call_count, 1) |
| |
| def test_delete_simulator_runtime(self, _, _2): |
| check_output_mock = mock.Mock() |
| self.mock(subprocess, 'check_output', check_output_mock) |
| runtime_id = '111111' |
| iossim_util.delete_simulator_runtime(runtime_id) |
| |
| calls = [ |
| mock.call(['xcrun', 'simctl', 'runtime', 'delete', runtime_id]), |
| ] |
| |
| check_output_mock.assert_has_calls(calls) |
| self.assertEqual(check_output_mock.call_count, 1) |
| |
| def test_delete_simulator_runtime_and_wait_success(self, _, _2): |
| with mock.patch('iossim_util.get_simulator_runtime_info_by_id') \ |
| as mock_get_runtime_info_by_id, \ |
| mock.patch('iossim_util.get_simulator_runtime_info') \ |
| as mock_get_runtime_info, \ |
| mock.patch('iossim_util.delete_simulator_runtime') \ |
| as mock_delete_runtime: |
| mock_get_runtime_info_by_id.side_effect = [ |
| { |
| 'identifier': '111111', |
| 'state': 'deleting' |
| }, |
| None, |
| ] |
| mock_get_runtime_info.return_value = { |
| 'identifier': '111111', |
| 'state': 'ready' |
| } |
| mock_delete_runtime.return_value = None |
| |
| iossim_util.delete_simulator_runtime_and_wait('13.1') |
| |
| mock_get_runtime_info.assert_called_with('13.1') |
| mock_delete_runtime.assert_called_once_with('111111', True) |
| |
| def test_delete_least_recently_used_simulator_runtimes(self, _, _2): |
| with mock.patch('iossim_util.delete_simulator_runtime') \ |
| as mock_delete_simulator_runtime: |
| iossim_util.delete_least_recently_used_simulator_runtimes(1) |
| |
| calls = [ |
| mock.call('444444', True), |
| mock.call('555555', True), |
| ] |
| |
| self.assertEqual(mock_delete_simulator_runtime.call_count, 2) |
| mock_delete_simulator_runtime.assert_has_calls(calls, any_order=True) |
| |
| def test_delete_least_recently_used_simulator_runtimes_no_op(self, _, _2): |
| with mock.patch('iossim_util.delete_simulator_runtime') \ |
| as mock_delete_simulator_runtime: |
| iossim_util.delete_least_recently_used_simulator_runtimes() |
| |
| self.assertEqual(mock_delete_simulator_runtime.call_count, 0) |
| |
| def test_disable_hardware_keyboard(self, _, _2): |
| """Ensures right commands are issued to disable hardware keyboard""" |
| |
| self.mock(os.path, 'exists', lambda *args: False) |
| self.mock(os.path, 'expanduser', lambda *args: 'PATH') |
| |
| check_call_mock = mock.Mock() |
| self.mock(subprocess, 'check_call', check_call_mock) |
| check_calls = [ |
| mock.call(['plutil', '-create', 'binary1', 'PATH']), |
| mock.call( |
| ['plutil', '-insert', 'DevicePreferences', '-dictionary', 'PATH']), |
| mock.call([ |
| 'plutil', '-insert', 'DevicePreferences.UDID', '-dictionary', 'PATH' |
| ]), |
| mock.call([ |
| 'plutil', '-replace', |
| 'DevicePreferences.UDID.ConnectHardwareKeyboard', '-bool', 'NO', |
| 'PATH' |
| ]) |
| ] |
| |
| dict_mock = mock.Mock() |
| self.mock(mac_util, 'plist_as_dict', dict_mock) |
| |
| # file does not exist |
| dict_mock.return_value = ({}, None) |
| iossim_util.disable_hardware_keyboard('UDID') |
| check_call_mock.assert_has_calls(check_calls) |
| |
| # file exists but is empty |
| self.mock(os.path, 'exists', lambda *args: True) |
| check_call_mock.reset_mock() |
| dict_mock.return_value = ({}, None) |
| iossim_util.disable_hardware_keyboard('UDID') |
| check_call_mock.assert_has_calls(check_calls[1:]) |
| |
| #Device Prefs Dictionary Exists but not Prefs for UDID |
| check_call_mock.reset_mock() |
| dict_mock.return_value = ({'DevicePreferences': {}}, None) |
| iossim_util.disable_hardware_keyboard('UDID') |
| check_call_mock.assert_has_calls(check_calls[2:]) |
| |
| # Prefs for UDID exists |
| check_call_mock.reset_mock() |
| dict_mock.return_value = ({'DevicePreferences': {'UDID': {}}}, None) |
| iossim_util.disable_hardware_keyboard('UDID') |
| check_call_mock.assert_has_calls(check_calls[3:]) |
| |
| def test_disable_simulator_keyboard_tutorial(self, _, _2): |
| with mock.patch('iossim_util.boot_simulator_if_not_booted') \ |
| as mock_boot_simulator: |
| # boots successfully |
| mock_boot_simulator.return_value = None |
| |
| check_call_mock = mock.Mock() |
| self.mock(subprocess, 'check_call', check_call_mock) |
| udid = "1111111" |
| check_calls = [ |
| mock.call([ |
| 'xcrun', 'simctl', 'spawn', udid, 'defaults', 'write', |
| 'com.apple.keyboard.preferences', |
| 'DidShowContinuousPathIntroduction', '1' |
| ]), |
| mock.call([ |
| 'xcrun', 'simctl', 'spawn', udid, 'defaults', 'write', |
| 'com.apple.keyboard.preferences', |
| 'KeyboardDidShowProductivityTutorial', '1' |
| ]), |
| mock.call([ |
| 'xcrun', 'simctl', 'spawn', udid, 'defaults', 'write', |
| 'com.apple.keyboard.preferences', |
| 'DidShowGestureKeyboardIntroduction', '1' |
| ]), |
| mock.call([ |
| 'xcrun', 'simctl', 'spawn', udid, 'defaults', 'write', |
| 'com.apple.keyboard.preferences', |
| 'UIKeyboardDidShowInternationalInfoIntroduction', '1' |
| ]), |
| mock.call([ |
| 'xcrun', 'simctl', 'spawn', udid, 'defaults', 'write', |
| 'com.apple.keyboard.preferences', 'KeyboardAutocorrection', '0' |
| ]), |
| mock.call([ |
| 'xcrun', 'simctl', 'spawn', udid, 'defaults', 'write', |
| 'com.apple.keyboard.preferences', 'KeyboardPrediction', '0' |
| ]), |
| mock.call([ |
| 'xcrun', 'simctl', 'spawn', udid, 'defaults', 'write', |
| 'com.apple.keyboard.preferences', 'KeyboardShowPredictionBar', '0' |
| ]) |
| ] |
| |
| iossim_util.disable_simulator_keyboard_tutorial(udid) |
| check_call_mock.assert_has_calls(check_calls) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |