• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 time
6
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.common_lib.cros import cr50_utils
9from autotest_lib.server.cros.faft.cr50_test import Cr50Test
10
11
12class firmware_Cr50RejectUpdate(Cr50Test):
13    """Verify cr50 rejects certain updates."""
14    version = 1
15    OLD_IMAGE_VER = '0.0.18'
16    # We dont care that it actually matches the device devid. It will be
17    # rejected before the update. This is just one that I picked from google
18    # storage
19    IMAGE_DEVID = '0x1000d059 0x04657208'
20    # No boards use the bid TEST. Use this image to verify cr50 rejects images
21    # with the wrong board id.
22    BID = 'TEST:0000ffff:0000ff00'
23    TEST_PATH = '/tmp/test_image.bin'
24
25
26    def initialize(self, host, cmdline_args, full_args):
27        """Initialize servo and download images"""
28        super(firmware_Cr50RejectUpdate, self).initialize(host, cmdline_args,
29                full_args, restore_cr50_state=True)
30
31        if not hasattr(self, 'cr50'):
32            raise error.TestNAError('Test can only be run on devices with '
33                                    'access to the Cr50 console')
34
35        if 'DBG' in self.cr50.get_version():
36            raise error.TestNAError('Update rules are wonky on DBG images')
37
38        if cr50_utils.GetChipBoardId(host) == cr50_utils.ERASED_CHIP_BID:
39            raise error.TestNAError('Set Cr50 board id to run test')
40
41        self.bid_path = self.download_cr50_debug_image(self.IMAGE_DEVID,
42                self.BID)[0]
43        self.old_path = self.download_cr50_release_image(self.OLD_IMAGE_VER)[0]
44        self.original_path = self.get_saved_cr50_original_path()
45        self.host = host
46        # Wait until cr50 can accept an update, so cr50 update rate limiting
47        # won't interfere with the test.
48        self.cr50.wait_until_update_is_allowed()
49
50
51    def try_update(self, arg, path, err=0, stdout='', wait=True):
52        """Run gsctool with the given image and args. Verify the result
53
54        Args:
55            arg: strings with the gsctool args
56            path: local path to the test image
57            err: The error number
58            stdout: a string that must be included in the cmd stdout
59            wait: Wait for cr50 to have been up for 60 seconds before attempting
60                  the update.
61
62        Raises:
63            TestFail if there is an unexpected result.
64        """
65        # Copy the image to the DUT
66        self.host.send_file(path, self.TEST_PATH)
67
68        # Wait for cr50 to have been up for 60 seconds, so it won't
69        # automatically reject the image.
70        if wait:
71            self.cr50.wait_until_update_is_allowed()
72
73        # Try to update
74        result = self.host.run('gsctool -a %s %s' % (arg, self.TEST_PATH),
75                ignore_status=True, ignore_timeout=True, timeout=60)
76
77        # Check the result
78        stderr = 'Error %d' % err
79        if err and stderr not in result.stderr:
80            raise error.TestFail('"%s" not in "%s"' % (stderr, result.stderr))
81        if stdout and stdout not in result.stdout:
82            raise error.TestFail('"%s" not in "%s"' % (stdout, result.stdout))
83
84
85    def run_once(self):
86        """Verify cr50 rejects certain updates"""
87        # Cr50 rejects a mismatched board id no matter what
88        self.try_update('-u', self.bid_path, err=12)
89        self.try_update('', self.bid_path, err=12)
90
91        # With the '-u' option cr50 rejects any images with old/same header
92        # with 'nothing to do'
93        self.try_update('-u', self.old_path, stdout='nothing to do')
94        self.try_update('-u', self.original_path, stdout='nothing to do')
95
96        # Without '-u' cr50 rejects old headers
97        self.try_update('', self.old_path, err=8)
98
99        # Cr50 will accept images with the same header version if -u is omitted.
100        # original_path is the image already on cr50, so this won't have any
101        # real effect. It will just reboot the device.
102        self.try_update('', self.original_path, stdout='image updated')
103        # After reboot, if the DUT hasn't responded within 45 seconds, it's not
104        # going to.
105        time.sleep(45)
106        if not self.host.is_up_fast():
107            raise error.TestError('DUT did not respond')
108        # Wait for the host to respond to ping. Make sure it responded within
109        # 60 seconds. The whole point of this case is that cr50 will reject
110        # images in the first 60 seconds of boot, so it won't work if cr50
111        # has been up for a while.
112        if self.cr50.gettime() >= 60:
113            raise error.TestError('Cannot complete test. Took >60 seconds for '
114                                  'DUT to come back online')
115        # After any reboot, cr50 will reject images for 60 seconds
116        self.try_update('', self.original_path, err=9, wait=False)
117