1#!/usr/bin/python
2# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import mox
7import pexpect
8import unittest
9
10import dli
11
12import rpm_controller
13
14import common
15from autotest_lib.site_utils.rpm_control_system import utils
16
17
18class TestRPMControllerQueue(mox.MoxTestBase):
19    """Test request can be queued and processed in controller.
20    """
21
22    def setUp(self):
23        super(TestRPMControllerQueue, self).setUp()
24        self.rpm = rpm_controller.SentryRPMController('chromeos-rack1-host8')
25        self.powerunit_info = utils.PowerUnitInfo(
26                device_hostname='chromos-rack1-host8',
27                powerunit_hostname='chromeos-rack1-rpm1',
28                powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM,
29                outlet='.A100',
30                hydra_hostname=None)
31
32
33    def testQueueRequest(self):
34        """Should create a new process to handle request."""
35        new_state = 'ON'
36        process = self.mox.CreateMockAnything()
37        rpm_controller.multiprocessing.Process = self.mox.CreateMockAnything()
38        rpm_controller.multiprocessing.Process(target=mox.IgnoreArg(),
39                args=mox.IgnoreArg()).AndReturn(process)
40        process.start()
41        process.join()
42        self.mox.ReplayAll()
43        self.assertFalse(self.rpm.queue_request(self.powerunit_info, new_state))
44        self.mox.VerifyAll()
45
46
47class TestSentryRPMController(mox.MoxTestBase):
48    """Test SentryRPMController."""
49
50
51    def setUp(self):
52        super(TestSentryRPMController, self).setUp()
53        self.ssh = self.mox.CreateMockAnything()
54        rpm_controller.pexpect.spawn = self.mox.CreateMockAnything()
55        rpm_controller.pexpect.spawn(mox.IgnoreArg()).AndReturn(self.ssh)
56        self.rpm = rpm_controller.SentryRPMController('chromeos-rack1-host8')
57        self.powerunit_info = utils.PowerUnitInfo(
58                device_hostname='chromos-rack1-host8',
59                powerunit_hostname='chromeos-rack1-rpm1',
60                powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM,
61                outlet='.A100',
62                hydra_hostname=None)
63
64
65    def testSuccessfullyChangeOutlet(self):
66        """Should return True if change was successful."""
67        prompt = 'Switched CDU:'
68        password = 'admn'
69        new_state = 'ON'
70        self.ssh.expect('Password:', timeout=60)
71        self.ssh.sendline(password)
72        self.ssh.expect(prompt, timeout=60)
73        self.ssh.sendline('%s %s' % (new_state, self.powerunit_info.outlet))
74        self.ssh.expect('Command successful', timeout=60)
75        self.ssh.sendline('logout')
76        self.ssh.close(force=True)
77        self.mox.ReplayAll()
78        self.assertTrue(self.rpm.set_power_state(
79                self.powerunit_info, new_state))
80        self.mox.VerifyAll()
81
82
83    def testUnsuccessfullyChangeOutlet(self):
84        """Should return False if change was unsuccessful."""
85        prompt = 'Switched CDU:'
86        password = 'admn'
87        new_state = 'ON'
88        self.ssh.expect('Password:', timeout=60)
89        self.ssh.sendline(password)
90        self.ssh.expect(prompt, timeout=60)
91        self.ssh.sendline('%s %s' % (new_state, self.powerunit_info.outlet))
92        self.ssh.expect('Command successful',
93                        timeout=60).AndRaise(pexpect.TIMEOUT('Timed Out'))
94        self.ssh.sendline('logout')
95        self.ssh.close(force=True)
96        self.mox.ReplayAll()
97        self.assertFalse(self.rpm.set_power_state(self.powerunit_info, new_state))
98        self.mox.VerifyAll()
99
100
101class TestWebPoweredRPMController(mox.MoxTestBase):
102    """Test WebPoweredRPMController."""
103
104
105    def setUp(self):
106        super(TestWebPoweredRPMController, self).setUp()
107        self.dli_ps = self.mox.CreateMock(dli.powerswitch)
108        hostname = 'chromeos-rack8a-rpm1'
109        self.web_rpm = rpm_controller.WebPoweredRPMController(hostname,
110                                                              self.dli_ps)
111        outlet = 8
112        dut = 'chromeos-rack8a-host8'
113        # Outlet statuses are in the format "u'ON'"
114        initial_state = 'u\'ON\''
115        self.test_status_list_initial = [[outlet, dut, initial_state]]
116        self.powerunit_info = utils.PowerUnitInfo(
117                device_hostname=dut,
118                powerunit_hostname=hostname,
119                powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM,
120                outlet=outlet,
121                hydra_hostname=None)
122
123
124    def testSuccessfullyChangeOutlet(self):
125        """Should return True if change was successful."""
126        test_status_list_final = [[8, 'chromeos-rack8a-host8','u\'OFF\'']]
127        self.dli_ps.statuslist().AndReturn(self.test_status_list_initial)
128        self.dli_ps.off(8)
129        self.dli_ps.statuslist().AndReturn(test_status_list_final)
130        self.mox.ReplayAll()
131        self.assertTrue(self.web_rpm.set_power_state(
132                self.powerunit_info, 'OFF'))
133        self.mox.VerifyAll()
134
135
136    def testUnsuccessfullyChangeOutlet(self):
137        """Should return False if Outlet State does not change."""
138        test_status_list_final = [[8, 'chromeos-rack8a-host8','u\'ON\'']]
139        self.dli_ps.statuslist().AndReturn(self.test_status_list_initial)
140        self.dli_ps.off(8)
141        self.dli_ps.statuslist().AndReturn(test_status_list_final)
142        self.mox.ReplayAll()
143        self.assertFalse(self.web_rpm.set_power_state(
144                self.powerunit_info, 'OFF'))
145        self.mox.VerifyAll()
146
147
148    def testNoOutlet(self):
149        """Should return False if DUT hostname is not on the RPM device."""
150        self.powerunit_info.outlet=None
151        self.assertFalse(self.web_rpm.set_power_state(
152                self.powerunit_info, 'OFF'))
153
154
155class TestCiscoPOEController(mox.MoxTestBase):
156    """Test CiscoPOEController."""
157
158
159    STREAM_WELCOME = 'This is a POE switch.\n\nUser Name:'
160    STREAM_PWD = 'Password:'
161    STREAM_DEVICE = '\nchromeos2-poe-sw8#'
162    STREAM_CONFIG = 'chromeos2-poe-sw8(config)#'
163    STREAM_CONFIG_IF = 'chromeos2-poe-sw8(config-if)#'
164    STREAM_STATUS = ('\n                                             '
165                     'Flow Link          Back   Mdix\n'
166                     'Port     Type         Duplex  Speed Neg      '
167                     'ctrl State       Pressure Mode\n'
168                     '-------- ------------ ------  ----- -------- '
169                     '---- ----------- -------- -------\n'
170                     'fa32     100M-Copper  Full    100   Enabled  '
171                     'Off  Up          Disabled Off\n')
172    SERVO = 'chromeos1-rack3-host12-servo'
173    SWITCH = 'chromeos2-poe-switch8'
174    PORT = 'fa32'
175    POWERUNIT_INFO = utils.PowerUnitInfo(
176            device_hostname=PORT,
177            powerunit_hostname=SERVO,
178            powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.POE,
179            outlet=PORT,
180            hydra_hostname=None)
181
182
183    def setUp(self):
184        super(TestCiscoPOEController, self).setUp()
185        self.mox.StubOutWithMock(pexpect.spawn, '_spawn')
186        self.mox.StubOutWithMock(pexpect.spawn, 'read_nonblocking')
187        self.mox.StubOutWithMock(pexpect.spawn, 'sendline')
188        self.poe = rpm_controller.CiscoPOEController(self.SWITCH)
189        pexpect.spawn._spawn(mox.IgnoreArg(), mox.IgnoreArg())
190        pexpect.spawn.read_nonblocking(
191                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_WELCOME)
192        pexpect.spawn.sendline(self.poe._username)
193        pexpect.spawn.read_nonblocking(
194                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_PWD)
195        pexpect.spawn.sendline(self.poe._password)
196        pexpect.spawn.read_nonblocking(
197                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_DEVICE)
198
199
200    def testLogin(self):
201        """Test we can log into the switch."""
202        self.mox.ReplayAll()
203        self.assertNotEqual(self.poe._login(), None)
204        self.mox.VerifyAll()
205
206
207    def _EnterConfigurationHelper(self, success=True):
208        """A helper function for testing entering configuration terminal.
209
210        @param success: True if we want the process to pass, False if we
211                        want it to fail.
212        """
213        pexpect.spawn.sendline('configure terminal')
214        pexpect.spawn.read_nonblocking(
215                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_CONFIG)
216        pexpect.spawn.sendline('interface %s' % self.PORT)
217        if success:
218            pexpect.spawn.read_nonblocking(
219                    mox.IgnoreArg(),
220                    mox.IgnoreArg()).AndReturn(self.STREAM_CONFIG_IF)
221        else:
222            self.mox.StubOutWithMock(pexpect.spawn, '__str__')
223            exception = pexpect.TIMEOUT(
224                    'Could not enter configuration terminal.')
225            pexpect.spawn.read_nonblocking(
226                    mox.IgnoreArg(),
227                    mox.IgnoreArg()).MultipleTimes().AndRaise(exception)
228            pexpect.spawn.__str__().AndReturn('A pexpect.spawn object.')
229            pexpect.spawn.sendline('end')
230
231
232    def testSuccessfullyChangeOutlet(self):
233        """Should return True if change was successful."""
234        self._EnterConfigurationHelper()
235        pexpect.spawn.sendline('power inline auto')
236        pexpect.spawn.sendline('end')
237        pexpect.spawn.read_nonblocking(
238                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_DEVICE)
239        pexpect.spawn.sendline('show interface status %s' % self.PORT)
240        pexpect.spawn.read_nonblocking(
241                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_STATUS)
242        pexpect.spawn.read_nonblocking(
243                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_DEVICE)
244        pexpect.spawn.sendline('exit')
245        self.mox.ReplayAll()
246        self.assertTrue(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON'))
247        self.mox.VerifyAll()
248
249
250    def testUnableToEnterConfigurationTerminal(self):
251        """Should return False if unable to enter configuration terminal."""
252        self._EnterConfigurationHelper(success=False)
253        pexpect.spawn.sendline('exit')
254        self.mox.ReplayAll()
255        self.assertFalse(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON'))
256        self.mox.VerifyAll()
257
258
259    def testUnableToExitConfigurationTerminal(self):
260        """Should return False if unable to exit configuration terminal."""
261        self.mox.StubOutWithMock(pexpect.spawn, '__str__')
262        self.mox.StubOutWithMock(rpm_controller.CiscoPOEController,
263                                 '_enter_configuration_terminal')
264        self.poe._enter_configuration_terminal(
265                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(True)
266        pexpect.spawn.sendline('power inline auto')
267        pexpect.spawn.sendline('end')
268        exception = pexpect.TIMEOUT('Could not exit configuration terminal.')
269        pexpect.spawn.read_nonblocking(
270                mox.IgnoreArg(),
271                mox.IgnoreArg()).MultipleTimes().AndRaise(exception)
272        pexpect.spawn.__str__().AndReturn('A pexpect.spawn object.')
273        pexpect.spawn.sendline('exit')
274        self.mox.ReplayAll()
275        self.assertFalse(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON'))
276        self.mox.VerifyAll()
277
278
279    def testUnableToVerifyState(self):
280        """Should return False if unable to verify current state."""
281        self.mox.StubOutWithMock(pexpect.spawn, '__str__')
282        self.mox.StubOutWithMock(rpm_controller.CiscoPOEController,
283                                 '_enter_configuration_terminal')
284        self.mox.StubOutWithMock(rpm_controller.CiscoPOEController,
285                                 '_exit_configuration_terminal')
286        self.poe._enter_configuration_terminal(
287                mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(True)
288        pexpect.spawn.sendline('power inline auto')
289        self.poe._exit_configuration_terminal(mox.IgnoreArg()).AndReturn(True)
290        pexpect.spawn.sendline('show interface status %s' % self.PORT)
291        exception = pexpect.TIMEOUT('Could not verify state.')
292        pexpect.spawn.read_nonblocking(
293                mox.IgnoreArg(),
294                mox.IgnoreArg()).MultipleTimes().AndRaise(exception)
295        pexpect.spawn.__str__().AndReturn('A pexpect.spawn object.')
296        pexpect.spawn.sendline('exit')
297        self.mox.ReplayAll()
298        self.assertFalse(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON'))
299        self.mox.VerifyAll()
300
301
302if __name__ == "__main__":
303    unittest.main()
304