blob: 5a6e27a4c5ca74834d3b37f98c0000b187efa374 [file] [log] [blame]
Craig Harrison2b6c6fc2011-06-23 10:34:02 -07001# Copyright (c) 2011 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
Craig Harrison91944552011-08-04 14:09:55 -07005import logging
Craig Harrison2b6c6fc2011-06-23 10:34:02 -07006import subprocess
Craig Harrison91944552011-08-04 14:09:55 -07007import time
8import xmlrpclib
Craig Harrison2b6c6fc2011-06-23 10:34:02 -07009
Chrome Bot9a1137d2011-07-19 14:35:00 -070010from autotest_lib.client.common_lib import error
Craig Harrison91944552011-08-04 14:09:55 -070011from autotest_lib.server import test, autotest
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070012import autotest_lib.server.cros.servo
13
Craig Harrison91944552011-08-04 14:09:55 -070014
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070015class ServoTest(test.test):
16 """AutoTest test class that creates and destroys a servo object.
17
Craig Harrison91944552011-08-04 14:09:55 -070018 Servo-based server side AutoTests can inherit from this object. If the
19 use_pyauto flag is True a remote session of PyAuto will also be launched.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070020 """
21 version = 1
Craig Harrison91944552011-08-04 14:09:55 -070022 # Abstracts access to all Servo functions.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070023 servo = None
Craig Harrison91944552011-08-04 14:09:55 -070024 # Exposes RPC access to a remote PyAuto client.
25 pyauto = None
26 # Autotest references to the client.
27 _client = None
28 _client_autotest = None
29 # SSH processes for communicating with the client PyAuto RPC server.
30 _ssh = None
31 _remote_pyauto = None
32 # Enable PyAuto functionality.
33 _use_pyauto = False
34 # Port to look at for the client PyAuto RPC server.
35 _rpc_port = 9988
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070036
37
Todd Broch5fd6bc02011-07-20 15:53:37 -070038 def initialize(self, host, servo_port, xml_config='servo.xml',
Craig Harrison91944552011-08-04 14:09:55 -070039 servo_vid=None, servo_pid=None, servo_serial=None,
40 use_pyauto=False):
41 """Create a Servo object and install the PyAuto dependency.
42
43 If use_pyauto is True the PyAuto dependency is installed on the client
44 and a remote PyAuto server is launched and connected.
45 """
Chrome Bot9a1137d2011-07-19 14:35:00 -070046 self.servo = autotest_lib.server.cros.servo.Servo(
47 servo_port, xml_config, servo_vid, servo_pid, servo_serial)
48
49 # Initializes dut, may raise AssertionError if pre-defined gpio
50 # sequence to set GPIO's fail. Autotest does not handle exception
51 # throwing in initialize and will cause a test to hang.
52 try:
53 self.servo.initialize_dut()
54 except AssertionError as e:
55 del self.servo
56 raise error.TestFail(e)
57
Craig Harrison91944552011-08-04 14:09:55 -070058 self._client = host;
59
60 # Install PyAuto dependency.
61 self._use_pyauto = use_pyauto
62 if self._use_pyauto:
63 self._client_autotest = autotest.Autotest(self._client)
64 self._client_autotest.run_test('desktopui_ServoPyAuto')
65 self.launch_pyauto()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070066
67
68 def assert_ping(self):
69 """Ping to assert that the device is up."""
Craig Harrison91944552011-08-04 14:09:55 -070070 assert self.ping_test(self._client.ip)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070071
72
73 def assert_pingfail(self):
74 """Ping to assert that the device is down."""
Craig Harrison91944552011-08-04 14:09:55 -070075 assert not self.ping_test(self._client.ip)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070076
77
78 def ping_test(self, hostname, timeout=5):
79 """Verify whether a host responds to a ping.
80
81 Args:
82 hostname: Hostname to ping.
83 timeout: Time in seconds to wait for a response.
84 """
85 return subprocess.call(['ping', '-c', '1', '-W',
86 str(timeout), hostname]) == 0
87
88
Craig Harrison91944552011-08-04 14:09:55 -070089 def launch_pyauto(self):
90 """Launch PyAuto on the client and set up an xmlrpc connection."""
91 assert self._use_pyauto, 'PyAuto dependency not installed.'
92 if not self._ssh or self._ssh.poll() is not None:
93 self._launch_ssh_tunnel()
94 assert self._ssh and self._ssh.poll() is None, \
95 'The SSH tunnel is not up.'
96 # Launch client RPC server.
97 self._kill_remote_pyauto()
98 pyauto_cmd = \
99 'python /usr/local/autotest/cros/servo_pyauto.py --no-http-server'
100 logging.info('Client command: %s' % pyauto_cmd)
Craig Harrison63e9c6a2011-08-10 17:13:57 -0700101 self._remote_pyauto = subprocess.Popen([
102 'ssh -o "StrictHostKeyChecking no" -n root@%s \'%s\'' %
103 (self._client.ip, pyauto_cmd)], shell=True)
Craig Harrison91944552011-08-04 14:09:55 -0700104 logging.info('Connecting to client PyAuto RPC server...')
105 remote = 'http://localhost:%s' % self._rpc_port
106 self.pyauto = xmlrpclib.ServerProxy(remote, allow_none=True)
107 logging.info('Server proxy: %s' % remote)
108 # Poll for client RPC server to come online.
109 timeout = 10
110 succeed = False
111 while timeout > 0 and not succeed:
112 time.sleep(2)
113 try:
114 self.pyauto.IsLinux()
115 succeed = True
116 except:
117 timeout -= 1
118 assert succeed, 'Timed out connecting to client PyAuto RPC server.'
119
120
121 def wait_for_client(self):
122 """Wait for the client to come back online.
123
124 A new remote PyAuto process will be launched if use_pyauto is enabled.
125 """
126 timeout = 10
127 # Ensure old ssh connections are terminated.
128 self._terminate_all_ssh()
129 # Wait for the client to come up.
130 while timeout > 0 and not self.ping_test(self._client.ip):
131 time.sleep(5)
132 timeout -= 1
133 assert timeout, 'Timed out waiting for client to reboot.'
134 logging.info('Server: Client machine is back up.')
135 # Relaunch remote PyAuto.
136 if self._use_pyauto:
137 self.launch_pyauto()
138 logging.info('Server: Relaunched remote PyAuto.')
139
140
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700141 def cleanup(self):
Craig Harrison91944552011-08-04 14:09:55 -0700142 """Delete the Servo object, call PyAuto cleanup, and kill ssh."""
143 if self.servo:
144 del self.servo
145 if self._remote_pyauto and self._remote_pyauto.poll() is None:
146 self.pyauto.cleanup()
147 self._terminate_all_ssh()
148
149
150 def _launch_ssh_tunnel(self):
151 """Establish an ssh tunnel for connecting to the remote RPC server."""
152 if not self._ssh or self._ssh.poll() is not None:
153 self._ssh = subprocess.Popen(['ssh', '-N', '-n', '-L',
154 '%s:localhost:%s' % (self._rpc_port, self._rpc_port),
155 'root@%s' % self._client.ip])
156
157
158 def _kill_remote_pyauto(self):
159 """Ensure the remote PyAuto and local ssh process are terminated."""
160 kill_cmd = 'pkill -f servo_pyauto'
Craig Harrison63e9c6a2011-08-10 17:13:57 -0700161 subprocess.call(['ssh -n -o "StrictHostKeyChecking no" root@%s \'%s\'' %
Craig Harrison91944552011-08-04 14:09:55 -0700162 (self._client.ip, kill_cmd)],
163 shell=True)
164 if self._remote_pyauto and self._remote_pyauto.poll() is None:
165 self._remote_pyauto.terminate()
166
167
168 def _terminate_all_ssh(self):
169 """Terminate all ssh connections associated with remote PyAuto."""
170 if self._ssh and self._ssh.poll() is None:
171 self._ssh.terminate()
172 self._kill_remote_pyauto()