1#!/usr/bin/env python3 2# 3# Copyright 2016 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import time 18import unittest 19 20import mock 21 22from acts import utils 23from acts import signals 24from acts.controllers.adb import AdbError 25 26PROVISIONED_STATE_GOOD = 1 27 28 29class ByPassSetupWizardTests(unittest.TestCase): 30 """This test class for unit testing acts.utils.bypass_setup_wizard.""" 31 32 def test_start_standing_subproc(self): 33 with self.assertRaisesRegex(utils.ActsUtilsError, 34 'Process .* has terminated'): 35 utils.start_standing_subprocess('sleep 0', check_health_delay=0.1) 36 37 def test_stop_standing_subproc(self): 38 p = utils.start_standing_subprocess('sleep 0') 39 time.sleep(0.1) 40 with self.assertRaisesRegex(utils.ActsUtilsError, 41 'Process .* has terminated'): 42 utils.stop_standing_subprocess(p) 43 44 @mock.patch('time.sleep') 45 def test_bypass_setup_wizard_no_complications(self, _): 46 ad = mock.Mock() 47 ad.adb.shell.side_effect = [ 48 # Return value for SetupWizardExitActivity 49 BypassSetupWizardReturn.NO_COMPLICATIONS, 50 # Return value for device_provisioned 51 PROVISIONED_STATE_GOOD, 52 ] 53 ad.adb.return_state = BypassSetupWizardReturn.NO_COMPLICATIONS 54 self.assertTrue(utils.bypass_setup_wizard(ad)) 55 self.assertFalse( 56 ad.adb.root_adb.called, 57 'The root command should not be called if there are no ' 58 'complications.') 59 60 @mock.patch('time.sleep') 61 def test_bypass_setup_wizard_unrecognized_error(self, _): 62 ad = mock.Mock() 63 ad.adb.shell.side_effect = [ 64 # Return value for SetupWizardExitActivity 65 BypassSetupWizardReturn.UNRECOGNIZED_ERR, 66 # Return value for device_provisioned 67 PROVISIONED_STATE_GOOD, 68 ] 69 with self.assertRaises(AdbError): 70 utils.bypass_setup_wizard(ad) 71 self.assertFalse( 72 ad.adb.root_adb.called, 73 'The root command should not be called if we do not have a ' 74 'codepath for recovering from the failure.') 75 76 @mock.patch('time.sleep') 77 def test_bypass_setup_wizard_need_root_access(self, _): 78 ad = mock.Mock() 79 ad.adb.shell.side_effect = [ 80 # Return value for SetupWizardExitActivity 81 BypassSetupWizardReturn.ROOT_ADB_NO_COMP, 82 # Return value for rooting the device 83 BypassSetupWizardReturn.NO_COMPLICATIONS, 84 # Return value for device_provisioned 85 PROVISIONED_STATE_GOOD 86 ] 87 88 utils.bypass_setup_wizard(ad) 89 90 self.assertTrue( 91 ad.adb.root_adb_called, 92 'The command required root access, but the device was never ' 93 'rooted.') 94 95 @mock.patch('time.sleep') 96 def test_bypass_setup_wizard_need_root_already_skipped(self, _): 97 ad = mock.Mock() 98 ad.adb.shell.side_effect = [ 99 # Return value for SetupWizardExitActivity 100 BypassSetupWizardReturn.ROOT_ADB_SKIPPED, 101 # Return value for SetupWizardExitActivity after root 102 BypassSetupWizardReturn.ALREADY_BYPASSED, 103 # Return value for device_provisioned 104 PROVISIONED_STATE_GOOD 105 ] 106 self.assertTrue(utils.bypass_setup_wizard(ad)) 107 self.assertTrue(ad.adb.root_adb_called) 108 109 @mock.patch('time.sleep') 110 def test_bypass_setup_wizard_root_access_still_fails(self, _): 111 ad = mock.Mock() 112 ad.adb.shell.side_effect = [ 113 # Return value for SetupWizardExitActivity 114 BypassSetupWizardReturn.ROOT_ADB_FAILS, 115 # Return value for SetupWizardExitActivity after root 116 BypassSetupWizardReturn.UNRECOGNIZED_ERR, 117 # Return value for device_provisioned 118 PROVISIONED_STATE_GOOD 119 ] 120 121 with self.assertRaises(AdbError): 122 utils.bypass_setup_wizard(ad) 123 self.assertTrue(ad.adb.root_adb_called) 124 125 126class BypassSetupWizardReturn: 127 # No complications. Bypass works the first time without issues. 128 NO_COMPLICATIONS = ('Starting: Intent { cmp=com.google.android.setupwizard/' 129 '.SetupWizardExitActivity }') 130 131 # Fail with doesn't need to be skipped/was skipped already. 132 ALREADY_BYPASSED = AdbError('', 'ADB_CMD_OUTPUT:0', 'Error type 3\n' 133 'Error: Activity class', 134 1) 135 # Fail with different error. 136 UNRECOGNIZED_ERR = AdbError('', 'ADB_CMD_OUTPUT:0', 'Error type 4\n' 137 'Error: Activity class', 138 0) 139 # Fail, get root access, then no complications arise. 140 ROOT_ADB_NO_COMP = AdbError('', 'ADB_CMD_OUTPUT:255', 141 'Security exception: Permission Denial: ' 142 'starting Intent { flg=0x10000000 ' 143 'cmp=com.google.android.setupwizard/' 144 '.SetupWizardExitActivity } from null ' 145 '(pid=5045, uid=2000) not exported from uid ' 146 '10000', 0) 147 # Even with root access, the bypass setup wizard doesn't need to be skipped. 148 ROOT_ADB_SKIPPED = AdbError('', 'ADB_CMD_OUTPUT:255', 149 'Security exception: Permission Denial: ' 150 'starting Intent { flg=0x10000000 ' 151 'cmp=com.google.android.setupwizard/' 152 '.SetupWizardExitActivity } from null ' 153 '(pid=5045, uid=2000) not exported from ' 154 'uid 10000', 0) 155 # Even with root access, the bypass setup wizard fails 156 ROOT_ADB_FAILS = AdbError( 157 '', 'ADB_CMD_OUTPUT:255', 158 'Security exception: Permission Denial: starting Intent { ' 159 'flg=0x10000000 cmp=com.google.android.setupwizard/' 160 '.SetupWizardExitActivity } from null (pid=5045, uid=2000) not ' 161 'exported from uid 10000', 0) 162 163 164class ConcurrentActionsTest(unittest.TestCase): 165 """Tests acts.utils.run_concurrent_actions and related functions.""" 166 167 @staticmethod 168 def function_returns_passed_in_arg(arg): 169 return arg 170 171 @staticmethod 172 def function_raises_passed_in_exception_type(exception_type): 173 raise exception_type 174 175 def test_run_concurrent_actions_no_raise_returns_proper_return_values(self): 176 """Tests run_concurrent_actions_no_raise returns in the correct order. 177 178 Each function passed into run_concurrent_actions_no_raise returns the 179 values returned from each individual callable in the order passed in. 180 """ 181 ret_values = utils.run_concurrent_actions_no_raise( 182 lambda: self.function_returns_passed_in_arg('ARG1'), 183 lambda: self.function_returns_passed_in_arg('ARG2'), 184 lambda: self.function_returns_passed_in_arg('ARG3') 185 ) 186 187 self.assertEqual(len(ret_values), 3) 188 self.assertEqual(ret_values[0], 'ARG1') 189 self.assertEqual(ret_values[1], 'ARG2') 190 self.assertEqual(ret_values[2], 'ARG3') 191 192 def test_run_concurrent_actions_no_raise_returns_raised_exceptions(self): 193 """Tests run_concurrent_actions_no_raise returns raised exceptions. 194 195 Instead of allowing raised exceptions to be raised in the main thread, 196 this function should capture the exception and return them in the slot 197 the return value should have been returned in. 198 """ 199 ret_values = utils.run_concurrent_actions_no_raise( 200 lambda: self.function_raises_passed_in_exception_type(IndexError), 201 lambda: self.function_raises_passed_in_exception_type(KeyError) 202 ) 203 204 self.assertEqual(len(ret_values), 2) 205 self.assertEqual(ret_values[0].__class__, IndexError) 206 self.assertEqual(ret_values[1].__class__, KeyError) 207 208 def test_run_concurrent_actions_returns_proper_return_values(self): 209 """Tests run_concurrent_actions returns in the correct order. 210 211 Each function passed into run_concurrent_actions returns the values 212 returned from each individual callable in the order passed in. 213 """ 214 215 ret_values = utils.run_concurrent_actions( 216 lambda: self.function_returns_passed_in_arg('ARG1'), 217 lambda: self.function_returns_passed_in_arg('ARG2'), 218 lambda: self.function_returns_passed_in_arg('ARG3') 219 ) 220 221 self.assertEqual(len(ret_values), 3) 222 self.assertEqual(ret_values[0], 'ARG1') 223 self.assertEqual(ret_values[1], 'ARG2') 224 self.assertEqual(ret_values[2], 'ARG3') 225 226 def test_run_concurrent_actions_raises_exceptions(self): 227 """Tests run_concurrent_actions raises exceptions from given actions.""" 228 with self.assertRaises(KeyError): 229 utils.run_concurrent_actions( 230 lambda: self.function_returns_passed_in_arg('ARG1'), 231 lambda: self.function_raises_passed_in_exception_type(KeyError) 232 ) 233 234 def test_test_concurrent_actions_raises_non_test_failure(self): 235 """Tests test_concurrent_actions raises the given exception.""" 236 with self.assertRaises(KeyError): 237 utils.test_concurrent_actions( 238 lambda: self.function_raises_passed_in_exception_type(KeyError), 239 failure_exceptions=signals.TestFailure 240 ) 241 242 def test_test_concurrent_actions_raises_test_failure(self): 243 """Tests test_concurrent_actions raises the given exception.""" 244 with self.assertRaises(signals.TestFailure): 245 utils.test_concurrent_actions( 246 lambda: self.function_raises_passed_in_exception_type(KeyError), 247 failure_exceptions=KeyError 248 ) 249 250 251if __name__ == '__main__': 252 unittest.main() 253