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