• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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 logging
6import re
7
8from collections import defaultdict
9
10from autotest_lib.client.common_lib import error
11from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
12
13class firmware_PDProtocol(FirmwareTest):
14    """
15    Servo based USB PD protocol test.
16
17    A charger must be connected to the DUT for this test.
18
19    This test checks that when an appropriate zinger charger is connected that
20    the PD is properly negotiated in dev mode and when booted from a test image
21    through recovery that the PD is not negotiated.
22
23    Example:
24    PD Successfully negotiated
25    - ectool usbpdpower should output Charger PD
26
27    PD not negotiated
28    - ectool usbpdpower should not output Charger PD
29
30    """
31    version = 1
32
33    NEGOTIATED_PATTERN = 'Charger PD'
34    PD_NOT_SUPPORTED_PATTERN = 'INVALID_COMMAND'
35
36    ECTOOL_CMD_DICT = defaultdict(lambda: 'ectool usbpdpower')
37
38    def initialize(self, host, cmdline_args):
39        super(firmware_PDProtocol, self).initialize(host, cmdline_args)
40
41        self.ECTOOL_CMD_DICT['samus'] = 'ectool --dev=1 usbpdpower'
42
43        self.current_board = self.servo.get_board();
44
45        self.check_if_pd_supported()
46        self.assert_test_image_in_usb_disk()
47        self.switcher.setup_mode('dev')
48        self.setup_usbkey(usbkey=True, host=False)
49
50        self.original_dev_boot_usb = self.faft_client.system.get_dev_boot_usb()
51        logging.info('Original dev_boot_usb value: %s',
52                     str(self.original_dev_boot_usb))
53
54    def cleanup(self):
55        self.ensure_internal_device_boot()
56        super(firmware_PDProtocol, self).cleanup()
57
58    def check_if_pd_supported(self):
59        """ Checks if the DUT responds to ectool usbpdpower and skips the test
60        if it isn't supported on the device.
61        """
62        output = self.run_command(self.ECTOOL_CMD_DICT[self.current_board])
63
64        if (not output or
65            self.check_ec_output(output, self.PD_NOT_SUPPORTED_PATTERN)):
66            raise error.TestNAError("PD not supported skipping test.")
67
68    def ensure_internal_device_boot(self):
69        """Ensure internal device boot; if not, reboot into it.
70
71        If not, it may be a test failure during step 2 or 3, try to reboot
72        and press Ctrl-D to internal device boot.
73        """
74        if self.faft_client.system.is_removable_device_boot():
75            logging.info('Reboot into internal disk...')
76            self.faft_client.system.set_dev_boot_usb(self.original_dev_boot_usb)
77            self.switcher.mode_aware_reboot()
78
79        self.check_state((self.checkers.dev_boot_usb_checker,
80                          False,
81                          'Did not boot from internal disk.'))
82
83    def boot_to_recovery(self):
84        """Boot device into recovery mode."""
85        logging.info('Reboot into Recovery...')
86        self.assert_test_image_in_usb_disk()
87        self.switcher.reboot_to_mode(to_mode='rec')
88
89        self.check_state((self.checkers.crossystem_checker,
90                          {'mainfw_type': 'recovery'}))
91
92    def run_command(self, command):
93        """Runs the specified command and returns the output
94        as a list of strings.
95
96        @param command: The command to run on the DUT
97        @return A list of strings of the command output
98        """
99        logging.info('Command to run: %s', command)
100
101        output = self.faft_client.system.run_shell_command_get_output(command)
102
103        logging.info('Command output: %s', output)
104
105        return output
106
107    def check_ec_output(self, output, pattern):
108        """Checks if any line in the output matches the given pattern.
109
110        @param output: A list of strings containg the output to search
111        @param pattern: The regex to search the output for
112
113        @return True upon first match found or False
114        """
115        logging.info('Checking %s for %s.', output, pattern)
116
117        for line in output:
118            if bool(re.search(pattern, line)):
119                return True
120
121        return False
122
123
124    def run_once(self):
125        self.ensure_internal_device_boot()
126        output = self.run_command(self.ECTOOL_CMD_DICT[self.current_board])
127
128        if not self.check_ec_output(output, self.NEGOTIATED_PATTERN):
129            raise error.TestFail(
130                'ectool usbpdpower output %s did not match %s',
131                (output, self.NEGOTIATED_PATTERN))
132
133
134        self.boot_to_recovery()
135        output = self.run_command(self.ECTOOL_CMD_DICT[self.current_board])
136
137        if self.check_ec_output(output, self.NEGOTIATED_PATTERN):
138            raise error.TestFail(
139                'ectool usbpdpower output %s matched %s',
140                (output, self.NEGOTIATED_PATTERN))
141
142