blob: b314a7e7b1085ca82bb8dac571a02760fc3a3c9f [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
Todd Brochf24d2782011-08-19 10:55:41 -07006import re
Craig Harrison2b6c6fc2011-06-23 10:34:02 -07007import subprocess
Craig Harrison91944552011-08-04 14:09:55 -07008import time
9import xmlrpclib
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070010
Chrome Bot9a1137d2011-07-19 14:35:00 -070011from autotest_lib.client.common_lib import error
Todd Brochf24d2782011-08-19 10:55:41 -070012from autotest_lib.server import autotest, site_host_attributes, test
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070013import autotest_lib.server.cros.servo
14
Craig Harrison91944552011-08-04 14:09:55 -070015
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070016class ServoTest(test.test):
17 """AutoTest test class that creates and destroys a servo object.
18
Craig Harrison91944552011-08-04 14:09:55 -070019 Servo-based server side AutoTests can inherit from this object. If the
20 use_pyauto flag is True a remote session of PyAuto will also be launched.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070021 """
22 version = 1
Craig Harrison91944552011-08-04 14:09:55 -070023 # Abstracts access to all Servo functions.
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070024 servo = None
Craig Harrison91944552011-08-04 14:09:55 -070025 # Exposes RPC access to a remote PyAuto client.
26 pyauto = None
27 # Autotest references to the client.
28 _client = None
29 _client_autotest = None
30 # SSH processes for communicating with the client PyAuto RPC server.
31 _ssh = None
32 _remote_pyauto = None
33 # Enable PyAuto functionality.
34 _use_pyauto = False
35 # Port to look at for the client PyAuto RPC server.
36 _rpc_port = 9988
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070037
38
Todd Brochf24d2782011-08-19 10:55:41 -070039 def initialize(self, host, cmdline_args, use_pyauto=False):
Craig Harrison91944552011-08-04 14:09:55 -070040 """Create a Servo object and install the PyAuto dependency.
41
42 If use_pyauto is True the PyAuto dependency is installed on the client
43 and a remote PyAuto server is launched and connected.
Chrome Bot9a1137d2011-07-19 14:35:00 -070044
Todd Brochf24d2782011-08-19 10:55:41 -070045 """
46 # Assign default arguments for servo invocation.
47 args = {
48 'servo_host': 'localhost', 'servo_port': 9999,
49 'xml_config': 'servo.xml', 'servo_vid': None, 'servo_pid': None,
50 'servo_serial': None, 'use_pyauto': False}
51
52 # Parse arguments from AFE and override servo defaults above.
53 client_attributes = site_host_attributes.HostAttributes(host.hostname)
54 if hasattr(site_host_attributes, 'servo_serial'):
55 args['servo_serial'] = client_attributes.servo_serial
56
57 # Parse arguments from command line and override previous AFE or servo
58 # defaults
59 for arg in cmdline_args:
60 match = re.search("^(\w+)=(.+)", arg)
61 if match:
62 args[match.group(1)] = match.group(2)
63
64 self.servo = autotest_lib.server.cros.servo.Servo(
65 args['servo_host'], args['servo_port'], args['xml_config'],
66 args['servo_vid'], args['servo_pid'], args['servo_serial'])
Chrome Bot9a1137d2011-07-19 14:35:00 -070067 # Initializes dut, may raise AssertionError if pre-defined gpio
68 # sequence to set GPIO's fail. Autotest does not handle exception
69 # throwing in initialize and will cause a test to hang.
70 try:
71 self.servo.initialize_dut()
72 except AssertionError as e:
73 del self.servo
74 raise error.TestFail(e)
75
Craig Harrison91944552011-08-04 14:09:55 -070076 self._client = host;
77
78 # Install PyAuto dependency.
79 self._use_pyauto = use_pyauto
80 if self._use_pyauto:
81 self._client_autotest = autotest.Autotest(self._client)
82 self._client_autotest.run_test('desktopui_ServoPyAuto')
83 self.launch_pyauto()
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070084
85
86 def assert_ping(self):
87 """Ping to assert that the device is up."""
Craig Harrison91944552011-08-04 14:09:55 -070088 assert self.ping_test(self._client.ip)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070089
90
91 def assert_pingfail(self):
92 """Ping to assert that the device is down."""
Craig Harrison91944552011-08-04 14:09:55 -070093 assert not self.ping_test(self._client.ip)
Craig Harrison2b6c6fc2011-06-23 10:34:02 -070094
95
96 def ping_test(self, hostname, timeout=5):
97 """Verify whether a host responds to a ping.
98
99 Args:
100 hostname: Hostname to ping.
101 timeout: Time in seconds to wait for a response.
102 """
103 return subprocess.call(['ping', '-c', '1', '-W',
104 str(timeout), hostname]) == 0
105
106
Craig Harrison91944552011-08-04 14:09:55 -0700107 def launch_pyauto(self):
108 """Launch PyAuto on the client and set up an xmlrpc connection."""
109 assert self._use_pyauto, 'PyAuto dependency not installed.'
110 if not self._ssh or self._ssh.poll() is not None:
111 self._launch_ssh_tunnel()
112 assert self._ssh and self._ssh.poll() is None, \
113 'The SSH tunnel is not up.'
114 # Launch client RPC server.
115 self._kill_remote_pyauto()
116 pyauto_cmd = \
117 'python /usr/local/autotest/cros/servo_pyauto.py --no-http-server'
118 logging.info('Client command: %s' % pyauto_cmd)
Craig Harrison63e9c6a2011-08-10 17:13:57 -0700119 self._remote_pyauto = subprocess.Popen([
120 'ssh -o "StrictHostKeyChecking no" -n root@%s \'%s\'' %
121 (self._client.ip, pyauto_cmd)], shell=True)
Craig Harrison91944552011-08-04 14:09:55 -0700122 logging.info('Connecting to client PyAuto RPC server...')
123 remote = 'http://localhost:%s' % self._rpc_port
124 self.pyauto = xmlrpclib.ServerProxy(remote, allow_none=True)
125 logging.info('Server proxy: %s' % remote)
126 # Poll for client RPC server to come online.
127 timeout = 10
128 succeed = False
129 while timeout > 0 and not succeed:
130 time.sleep(2)
131 try:
132 self.pyauto.IsLinux()
133 succeed = True
134 except:
135 timeout -= 1
136 assert succeed, 'Timed out connecting to client PyAuto RPC server.'
137
138
139 def wait_for_client(self):
140 """Wait for the client to come back online.
141
142 A new remote PyAuto process will be launched if use_pyauto is enabled.
143 """
144 timeout = 10
145 # Ensure old ssh connections are terminated.
146 self._terminate_all_ssh()
147 # Wait for the client to come up.
148 while timeout > 0 and not self.ping_test(self._client.ip):
149 time.sleep(5)
150 timeout -= 1
151 assert timeout, 'Timed out waiting for client to reboot.'
152 logging.info('Server: Client machine is back up.')
153 # Relaunch remote PyAuto.
154 if self._use_pyauto:
155 self.launch_pyauto()
156 logging.info('Server: Relaunched remote PyAuto.')
157
158
Craig Harrison2b6c6fc2011-06-23 10:34:02 -0700159 def cleanup(self):
Craig Harrison91944552011-08-04 14:09:55 -0700160 """Delete the Servo object, call PyAuto cleanup, and kill ssh."""
161 if self.servo:
162 del self.servo
163 if self._remote_pyauto and self._remote_pyauto.poll() is None:
164 self.pyauto.cleanup()
165 self._terminate_all_ssh()
166
167
168 def _launch_ssh_tunnel(self):
169 """Establish an ssh tunnel for connecting to the remote RPC server."""
170 if not self._ssh or self._ssh.poll() is not None:
171 self._ssh = subprocess.Popen(['ssh', '-N', '-n', '-L',
172 '%s:localhost:%s' % (self._rpc_port, self._rpc_port),
173 'root@%s' % self._client.ip])
174
175
176 def _kill_remote_pyauto(self):
177 """Ensure the remote PyAuto and local ssh process are terminated."""
178 kill_cmd = 'pkill -f servo_pyauto'
Craig Harrison63e9c6a2011-08-10 17:13:57 -0700179 subprocess.call(['ssh -n -o "StrictHostKeyChecking no" root@%s \'%s\'' %
Craig Harrison91944552011-08-04 14:09:55 -0700180 (self._client.ip, kill_cmd)],
181 shell=True)
182 if self._remote_pyauto and self._remote_pyauto.poll() is None:
183 self._remote_pyauto.terminate()
184
185
186 def _terminate_all_ssh(self):
187 """Terminate all ssh connections associated with remote PyAuto."""
188 if self._ssh and self._ssh.poll() is None:
189 self._ssh.terminate()
190 self._kill_remote_pyauto()