1# 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
16import os
17import unittest
18import fastboot
19import subprocess
20
21class ShellTest(unittest.TestCase):
22    def __init__(self, *args, **kwargs):
23        super(ShellTest, self).__init__(*args, **kwargs)
24        self.fastboot = fastboot.FastbootDevice()
25
26    def exists_validvals(self, varname, varlist, validlist):
27        self.assertIn(varname, varlist)
28        self.assertIn(varlist[varname], validlist)
29        return varlist[varname]
30
31    def exists_yes_no(self, varname, varlist):
32        return self.exists_validvals(varname, varlist, ["yes", "no"])
33
34    def exists_nonempty(self, varname, varlist):
35        self.assertIn(varname, varlist)
36        self.assertGreater(len(varlist[varname]), 0)
37        return varlist[varname]
38
39    def exists_integer(self, varname, varlist, base=10):
40        val = 0
41        self.assertIn(varname, varlist)
42        try:
43            val = int(varlist[varname], base)
44        except ValueError:
45            self.fail("%s (%s) is not an integer" % (varname, varlist[varname]))
46        return val
47
48    def get_exists(self, varname):
49        val = self.fastboot.getvar(varname)
50        self.assertIsNotNone(val)
51        return val
52
53    def get_exists_validvals(self, varname, validlist):
54        val = self.get_exists(varname)
55        self.assertIn(val, validlist)
56        return val
57
58    def get_exists_yes_no(self, varname):
59        return self.get_exists_validvals(varname, ["yes", "no"])
60
61    def get_exists_nonempty(self, varname):
62        val = self.get_exists(varname)
63        self.assertGreater(len(val), 0)
64        return val
65
66    def get_exists_integer(self, varname, base=10):
67        val = self.get_exists(varname)
68        try:
69            num = int(val, base)
70        except ValueError:
71            self.fail("%s (%s) is not an integer" % (varname, val))
72        return num
73
74    def test_getvarall(self):
75        """Tests that required variables are reported by getvar all"""
76
77        var_all = self.fastboot.getvar_all()
78        self.exists_nonempty("version-baseband", var_all)
79        self.exists_nonempty("version-bootloader", var_all)
80        self.exists_nonempty("product", var_all)
81        self.exists_yes_no("secure", var_all)
82        self.exists_yes_no("unlocked", var_all)
83        self.exists_validvals("off-mode-charge", var_all, ["0", "1"])
84        self.assertIn("variant", var_all)
85        voltage = self.exists_nonempty("battery-voltage", var_all)
86        if voltage[-2:].lower() == "mv":
87            voltage = voltage[:-2]
88        try:
89            voltnum = float(voltage)
90        except ValueError:
91            self.fail("battery-voltage (%s) is not a number" % (varname, voltage))
92        self.exists_yes_no("battery-soc-ok", var_all)
93        maxdl = self.exists_integer("max-download-size", var_all, 16)
94        self.assertGreater(maxdl, 0)
95
96        if "slot-count" in var_all:
97            try:
98                slotcount = int(var_all["slot-count"])
99            except ValueError:
100                self.fail("slot-count (%s) is not an integer" % var_all["slot-count"])
101            if slotcount > 1:
102                # test for A/B variables
103                slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
104                self.exists_validvals("current-slot", var_all, slots)
105
106                # test for slot metadata
107                for slot in slots:
108                    self.exists_yes_no("slot-unbootable:"+slot, var_all)
109                    self.exists_yes_no("slot-unbootable:"+slot, var_all)
110                    self.exists_integer("slot-retry-count:"+slot, var_all)
111            else:
112                print "This does not appear to be an A/B device."
113
114    def test_getvar_nonexistent(self):
115        """Tests behaviour of nonexistent variables."""
116
117        self.assertIsNone(self.fastboot.getvar("fhqwhgads"))
118
119    def test_getvar(self):
120        """Tests all variables separately"""
121
122        self.get_exists_nonempty("version-baseband")
123        self.get_exists_nonempty("version-bootloader")
124        self.get_exists_nonempty("product")
125        self.get_exists_yes_no("secure")
126        self.get_exists_yes_no("unlocked")
127        self.get_exists_validvals("off-mode-charge", ["0", "1"])
128        self.get_exists("variant")
129        voltage = self.get_exists_nonempty("battery-voltage")
130        if voltage[-2:].lower() == "mv":
131            voltage = voltage[:-2]
132        try:
133            voltnum = float(voltage)
134        except ValueError:
135            self.fail("battery-voltage (%s) is not a number" % voltage)
136        self.get_exists_yes_no("battery-soc-ok")
137        maxdl = self.get_exists_integer("max-download-size", 16)
138        self.assertGreater(maxdl, 0)
139
140        slotcount = 0
141        try:
142            slotcountString = self.fastboot.getvar("slot-count")
143            if slotcountString != None:
144                slotcount = int(slotcountString)
145        except ValueError:
146            self.fail("slot-count (%s) is not an integer" % slotcountString)
147        if slotcount  > 1:
148            # test for A/B variables
149            slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
150            self.get_exists_validvals("current-slot", slots)
151
152            # test for slot metadata
153            for slot in slots:
154                self.get_exists_yes_no("slot-unbootable:"+slot)
155                self.get_exists_yes_no("slot-successful:"+slot)
156                self.get_exists_integer("slot-retry-count:"+slot)
157        else:
158            print "This does not appear to be an A/B device."
159
160    def test_setactive(self):
161        """Tests that A/B devices can switch to each slot, and the change persists over a reboot."""
162
163        slotcount = 0
164        try:
165            val = self.fastboot.getvar("slot-count")
166            if val != None:
167                slotcount = int(val)
168        except ValueError:
169            self.fail("slot-count (%s) is not an integer" % val)
170        except subprocess.CalledProcessError:
171            print "Does not appear to be an A/B device."
172        maxtries = 0
173        if slotcount > 1:
174            slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
175            for slot in slots:
176                self.fastboot.set_active(slot)
177                self.assertEqual(slot, self.fastboot.getvar("current-slot"))
178                self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
179                self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
180                retry = self.get_exists_integer("slot-retry-count:"+slot)
181                if maxtries == 0:
182                   maxtries = retry
183                else:
184                   self.assertEqual(maxtries, retry)
185                self.fastboot.reboot(True)
186                self.assertEqual(slot, self.fastboot.getvar("current-slot"))
187                self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
188                self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
189                retry = self.get_exists_integer("slot-retry-count:"+slot)
190                if maxtries == 0:
191                   maxtries = retry
192                else:
193                   self.assertEqual(maxtries, retry)
194        else:
195            print "Does not appear to be an A/B device."
196
197if __name__ == '__main__':
198    unittest.main(verbosity=3)
199