1*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2016 The Android Open Source Project 2*288bf522SAndroid Build Coastguard Worker# 3*288bf522SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*288bf522SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*288bf522SAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*288bf522SAndroid Build Coastguard Worker# 7*288bf522SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*288bf522SAndroid Build Coastguard Worker# 9*288bf522SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*288bf522SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*288bf522SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*288bf522SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*288bf522SAndroid Build Coastguard Worker# limitations under the License. 14*288bf522SAndroid Build Coastguard Worker 15*288bf522SAndroid Build Coastguard Workerfrom __future__ import print_function 16*288bf522SAndroid Build Coastguard Worker 17*288bf522SAndroid Build Coastguard Workerimport argparse 18*288bf522SAndroid Build Coastguard Workerimport os 19*288bf522SAndroid Build Coastguard Workerimport unittest 20*288bf522SAndroid Build Coastguard Workerimport fastboot 21*288bf522SAndroid Build Coastguard Workerimport subprocess 22*288bf522SAndroid Build Coastguard Workerimport sys 23*288bf522SAndroid Build Coastguard Worker 24*288bf522SAndroid Build Coastguard Worker# Default values for arguments 25*288bf522SAndroid Build Coastguard Workerdevice_type = "phone" 26*288bf522SAndroid Build Coastguard Worker 27*288bf522SAndroid Build Coastguard Workerclass ShellTest(unittest.TestCase): 28*288bf522SAndroid Build Coastguard Worker @classmethod 29*288bf522SAndroid Build Coastguard Worker def setUpClass(cls): 30*288bf522SAndroid Build Coastguard Worker cls.fastboot = fastboot.FastbootDevice() 31*288bf522SAndroid Build Coastguard Worker 32*288bf522SAndroid Build Coastguard Worker def exists_validvals(self, varname, varlist, validlist): 33*288bf522SAndroid Build Coastguard Worker self.assertIn(varname, varlist) 34*288bf522SAndroid Build Coastguard Worker self.assertIn(varlist[varname], validlist) 35*288bf522SAndroid Build Coastguard Worker return varlist[varname] 36*288bf522SAndroid Build Coastguard Worker 37*288bf522SAndroid Build Coastguard Worker def exists_yes_no(self, varname, varlist): 38*288bf522SAndroid Build Coastguard Worker return self.exists_validvals(varname, varlist, ["yes", "no"]) 39*288bf522SAndroid Build Coastguard Worker 40*288bf522SAndroid Build Coastguard Worker def exists_nonempty(self, varname, varlist): 41*288bf522SAndroid Build Coastguard Worker self.assertIn(varname, varlist) 42*288bf522SAndroid Build Coastguard Worker self.assertGreater(len(varlist[varname]), 0) 43*288bf522SAndroid Build Coastguard Worker return varlist[varname] 44*288bf522SAndroid Build Coastguard Worker 45*288bf522SAndroid Build Coastguard Worker def exists_integer(self, varname, varlist, base=10): 46*288bf522SAndroid Build Coastguard Worker val = 0 47*288bf522SAndroid Build Coastguard Worker self.assertIn(varname, varlist) 48*288bf522SAndroid Build Coastguard Worker try: 49*288bf522SAndroid Build Coastguard Worker val = int(varlist[varname], base) 50*288bf522SAndroid Build Coastguard Worker except ValueError: 51*288bf522SAndroid Build Coastguard Worker self.fail("%s (%s) is not an integer" % (varname, varlist[varname])) 52*288bf522SAndroid Build Coastguard Worker return val 53*288bf522SAndroid Build Coastguard Worker 54*288bf522SAndroid Build Coastguard Worker def get_exists(self, varname): 55*288bf522SAndroid Build Coastguard Worker val = self.fastboot.getvar(varname) 56*288bf522SAndroid Build Coastguard Worker self.assertIsNotNone(val) 57*288bf522SAndroid Build Coastguard Worker return val 58*288bf522SAndroid Build Coastguard Worker 59*288bf522SAndroid Build Coastguard Worker def get_exists_validvals(self, varname, validlist): 60*288bf522SAndroid Build Coastguard Worker val = self.get_exists(varname) 61*288bf522SAndroid Build Coastguard Worker self.assertIn(val, validlist) 62*288bf522SAndroid Build Coastguard Worker return val 63*288bf522SAndroid Build Coastguard Worker 64*288bf522SAndroid Build Coastguard Worker def get_exists_yes_no(self, varname): 65*288bf522SAndroid Build Coastguard Worker return self.get_exists_validvals(varname, ["yes", "no"]) 66*288bf522SAndroid Build Coastguard Worker 67*288bf522SAndroid Build Coastguard Worker def get_exists_nonempty(self, varname): 68*288bf522SAndroid Build Coastguard Worker val = self.get_exists(varname) 69*288bf522SAndroid Build Coastguard Worker self.assertGreater(len(val), 0) 70*288bf522SAndroid Build Coastguard Worker return val 71*288bf522SAndroid Build Coastguard Worker 72*288bf522SAndroid Build Coastguard Worker def get_exists_integer(self, varname, base=10): 73*288bf522SAndroid Build Coastguard Worker val = self.get_exists(varname) 74*288bf522SAndroid Build Coastguard Worker try: 75*288bf522SAndroid Build Coastguard Worker num = int(val, base) 76*288bf522SAndroid Build Coastguard Worker except ValueError: 77*288bf522SAndroid Build Coastguard Worker self.fail("%s (%s) is not an integer" % (varname, val)) 78*288bf522SAndroid Build Coastguard Worker return num 79*288bf522SAndroid Build Coastguard Worker 80*288bf522SAndroid Build Coastguard Worker def get_slotcount(self): 81*288bf522SAndroid Build Coastguard Worker slotcount = 0 82*288bf522SAndroid Build Coastguard Worker try: 83*288bf522SAndroid Build Coastguard Worker val = self.fastboot.getvar("slot-count") 84*288bf522SAndroid Build Coastguard Worker if val != None: 85*288bf522SAndroid Build Coastguard Worker slotcount = int(val) 86*288bf522SAndroid Build Coastguard Worker except ValueError: 87*288bf522SAndroid Build Coastguard Worker self.fail("slot-count (%s) is not an integer" % val) 88*288bf522SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 89*288bf522SAndroid Build Coastguard Worker print("Does not appear to be an A/B device.") 90*288bf522SAndroid Build Coastguard Worker if not slotcount: 91*288bf522SAndroid Build Coastguard Worker print("Does not appear to be an A/B device.") 92*288bf522SAndroid Build Coastguard Worker return slotcount 93*288bf522SAndroid Build Coastguard Worker 94*288bf522SAndroid Build Coastguard Worker def test_getvarall(self): 95*288bf522SAndroid Build Coastguard Worker """Tests that required variables are reported by getvar all""" 96*288bf522SAndroid Build Coastguard Worker 97*288bf522SAndroid Build Coastguard Worker var_all = self.fastboot.getvar_all() 98*288bf522SAndroid Build Coastguard Worker self.exists_nonempty("version-baseband", var_all) 99*288bf522SAndroid Build Coastguard Worker self.exists_nonempty("version-bootloader", var_all) 100*288bf522SAndroid Build Coastguard Worker self.exists_nonempty("product", var_all) 101*288bf522SAndroid Build Coastguard Worker self.exists_yes_no("secure", var_all) 102*288bf522SAndroid Build Coastguard Worker self.exists_yes_no("unlocked", var_all) 103*288bf522SAndroid Build Coastguard Worker self.exists_validvals("off-mode-charge", var_all, ["0", "1"]) 104*288bf522SAndroid Build Coastguard Worker self.assertIn("variant", var_all) 105*288bf522SAndroid Build Coastguard Worker voltage = self.exists_nonempty("battery-voltage", var_all) 106*288bf522SAndroid Build Coastguard Worker if voltage[-2:].lower() == "mv": 107*288bf522SAndroid Build Coastguard Worker voltage = voltage[:-2] 108*288bf522SAndroid Build Coastguard Worker try: 109*288bf522SAndroid Build Coastguard Worker voltnum = float(voltage) 110*288bf522SAndroid Build Coastguard Worker except ValueError: 111*288bf522SAndroid Build Coastguard Worker self.fail("battery-voltage (%s) is not a number" % (varname, voltage)) 112*288bf522SAndroid Build Coastguard Worker self.exists_yes_no("battery-soc-ok", var_all) 113*288bf522SAndroid Build Coastguard Worker maxdl = self.exists_integer("max-download-size", var_all, 16) 114*288bf522SAndroid Build Coastguard Worker self.assertGreater(maxdl, 0) 115*288bf522SAndroid Build Coastguard Worker 116*288bf522SAndroid Build Coastguard Worker if "slot-count" in var_all: 117*288bf522SAndroid Build Coastguard Worker try: 118*288bf522SAndroid Build Coastguard Worker slotcount = int(var_all["slot-count"]) 119*288bf522SAndroid Build Coastguard Worker except ValueError: 120*288bf522SAndroid Build Coastguard Worker self.fail("slot-count (%s) is not an integer" % var_all["slot-count"]) 121*288bf522SAndroid Build Coastguard Worker if slotcount > 1: 122*288bf522SAndroid Build Coastguard Worker # test for A/B variables 123*288bf522SAndroid Build Coastguard Worker slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)] 124*288bf522SAndroid Build Coastguard Worker self.exists_validvals("current-slot", var_all, slots) 125*288bf522SAndroid Build Coastguard Worker 126*288bf522SAndroid Build Coastguard Worker # test for slot metadata 127*288bf522SAndroid Build Coastguard Worker for slot in slots: 128*288bf522SAndroid Build Coastguard Worker self.exists_yes_no("slot-unbootable:"+slot, var_all) 129*288bf522SAndroid Build Coastguard Worker self.exists_yes_no("slot-unbootable:"+slot, var_all) 130*288bf522SAndroid Build Coastguard Worker self.exists_integer("slot-retry-count:"+slot, var_all) 131*288bf522SAndroid Build Coastguard Worker else: 132*288bf522SAndroid Build Coastguard Worker print("This does not appear to be an A/B device.") 133*288bf522SAndroid Build Coastguard Worker 134*288bf522SAndroid Build Coastguard Worker def test_getvar_nonexistent(self): 135*288bf522SAndroid Build Coastguard Worker """Tests behaviour of nonexistent variables.""" 136*288bf522SAndroid Build Coastguard Worker 137*288bf522SAndroid Build Coastguard Worker self.assertIsNone(self.fastboot.getvar("fhqwhgads")) 138*288bf522SAndroid Build Coastguard Worker 139*288bf522SAndroid Build Coastguard Worker def test_getvar(self): 140*288bf522SAndroid Build Coastguard Worker """Tests all variables separately""" 141*288bf522SAndroid Build Coastguard Worker 142*288bf522SAndroid Build Coastguard Worker self.get_exists_nonempty("version-baseband") 143*288bf522SAndroid Build Coastguard Worker self.get_exists_nonempty("version-bootloader") 144*288bf522SAndroid Build Coastguard Worker self.get_exists_nonempty("product") 145*288bf522SAndroid Build Coastguard Worker self.get_exists_yes_no("secure") 146*288bf522SAndroid Build Coastguard Worker self.get_exists_yes_no("unlocked") 147*288bf522SAndroid Build Coastguard Worker self.get_exists_validvals("off-mode-charge", ["0", "1"]) 148*288bf522SAndroid Build Coastguard Worker self.get_exists("variant") 149*288bf522SAndroid Build Coastguard Worker voltage = self.get_exists_nonempty("battery-voltage") 150*288bf522SAndroid Build Coastguard Worker if voltage[-2:].lower() == "mv": 151*288bf522SAndroid Build Coastguard Worker voltage = voltage[:-2] 152*288bf522SAndroid Build Coastguard Worker try: 153*288bf522SAndroid Build Coastguard Worker voltnum = float(voltage) 154*288bf522SAndroid Build Coastguard Worker except ValueError: 155*288bf522SAndroid Build Coastguard Worker self.fail("battery-voltage (%s) is not a number" % voltage) 156*288bf522SAndroid Build Coastguard Worker self.get_exists_yes_no("battery-soc-ok") 157*288bf522SAndroid Build Coastguard Worker maxdl = self.get_exists_integer("max-download-size", 16) 158*288bf522SAndroid Build Coastguard Worker self.assertGreater(maxdl, 0) 159*288bf522SAndroid Build Coastguard Worker 160*288bf522SAndroid Build Coastguard Worker slotcount = self.get_slotcount() 161*288bf522SAndroid Build Coastguard Worker if slotcount > 1: 162*288bf522SAndroid Build Coastguard Worker # test for A/B variables 163*288bf522SAndroid Build Coastguard Worker slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)] 164*288bf522SAndroid Build Coastguard Worker self.get_exists_validvals("current-slot", slots) 165*288bf522SAndroid Build Coastguard Worker 166*288bf522SAndroid Build Coastguard Worker # test for slot metadata 167*288bf522SAndroid Build Coastguard Worker for slot in slots: 168*288bf522SAndroid Build Coastguard Worker self.get_exists_yes_no("slot-unbootable:"+slot) 169*288bf522SAndroid Build Coastguard Worker self.get_exists_yes_no("slot-successful:"+slot) 170*288bf522SAndroid Build Coastguard Worker self.get_exists_integer("slot-retry-count:"+slot) 171*288bf522SAndroid Build Coastguard Worker 172*288bf522SAndroid Build Coastguard Worker def test_setactive(self): 173*288bf522SAndroid Build Coastguard Worker """Tests that A/B devices can switch to each slot, and the change persists over a reboot.""" 174*288bf522SAndroid Build Coastguard Worker # Test invalid if not an A/B device 175*288bf522SAndroid Build Coastguard Worker slotcount = self.get_slotcount() 176*288bf522SAndroid Build Coastguard Worker if not slotcount: 177*288bf522SAndroid Build Coastguard Worker return 178*288bf522SAndroid Build Coastguard Worker 179*288bf522SAndroid Build Coastguard Worker maxtries = 0 180*288bf522SAndroid Build Coastguard Worker slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)] 181*288bf522SAndroid Build Coastguard Worker for slot in slots: 182*288bf522SAndroid Build Coastguard Worker self.fastboot.set_active(slot) 183*288bf522SAndroid Build Coastguard Worker self.assertEqual(slot, self.fastboot.getvar("current-slot")) 184*288bf522SAndroid Build Coastguard Worker self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot)) 185*288bf522SAndroid Build Coastguard Worker self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot)) 186*288bf522SAndroid Build Coastguard Worker retry = self.get_exists_integer("slot-retry-count:"+slot) 187*288bf522SAndroid Build Coastguard Worker if maxtries == 0: 188*288bf522SAndroid Build Coastguard Worker maxtries = retry 189*288bf522SAndroid Build Coastguard Worker else: 190*288bf522SAndroid Build Coastguard Worker self.assertEqual(maxtries, retry) 191*288bf522SAndroid Build Coastguard Worker self.fastboot.reboot(True) 192*288bf522SAndroid Build Coastguard Worker self.assertEqual(slot, self.fastboot.getvar("current-slot")) 193*288bf522SAndroid Build Coastguard Worker self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot)) 194*288bf522SAndroid Build Coastguard Worker self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot)) 195*288bf522SAndroid Build Coastguard Worker retry = self.get_exists_integer("slot-retry-count:"+slot) 196*288bf522SAndroid Build Coastguard Worker if maxtries == 0: 197*288bf522SAndroid Build Coastguard Worker maxtries = retry 198*288bf522SAndroid Build Coastguard Worker else: 199*288bf522SAndroid Build Coastguard Worker self.assertEqual(maxtries, retry) 200*288bf522SAndroid Build Coastguard Worker 201*288bf522SAndroid Build Coastguard Worker def test_hasslot(self): 202*288bf522SAndroid Build Coastguard Worker """Tests that A/B devices report partitions that have slots.""" 203*288bf522SAndroid Build Coastguard Worker # Test invalid if not an A/B device 204*288bf522SAndroid Build Coastguard Worker if not self.get_slotcount(): 205*288bf522SAndroid Build Coastguard Worker return 206*288bf522SAndroid Build Coastguard Worker 207*288bf522SAndroid Build Coastguard Worker self.assertEqual("yes", self.fastboot.getvar("has-slot:system")) 208*288bf522SAndroid Build Coastguard Worker self.assertEqual("yes", self.fastboot.getvar("has-slot:boot")) 209*288bf522SAndroid Build Coastguard Worker 210*288bf522SAndroid Build Coastguard Worker # Additional partition on AndroidThings (IoT) devices 211*288bf522SAndroid Build Coastguard Worker if device_type == "iot": 212*288bf522SAndroid Build Coastguard Worker self.assertEqual("yes", self.fastboot.getvar("has-slot:oem")) 213*288bf522SAndroid Build Coastguard Worker 214*288bf522SAndroid Build Coastguard Workerif __name__ == '__main__': 215*288bf522SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 216*288bf522SAndroid Build Coastguard Worker parser.add_argument("--device-type", default="phone", 217*288bf522SAndroid Build Coastguard Worker help="Type of device ('phone' or 'iot').") 218*288bf522SAndroid Build Coastguard Worker parser.add_argument("extra_args", nargs="*") 219*288bf522SAndroid Build Coastguard Worker args = parser.parse_args() 220*288bf522SAndroid Build Coastguard Worker 221*288bf522SAndroid Build Coastguard Worker if args.device_type.lower() not in ("phone", "iot"): 222*288bf522SAndroid Build Coastguard Worker raise ValueError("Unsupported device type '%s'." % args.device_type) 223*288bf522SAndroid Build Coastguard Worker device_type = args.device_type.lower() 224*288bf522SAndroid Build Coastguard Worker 225*288bf522SAndroid Build Coastguard Worker sys.argv[1:] = args.extra_args 226*288bf522SAndroid Build Coastguard Worker unittest.main(verbosity=3) 227