1# Lint as: python2, python3 2# Copyright 2022 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import unittest 7import tempfile 8import shutil 9import stat 10 11from unittest.mock import Mock, ANY, patch 12from autotest_lib.client.common_lib import error 13from autotest_lib.server.cros.tradefed import tradefed_test 14 15 16class TradefedTestTest(unittest.TestCase): 17 """Tests for TradefedTest class.""" 18 19 def setUp(self): 20 self._mockjob_tmpdirs = [] 21 self._bindir = tempfile.mkdtemp() 22 self._outputdir = tempfile.mkdtemp() 23 self.mock_adb = Mock() 24 self.tradefed = tradefed_test.TradefedTest(self.create_mock_job(), 25 self._bindir, 26 self._outputdir, 27 adb=self.mock_adb) 28 29 def tearDown(self): 30 shutil.rmtree(self._bindir) 31 shutil.rmtree(self._outputdir) 32 for tmpdir in self._mockjob_tmpdirs: 33 shutil.rmtree(tmpdir) 34 35 def create_mock_job(self): 36 """Creates a mock necessary for constructing tradefed_test instance.""" 37 mock_job = Mock() 38 mock_job.pkgmgr = None 39 mock_job.autodir = None 40 mock_job.tmpdir = tempfile.mkdtemp() 41 self._mockjob_tmpdirs.append(mock_job.tmpdir) 42 return mock_job 43 44 # Verify that try_adb_connect fails when run_adb_cmd fails. 45 @patch('autotest_lib.server.cros.tradefed.adb.get_adb_target') 46 def test_try_adb_connect_run_adb_fail(self, mock_get_adb_target): 47 mock_run_adb_cmd = self.mock_adb.run 48 49 # Exit status is set to non-0 to exit _try_adb_connect() early. 50 mock_run_adb_cmd.return_value.exit_status = 1 51 mock_get_adb_target.return_value = '123.76.0.29:3467' 52 53 self.assertFalse(self.tradefed._try_adb_connect(Mock())) 54 mock_run_adb_cmd.assert_called_with(ANY, 55 args=('connect', 56 '123.76.0.29:3467'), 57 verbose=ANY, 58 env=ANY, 59 ignore_status=ANY, 60 timeout=ANY) 61 62 # Verify that _run_tradefed_with_timeout works. 63 @patch('autotest_lib.server.cros.tradefed.tradefed_test.TradefedTest._run') 64 @patch('autotest_lib.server.cros.tradefed.tradefed_test.TradefedTest._tradefed_cmd_path' 65 ) 66 @patch('autotest_lib.server.cros.tradefed.tradefed_utils.adb_keepalive') 67 @patch('autotest_lib.server.cros.tradefed.adb.get_adb_targets') 68 def test_run_tradefed_with_timeout(self, mock_get_adb_targets, _, 69 mock_tradefed_cmd_path, mock_run): 70 self.tradefed._install_paths = '/any/install/path' 71 72 mock_host1 = Mock() 73 mock_host2 = Mock() 74 self.tradefed._hosts = [mock_host1, mock_host2] 75 76 mock_get_adb_targets.return_value = ['host1:4321', 'host2:22'] 77 78 mock_tradefed_cmd_path.return_value = '/any/path' 79 80 self.tradefed._run_tradefed_with_timeout(['command'], 1234) 81 mock_get_adb_targets.assert_called_with(self.tradefed._hosts) 82 83 def test_kill_adb_server(self): 84 mock_run = self.mock_adb.run 85 self.tradefed._kill_adb_server() 86 mock_run.assert_called_with(None, 87 args=('kill-server', ), 88 timeout=ANY, 89 verbose=ANY) 90 91 def test_verify_arc_hosts_single_host(self): 92 mock_run = self.mock_adb.run 93 mock_host = Mock() 94 self.tradefed._hosts = [mock_host] 95 96 self.tradefed._verify_arc_hosts() 97 98 mock_run.assert_called_with(mock_host, 99 args=('shell', 'getprop', 100 'ro.build.fingerprint')) 101 102 # Verify that multiple hosts with differet fingerprints fail. 103 def test_verify_arc_hosts_different_fingerprints(self): 104 mock_run = self.mock_adb.run 105 mock_host1 = Mock() 106 mock_host2 = Mock() 107 self.tradefed._hosts = [mock_host1, mock_host2] 108 109 side_effects = [Mock(), Mock()] 110 side_effects[0].stdout = 'fingerprint1' 111 side_effects[1].stdout = 'fingerprint2' 112 mock_run.side_effect = side_effects 113 114 self.assertRaises(error.TestFail, self.tradefed._verify_arc_hosts) 115 116 mock_run.assert_any_call(mock_host1, 117 args=('shell', 'getprop', 118 'ro.build.fingerprint')) 119 mock_run.assert_any_call(mock_host2, 120 args=('shell', 'getprop', 121 'ro.build.fingerprint')) 122 123 # Verify that wait for arc boot uses polling with adb. 124 @patch('autotest_lib.server.utils.poll_for_condition') 125 def test_wait_for_arc_boot(self, mock_poll_for_condition): 126 mock_run = self.mock_adb.run 127 128 # stdout just has to be something that evaluates to True. 129 mock_run.return_value.stdout = 'anything' 130 131 mock_host = Mock() 132 self.tradefed._wait_for_arc_boot(mock_host) 133 134 self.assertEqual(mock_run.call_count, 0) 135 136 # Verify that the condition function uses the expected adb command. 137 self.assertEqual(mock_poll_for_condition.call_count, 1) 138 args = mock_poll_for_condition.call_args[0] 139 condition_func = args[0] 140 self.assertTrue(condition_func()) 141 142 mock_run.assert_called_with(mock_host, 143 args=('shell', 'pgrep', '-f', 144 'org.chromium.arc.intent_helper'), 145 ignore_status=True) 146 147 def test_disable_adb_install_dialog_android_version_over_29(self): 148 mock_run = self.mock_adb.run 149 mock_run.return_value.stdout = 'disabled' 150 151 self.tradefed._android_version = 30 152 mock_host = Mock() 153 self.tradefed._disable_adb_install_dialog(mock_host) 154 155 mock_run.assert_called_with(mock_host, 156 args=('shell', 'settings', 'put', 'global', 157 'verifier_verify_adb_installs', '0'), 158 verbose=ANY) 159 160 def test_disable_adb_install_dialog_android_version_under_29(self): 161 mock_run = self.mock_adb.run 162 163 mock_run.return_value.stdout = 'disabled' 164 165 self.tradefed._android_version = 28 166 mock_host = Mock() 167 self.tradefed._disable_adb_install_dialog(mock_host) 168 169 mock_run.assert_called_with(mock_host, 170 args=('shell', 'settings', 'put', 'global', 171 'verifier_verify_adb_installs', '0'), 172 verbose=ANY) 173 174 mock_host.run.assert_called_with( 175 'android-sh -c \'setprop persist.sys.disable_rescue true\'') 176 177 def test_fetch_helpers_from_dut(self): 178 mock_run = self.mock_adb.run 179 self.tradefed._repository = '/repo/path' 180 181 mock_host = Mock() 182 self.tradefed._hosts = [mock_host] 183 184 # '::' is intentional and should be skipped. 185 mock_run.return_value.stdout = 'package1:package2::package3' 186 187 self.tradefed._fetch_helpers_from_dut() 188 189 mock_run.assert_called_with( 190 mock_host, 191 args=('shell', 'getprop', 192 'ro.vendor.cts_interaction_helper_packages')) 193 194 self.assertEqual(mock_host.get_file.call_count, 3) 195 196 mock_host.get_file.assert_any_call( 197 '/usr/local/opt/google/vms/android/package1.apk', 198 '/repo/path/testcases', 199 ) 200 201 mock_host.get_file.assert_any_call( 202 '/usr/local/opt/google/vms/android/package2.apk', 203 '/repo/path/testcases', 204 ) 205 206 mock_host.get_file.assert_any_call( 207 '/usr/local/opt/google/vms/android/package3.apk', 208 '/repo/path/testcases', 209 ) 210 211 def test_get_abilist(self): 212 mock_run = self.mock_adb.run 213 mock_host = Mock() 214 self.tradefed._hosts = [mock_host] 215 216 mock_run.return_value.stdout = 'arm,x86,my_awesome_architecture' 217 218 self.assertEqual(['arm', 'x86', 'my_awesome_architecture'], 219 self.tradefed._get_abilist()) 220 221 mock_run.assert_called_with(mock_host, 222 args=('shell', 'getprop', 223 'ro.product.cpu.abilist')) 224 225 def test_copy_extra_artifacts_dut(self): 226 mock_run = self.mock_adb.run 227 mock_host = Mock() 228 229 extra_artifacts = ['artifacts', '/path/to/some/file'] 230 self.tradefed._copy_extra_artifacts_dut(extra_artifacts, mock_host, 231 self._outputdir) 232 233 self.assertEqual(mock_run.call_count, 2) 234 235 mock_run.assert_any_call( 236 mock_host, 237 args=('pull', 'artifacts', self._outputdir), 238 verbose=ANY, 239 timeout=ANY, 240 ) 241 242 mock_run.assert_any_call( 243 mock_host, 244 args=('pull', '/path/to/some/file', self._outputdir), 245 verbose=ANY, 246 timeout=ANY, 247 ) 248 249 # TODO(rkuroiwa): This test was added to test Adb.add_path. 250 # So most of these tradefed_test functions are mocked because 251 # they are not ncecessarily ready to be tested. 252 # Once the rest of the modules are tested, reevaluate unmocking them. 253 @patch('os.chmod') 254 @patch('autotest_lib.server.cros.tradefed.tradefed_test.TradefedTest._instance_copyfile' 255 ) 256 @patch('autotest_lib.server.cros.tradefed.tradefed_test.TradefedTest._validate_download_cache' 257 ) 258 @patch('autotest_lib.server.cros.tradefed.tradefed_test.TradefedTest._download_to_cache' 259 ) 260 @patch('autotest_lib.server.cros.tradefed.tradefed_test.TradefedTest._invalidate_download_cache' 261 ) 262 @patch('autotest_lib.server.cros.tradefed.tradefed_utils.lock') 263 def test_install_files(self, mock_lock, mock_invalidate_download_cache, 264 mock_download_to_cache, 265 mock_validate_download_cache, mock_instance_copy, 266 mock_chmod): 267 mock_add_path = self.mock_adb.add_path 268 self.tradefed._tradefed_cache_lock = '/lock/lock_file' 269 self.tradefed._install_paths = [] 270 271 mock_download_to_cache.return_value = '/path/to/downloaded/file' 272 mock_instance_copy.return_value = '/path/to/local/downloaded_file' 273 274 self.tradefed._install_files('gs://mybucket/path/to/dir', ['anyfile'], 275 stat.S_IRWXU) 276 277 mock_lock.assert_called_with('/lock/lock_file') 278 mock_invalidate_download_cache.assert_called() 279 mock_validate_download_cache.assert_called() 280 mock_chmod.assert_called_with('/path/to/local/downloaded_file', 281 stat.S_IRWXU) 282 mock_add_path.assert_called_with('/path/to/local') 283 284 self.assertEqual(self.tradefed._install_paths, ['/path/to/local']) 285