1# Copyright (c) 2014 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.
4import logging
5import time
6
7from autotest_lib.client.common_lib import error
8from autotest_lib.server import test
9
10
11class platform_ServoPowerStateController(test.test):
12    """Test servo can power on and off DUT in recovery and non-recovery mode."""
13    version = 1
14
15
16    def initialize(self, host):
17        """Initialize DUT for testing."""
18        pass
19
20
21    def cleanup(self):
22        """Clean up DUT after servo actions."""
23        if not self.host.ssh_ping():
24            # Power off, then power on DUT from internal storage.
25            self.controller.power_off()
26            self.host.servo.switch_usbkey('off')
27            self.controller.power_on(self.controller.REC_OFF)
28
29
30    def assert_dut_on(self, rec_on=False):
31        """Confirm DUT is powered on, claim test failure if DUT is off.
32
33        @param rec_on: True if DUT should boot from external USB stick as in
34                       recovery mode.
35
36        @raise TestFail: If DUT is off or DUT boot from wrong source.
37        """
38        if not self.host.wait_up(timeout=300):
39            raise error.TestFail('power_state:%s did not turn DUT on.' %
40                                 ('rec' if rec_on else 'on'))
41
42        # Check boot source. Raise TestFail if DUT boot from wrong source.
43        boot_from_usb = self.host.is_boot_from_usb()
44        if boot_from_usb != rec_on:
45            boot_source = ('USB' if boot_from_usb else
46                           'non-removable storage')
47            raise error.TestFail('power_state:%s booted from %s.' %
48                                 ('rec' if rec_on else 'on', boot_source))
49
50
51    def assert_dut_off(self, error_message):
52        """Confirm DUT is off and does not turn back on after 30 seconds.
53
54        @param error_message: Error message to raise if DUT stays on.
55        @raise TestFail: If DUT stays on.
56        """
57        if not self.host.ping_wait_down(timeout=10):
58            raise error.TestFail(error_message)
59
60        if self.host.ping_wait_up(timeout=30):
61            raise error.TestFail('%s. %s' % (error_message, 'DUT turns back on'
62                                             ' after it is turned off.'))
63
64
65    def test_with_usb_plugged_in(self):
66        """Run test when USB stick is plugged in to servo."""
67        logging.info('Power off DUT')
68        self.controller.power_off()
69        self.assert_dut_off('power_state:off did not turn DUT off.')
70
71        logging.info('Power DUT on in recovery mode, DUT shall boot from USB.')
72        self.host.servo.switch_usbkey('off')
73        self.controller.power_on(self.controller.REC_ON)
74        self.assert_dut_off('power_state:rec didn\'t stay at recovery screen.')
75
76        self.host.servo.switch_usbkey('dut')
77        time.sleep(30)
78        self.assert_dut_on(rec_on=True)
79
80        logging.info('Power off DUT which is up in recovery mode.')
81        self.controller.power_off()
82        self.assert_dut_off('power_state:off failed after boot from external '
83                            'USB stick.')
84
85        logging.info('Power DUT off in recovery mode without booting.')
86        self.host.servo.switch_usbkey('off')
87        self.controller.power_on(self.controller.REC_ON)
88        self.controller.power_off()
89        self.assert_dut_off('power_state:off failed at recovery screen ')
90
91        # Power DUT on in non-recovery mode with USB stick plugged in.
92        # DUT shall boot from internal storage.
93        logging.info('Power on DUT in non-recovery mode.')
94        self.host.servo.switch_usbkey('dut')
95        self.controller.power_on(self.controller.REC_OFF)
96        self.assert_dut_on()
97        self.host.servo.switch_usbkey('off')
98
99
100    def test_with_usb_unplugged(self):
101        """Run test when USB stick is not plugged in servo."""
102        # Power off DUT regardless its current status.
103        logging.info('Power off DUT.')
104        self.controller.power_off()
105        self.assert_dut_off('power_state:off did not turn DUT off.')
106
107        # Try to power off the DUT again, make sure the DUT stays off.
108        logging.info('Power off DUT which is already off.')
109        self.controller.power_off()
110        self.assert_dut_off('power_state:off turned DUT on.')
111
112        # USB stick should be unplugged before the test.
113        self.host.servo.switch_usbkey('off')
114
115        logging.info('Power on in non-recovery mode.')
116        self.controller.power_on(self.controller.REC_OFF)
117        self.assert_dut_on(rec_on=False)
118
119        logging.info('Power DUT off and on without delay. DUT should be '
120                     'on after power_on is completed.')
121        self.controller.power_off()
122        self.controller.power_on(self.controller.REC_OFF)
123        self.assert_dut_on(rec_on=False)
124
125        logging.info('Power off DUT which is up in non-recovery mode.')
126        self.controller.power_off()
127        self.assert_dut_off('power_state:off failed after boot from '
128                            'internal storage.')
129
130        logging.info('Power DUT off and reset. DUT should be on after '
131                     'reset is completed.')
132        self.controller.reset()
133        self.assert_dut_on(rec_on=False)
134
135        logging.info('Reset DUT when it\'s on. DUT should be on after '
136                     'reset is completed.')
137        boot_id = self.host.get_boot_id()
138        self.controller.reset()
139        self.assert_dut_on(rec_on=False)
140        new_boot_id = self.host.get_boot_id()
141        if not new_boot_id or boot_id == new_boot_id:
142            raise error.TestFail('power_state:reset failed to reboot DUT.')
143
144
145    def run_once(self, host, usb_available=True):
146        """Run the test.
147
148        @param host: host object of tested DUT.
149        @param usb_plugged_in: True if USB stick is plugged in servo.
150        """
151        self.host = host
152        self.controller = host.servo.get_power_state_controller()
153
154        self.test_with_usb_unplugged()
155        if usb_available:
156            self.test_with_usb_plugged_in()
157