1# Copyright 2024 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5from __future__ import annotations 6 7import argparse 8import unittest 9 10import hjson 11 12from crossbench import plt 13from crossbench.cli.config.driver import (AmbiguousDriverIdentifier, 14 BrowserDriverType, DriverConfig) 15from crossbench.exception import ArgumentTypeMultiException 16from crossbench.plt.chromeos_ssh import ChromeOsSshPlatform 17from tests import test_helper 18from tests.crossbench.cli.config.base import (ADB_DEVICES_OUTPUT, 19 XCTRACE_DEVICES_SINGLE_OUTPUT, 20 BaseConfigTestCase) 21 22 23class BrowserDriverTypeTestCase(unittest.TestCase): 24 25 def test_default(self): 26 self.assertEqual(BrowserDriverType.default(), BrowserDriverType.WEB_DRIVER) 27 28 def test_parse_invalid(self): 29 for invalid in ["invalid", None, [], (), {}]: 30 with self.assertRaises(argparse.ArgumentTypeError): 31 BrowserDriverType.parse(invalid) 32 33 def test_parse_str(self): 34 test_data = { 35 "": BrowserDriverType.default(), 36 "selenium": BrowserDriverType.WEB_DRIVER, 37 "webdriver": BrowserDriverType.WEB_DRIVER, 38 "applescript": BrowserDriverType.APPLE_SCRIPT, 39 "osa": BrowserDriverType.APPLE_SCRIPT, 40 "android": BrowserDriverType.ANDROID, 41 "adb": BrowserDriverType.ANDROID, 42 "iphone": BrowserDriverType.IOS, 43 "ios": BrowserDriverType.IOS, 44 "ssh": BrowserDriverType.LINUX_SSH, 45 "chromeos-ssh": BrowserDriverType.CHROMEOS_SSH, 46 } 47 for value, result in test_data.items(): 48 self.assertEqual(BrowserDriverType.parse(value), result) 49 50 def test_parse_enum(self): 51 for driver_type in BrowserDriverType: 52 self.assertEqual(BrowserDriverType.parse(driver_type), driver_type) 53 54 55class DriverConfigTestCase(BaseConfigTestCase): 56 57 def test_default(self): 58 default = DriverConfig.default() 59 self.assertEqual(default.type, BrowserDriverType.WEB_DRIVER) 60 self.assertTrue(default.is_local) 61 self.assertFalse(default.is_remote) 62 63 def test_parse_invalid(self): 64 with self.assertRaises(argparse.ArgumentTypeError): 65 _ = DriverConfig.parse("") 66 with self.assertRaises(argparse.ArgumentTypeError): 67 _ = DriverConfig.parse(":") 68 with self.assertRaises(argparse.ArgumentTypeError): 69 _ = DriverConfig.parse("{:}") 70 with self.assertRaises(argparse.ArgumentTypeError): 71 _ = DriverConfig.parse("}") 72 with self.assertRaises(argparse.ArgumentTypeError): 73 _ = DriverConfig.parse("{") 74 75 def test_parse_driver_path_invalid(self): 76 driver_path = self.out_dir / "driver" 77 with self.assertRaises(argparse.ArgumentTypeError) as cm: 78 _ = DriverConfig.parse(str(driver_path)) 79 self.assertIn(str(driver_path), str(cm.exception)) 80 81 self.fs.create_file(driver_path) 82 with self.assertRaises(argparse.ArgumentTypeError) as cm: 83 _ = DriverConfig.parse(str(driver_path)) 84 message = str(cm.exception) 85 self.assertIn(str(driver_path), message) 86 self.assertIn("empty", message) 87 88 def test_parse_driver_path(self): 89 chromedriver_path = self.out_dir / "chromedriver" 90 self.fs.create_file(chromedriver_path, st_size=100) 91 driver = DriverConfig.parse(str(chromedriver_path)) 92 self.assertEqual(driver.path, chromedriver_path) 93 94 config = {"path": str(chromedriver_path)} 95 driver_2 = DriverConfig.parse(config) 96 self.assertEqual(driver_2.path, chromedriver_path) 97 self.assertEqual(driver, driver_2) 98 99 def test_parse_dict_device_id_conflict(self): 100 self.platform.sh_results = [] 101 config_dict = { 102 "type": "adb", 103 "device_id": "1234", 104 "settings": { 105 "device_id": "ABCD" 106 } 107 } 108 with self.assertRaises(argparse.ArgumentTypeError) as cm: 109 DriverConfig.parse(config_dict) 110 self.assertIn("1234", str(cm.exception)) 111 self.assertIn("ABCD", str(cm.exception)) 112 113 def test_parse_dict_chromeos_ssh(self): 114 config_dict = { 115 "type": "chromeos-ssh", 116 "settings": { 117 "host": "chromeos6-row17-rack14-host7", 118 "port": "9515", 119 "ssh_port": "22", 120 "ssh_user": "root" 121 } 122 } 123 ssh_user = config_dict["settings"]["ssh_user"] 124 ssh_host = config_dict["settings"]["host"] 125 self.platform.expect_sh("ssh", "-p", config_dict["settings"]["ssh_port"], 126 f"{ssh_user}@{ssh_host}", 127 f"'[' -e {ChromeOsSshPlatform.AUTOLOGIN_PATH} ']'") 128 config = DriverConfig.parse(config_dict) 129 assert isinstance(config, DriverConfig) 130 self.assertEqual(config.type, BrowserDriverType.CHROMEOS_SSH) 131 self.assertTrue(config.is_remote) 132 self.assertFalse(config.is_local) 133 platform = config.get_platform() 134 assert isinstance(platform, ChromeOsSshPlatform) 135 self.assertEqual(platform.host, "chromeos6-row17-rack14-host7") 136 self.assertEqual(platform.port, 9515) 137 self.assertEqual(platform.ssh_port, 22) 138 self.assertEqual(platform.ssh_user, "root") 139 140 def test_parse_inline_json_adb(self): 141 self.platform.sh_results = [ADB_DEVICES_OUTPUT] 142 config_dict = {"type": "adb", "settings": {"device_id": "0a388e93"}} 143 config_1 = DriverConfig.parse(hjson.dumps(config_dict)) 144 assert isinstance(config_1, DriverConfig) 145 self.assertEqual(config_1.type, BrowserDriverType.ANDROID) 146 self.assertEqual(config_1.device_id, "0a388e93") 147 self.assertEqual(config_1.settings["device_id"], "0a388e93") 148 self.assertTrue(config_1.is_remote) 149 self.assertFalse(config_1.is_local) 150 self.assertIsNone(config_1.adb_bin) 151 152 self.platform.sh_results = [ADB_DEVICES_OUTPUT] 153 config_2 = DriverConfig.parse_dict(config_dict) 154 assert isinstance(config_2, DriverConfig) 155 self.assertEqual(config_2.type, BrowserDriverType.ANDROID) 156 self.assertEqual(config_2.device_id, "0a388e93") 157 self.assertEqual(config_2.settings["device_id"], "0a388e93") 158 self.assertTrue(config_2.is_remote) 159 self.assertFalse(config_2.is_local) 160 self.assertIsNone(config_2.adb_bin) 161 self.assertEqual(config_1, config_2) 162 163 self.platform.sh_results = [ADB_DEVICES_OUTPUT] 164 config_dict = {"type": "adb", "device_id": "0a388e93"} 165 config_3 = DriverConfig.parse_dict(config_dict) 166 assert isinstance(config_3, DriverConfig) 167 self.assertEqual(config_3.type, BrowserDriverType.ANDROID) 168 self.assertEqual(config_3.device_id, "0a388e93") 169 self.assertTrue(config_3.is_remote) 170 self.assertFalse(config_3.is_local) 171 self.assertIsNone(config_3.settings) 172 self.assertIsNone(config_2.adb_bin) 173 self.assertNotEqual(config_1, config_3) 174 self.assertNotEqual(config_2, config_3) 175 176 def test_parse_custom_adb_bin(self): 177 adb_bin = self.out_dir / "adb" 178 self.platform.sh_results = [ADB_DEVICES_OUTPUT] 179 config_dict = { 180 "type": "adb", 181 "device_id": "0a388e93", 182 "adb_bin": str(adb_bin) 183 } 184 with self.assertRaises(argparse.ArgumentTypeError) as cm: 185 _ = DriverConfig.parse(hjson.dumps(config_dict)) 186 self.assertIn(str(adb_bin), str(cm.exception)) 187 self.fs.create_file(adb_bin, st_size=100) 188 config = DriverConfig.parse(hjson.dumps(config_dict)) 189 assert isinstance(config, DriverConfig) 190 self.assertEqual(config.type, BrowserDriverType.ANDROID) 191 self.assertEqual(config.adb_bin, adb_bin) 192 193 def test_parse_adb_phone_identifier_unknown(self): 194 self.platform.sh_results = [ADB_DEVICES_OUTPUT] 195 if self.platform.is_macos: 196 self.platform.expect_sh(result=XCTRACE_DEVICES_SINGLE_OUTPUT) 197 198 with self.assertRaises(argparse.ArgumentTypeError) as cm: 199 _ = DriverConfig.parse("Unknown Device X") 200 self.assertIn("Unknown Device X", str(cm.exception)) 201 202 def test_parse_adb_phone_identifier_multiple(self): 203 self.platform.sh_results = [ADB_DEVICES_OUTPUT] 204 with self.assertRaises(ArgumentTypeMultiException) as cm: 205 _ = DriverConfig.parse("emulator.*") 206 message: str = str(cm.exception) 207 self.assertIn("emulator-5554", message) 208 self.assertIn("emulator-5556", message) 209 self.assertTrue(len(cm.exception), 1) 210 self.assertTrue(cm.exception.matching(AmbiguousDriverIdentifier)) 211 self.assertEqual(len(self.platform.sh_cmds), 1) 212 213 def test_parse_adb_phone_identifier(self): 214 self.platform.sh_results = [ADB_DEVICES_OUTPUT, ADB_DEVICES_OUTPUT] 215 216 config = DriverConfig.parse("Nexus_7") 217 assert isinstance(config, DriverConfig) 218 self.assertEqual(len(self.platform.sh_cmds), 2) 219 220 self.assertEqual(config.type, BrowserDriverType.ANDROID) 221 self.assertEqual(config.device_id, "0a388e93") 222 self.assertTrue(config.is_remote) 223 self.assertFalse(config.is_local) 224 225 def test_parse_adb_phone_serial(self): 226 self.platform.sh_results = [ADB_DEVICES_OUTPUT, ADB_DEVICES_OUTPUT] 227 228 config = DriverConfig.parse("0a388e93") 229 assert isinstance(config, DriverConfig) 230 self.assertEqual(len(self.platform.sh_cmds), 2) 231 232 self.assertEqual(config.type, BrowserDriverType.ANDROID) 233 self.assertEqual(config.device_id, "0a388e93") 234 235 @unittest.skipIf(not plt.PLATFORM.is_macos, "Incompatible platform") 236 def test_parse_ios_phone_serial(self): 237 self.platform.sh_results = [ 238 ADB_DEVICES_OUTPUT, XCTRACE_DEVICES_SINGLE_OUTPUT, 239 XCTRACE_DEVICES_SINGLE_OUTPUT 240 ] 241 242 config = DriverConfig.parse("00001111-11AA22BB33DD") 243 assert isinstance(config, DriverConfig) 244 self.assertEqual(len(self.platform.sh_cmds), 3) 245 246 self.assertEqual(config.type, BrowserDriverType.IOS) 247 self.assertEqual(config.device_id, "00001111-11AA22BB33DD") 248 249 250if __name__ == "__main__": 251 test_helper.run_pytest(__file__) 252