1# Copyright 2018 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import pprint
6import logging
7
8from autotest_lib.client.common_lib import error
9from autotest_lib.server.cros.faft.cr50_test import Cr50Test
10
11
12class firmware_Cr50CheckCap(Cr50Test):
13    """Verify cr50 capabilities"""
14    version = 1
15
16    # The default requirements for these capabilities change between prod and
17    # prepvt images. Make sure they match the expected values.
18    SPECIAL_CAPS = ['OpenNoDevMode', 'OpenFromUSB']
19    EXPECTED_REQ_PREPVT = 'Always'
20    EXPECTED_REQ_PROD = 'IfOpened'
21    PASSWORD = 'Password'
22
23    def check_cap_command(self, command, enable_factory, reset_caps):
24        """Verify the cr50 cap response after running the given command"""
25        self.cr50.send_command(command)
26        caps = self.cr50.get_cap_dict()
27        logging.info(caps)
28        in_factory_mode, is_reset = self.cr50.get_cap_overview(caps)
29        if reset_caps and not is_reset:
30            raise error.TestFail('%r did not reset capabilities' % command)
31        if enable_factory and not in_factory_mode:
32            raise error.TestFail('%r did not enable factory mode' % command)
33
34
35    def check_cap_req(self, cap_dict, cap, expected_req):
36        """Check the current cap requirement against the expected requirement"""
37        req = cap_dict[cap]
38        if req != expected_req:
39            raise error.TestFail('%r should be %r not %r' % (cap, expected_req,
40                                                             req))
41
42
43    def check_cap_accessiblity(self, ccd_level, cap_setting, expect_accessible):
44        """Check setting cap requirements restricts the capabilities correctly.
45
46        Set each ccd capability to cap_setting. Set the ccd state to ccd_level.
47        Then verify the capability accessiblity matches expect_accessible.
48
49        Args:
50            ccd_level: a ccd state level: 'lock', 'unlock', or 'open'.
51            cap_setting: A ccd cap setting: 'IfOpened', 'Always', or
52                         'UnlessLocked'.
53            expect_accessible: True if capabilities should be accessible
54
55        Raises:
56            TestFail if expect_accessible doesn't match the accessibility state.
57        """
58        # Run testlab open, so we won't have to do physical presence stuff.
59        self.cr50.send_command('ccd testlab open')
60
61        # Set all capabilities to cap_setting
62        caps = self.cr50.get_cap_dict().keys()
63        cap_settings = {}
64        for cap in caps:
65            cap_settings[cap] = cap_setting
66        self.cr50.set_caps(cap_settings)
67
68        # Set the ccd state to ccd_level
69        self.cr50.set_ccd_level(ccd_level, self.PASSWORD)
70        cap_dict = self.cr50.get_cap_dict()
71        logging.info('Cap state with console %r req %r:\n%s', ccd_level,
72                     cap_setting, pprint.pformat(cap_dict))
73
74        # Check the accessiblity
75        for cap, cap_info in cap_dict.iteritems():
76            if cap_info[self.cr50.CAP_IS_ACCESSIBLE] != expect_accessible:
77                raise error.TestFail('%r is %raccessible' % (cap,
78                                     'not ' if expect_accessible else ''))
79
80
81    def run_once(self, ccd_open_restricted=False):
82        """Check cr50 capabilities work correctly."""
83        self.fast_open(enable_testlab=True)
84
85        # Make sure factory reset sets all capabilites to Always
86        self.check_cap_command('ccd reset factory', True, False)
87
88        # Make sure ccd reset sets all capabilites to Default
89        self.check_cap_command('ccd reset', False, True)
90
91        expected_req = (self.EXPECTED_REQ_PROD if ccd_open_restricted else
92                        self.EXPECTED_REQ_PREPVT)
93        cap_dict = self.cr50.get_cap_dict(info=self.cr50.CAP_REQ)
94        # Make sure the special ccd capabilities match ccd_open_restricted
95        for cap in self.SPECIAL_CAPS:
96            self.check_cap_req(cap_dict, cap, expected_req)
97
98        # Set the password so we can change the ccd level from the console
99        self.cr50.send_command('ccd testlab open')
100        self.cr50.send_command('ccd reset')
101        self.set_ccd_password(self.PASSWORD)
102
103        # Make sure ccd accessiblity behaves as expected based on the cap
104        # settings and the ccd state.
105        self.check_cap_accessiblity('open', 'IfOpened', True)
106        self.check_cap_accessiblity('open', 'UnlessLocked', True)
107        self.check_cap_accessiblity('open', 'Always', True)
108
109        self.check_cap_accessiblity('unlock', 'IfOpened', False)
110        self.check_cap_accessiblity('unlock', 'UnlessLocked', True)
111        self.check_cap_accessiblity('unlock', 'Always', True)
112
113        self.check_cap_accessiblity('lock', 'IfOpened', False)
114        self.check_cap_accessiblity('lock', 'UnlessLocked', False)
115        self.check_cap_accessiblity('lock', 'Always', True)
116