blob: f82617a9b593565336647be57f9c88c6ea11f663 [file] [log] [blame]
Josh Gao9b6522b2018-08-07 14:31:17 -07001#!/usr/bin/env python3
Dan Albert8e1fdd72015-07-24 17:08:33 -07002#
3# Copyright (C) 2015 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Tests for the adb program itself.
18
19This differs from things in test_device.py in that there is no API for these
20things. Most of these tests involve specific error messages or the help text.
21"""
Dan Albert8e1fdd72015-07-24 17:08:33 -070022
Spencer Low351ecd12015-10-14 17:32:44 -070023import contextlib
Spencer Low1ce06082015-09-16 20:45:53 -070024import os
Dan Albert8e1fdd72015-07-24 17:08:33 -070025import random
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070026import select
Spencer Low351ecd12015-10-14 17:32:44 -070027import socket
28import struct
Dan Albert8e1fdd72015-07-24 17:08:33 -070029import subprocess
Spencer Low1ce06082015-09-16 20:45:53 -070030import threading
Dan Albert8e1fdd72015-07-24 17:08:33 -070031import unittest
32
Dan Albert8e1fdd72015-07-24 17:08:33 -070033
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070034@contextlib.contextmanager
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070035def fake_adbd(protocol=socket.AF_INET, port=0):
36 """Creates a fake ADB daemon that just replies with a CNXN packet."""
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070037
38 serversock = socket.socket(protocol, socket.SOCK_STREAM)
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070039 serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070040 if protocol == socket.AF_INET:
41 serversock.bind(('127.0.0.1', port))
42 else:
43 serversock.bind(('::1', port))
44 serversock.listen(1)
45
46 # A pipe that is used to signal the thread that it should terminate.
Josh Gao676f375d2018-08-07 16:07:25 -070047 readsock, writesock = socket.socketpair()
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070048
Josh Gao9b6522b2018-08-07 14:31:17 -070049 def _adb_packet(command: bytes, arg0: int, arg1: int, data: bytes) -> bytes:
Luis Hector Chavez56fe7532018-04-17 14:25:04 -070050 bin_command = struct.unpack('I', command)[0]
51 buf = struct.pack('IIIIII', bin_command, arg0, arg1, len(data), 0,
52 bin_command ^ 0xffffffff)
53 buf += data
54 return buf
55
Josh Gao9b6522b2018-08-07 14:31:17 -070056 def _handle(sock):
57 with contextlib.closing(sock) as serversock:
Josh Gao676f375d2018-08-07 16:07:25 -070058 rlist = [readsock, serversock]
Josh Gao9b6522b2018-08-07 14:31:17 -070059 cnxn_sent = {}
60 while True:
61 read_ready, _, _ = select.select(rlist, [], [])
62 for ready in read_ready:
Josh Gao676f375d2018-08-07 16:07:25 -070063 if ready == readsock:
Josh Gao9b6522b2018-08-07 14:31:17 -070064 # Closure pipe
Josh Gao9b6522b2018-08-07 14:31:17 -070065 for f in rlist:
Josh Gao676f375d2018-08-07 16:07:25 -070066 f.close()
Josh Gao9b6522b2018-08-07 14:31:17 -070067 return
68 elif ready == serversock:
69 # Server socket
70 conn, _ = ready.accept()
71 rlist.append(conn)
72 else:
73 # Client socket
74 data = ready.recv(1024)
75 if not data or data.startswith(b'OPEN'):
76 if ready in cnxn_sent:
77 del cnxn_sent[ready]
78 ready.shutdown(socket.SHUT_RDWR)
79 ready.close()
80 rlist.remove(ready)
81 continue
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070082 if ready in cnxn_sent:
Josh Gao9b6522b2018-08-07 14:31:17 -070083 continue
84 cnxn_sent[ready] = True
85 ready.sendall(_adb_packet(b'CNXN', 0x01000001, 1024 * 1024,
86 b'device::ro.product.name=fakeadb'))
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070087
88 port = serversock.getsockname()[1]
Josh Gao9b6522b2018-08-07 14:31:17 -070089 server_thread = threading.Thread(target=_handle, args=(serversock,))
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070090 server_thread.start()
91
92 try:
93 yield port
94 finally:
Josh Gao676f375d2018-08-07 16:07:25 -070095 writesock.close()
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070096 server_thread.join()
97
98
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -070099@contextlib.contextmanager
100def adb_connect(unittest, serial):
101 """Context manager for an ADB connection.
102
103 This automatically disconnects when done with the connection.
104 """
105
106 output = subprocess.check_output(['adb', 'connect', serial])
Josh Gao9b6522b2018-08-07 14:31:17 -0700107 unittest.assertEqual(output.strip(),
108 'connected to {}'.format(serial).encode("utf8"))
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700109
110 try:
111 yield
112 finally:
113 # Perform best-effort disconnection. Discard the output.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700114 subprocess.Popen(['adb', 'disconnect', serial],
115 stdout=subprocess.PIPE,
116 stderr=subprocess.PIPE).communicate()
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700117
118
Luis Hector Chavez32559742018-05-02 10:47:01 -0700119@contextlib.contextmanager
120def adb_server():
121 """Context manager for an ADB server.
122
123 This creates an ADB server and returns the port it's listening on.
124 """
125
126 port = 5038
127 # Kill any existing server on this non-default port.
128 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
129 stderr=subprocess.STDOUT)
130 read_pipe, write_pipe = os.pipe()
Josh Gao9b6522b2018-08-07 14:31:17 -0700131 os.set_inheritable(write_pipe, True)
Luis Hector Chavez32559742018-05-02 10:47:01 -0700132 proc = subprocess.Popen(['adb', '-L', 'tcp:localhost:{}'.format(port),
133 'fork-server', 'server',
Josh Gao9b6522b2018-08-07 14:31:17 -0700134 '--reply-fd', str(write_pipe)], close_fds=False)
Luis Hector Chavez32559742018-05-02 10:47:01 -0700135 try:
136 os.close(write_pipe)
137 greeting = os.read(read_pipe, 1024)
Josh Gao9b6522b2018-08-07 14:31:17 -0700138 assert greeting == b'OK\n', repr(greeting)
Luis Hector Chavez32559742018-05-02 10:47:01 -0700139 yield port
140 finally:
141 proc.terminate()
142 proc.wait()
143
144
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700145class CommandlineTest(unittest.TestCase):
146 """Tests for the ADB commandline."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700147
148 def test_help(self):
149 """Make sure we get _something_ out of help."""
150 out = subprocess.check_output(
151 ['adb', 'help'], stderr=subprocess.STDOUT)
152 self.assertGreater(len(out), 0)
153
154 def test_version(self):
155 """Get a version number out of the output of adb."""
156 lines = subprocess.check_output(['adb', 'version']).splitlines()
157 version_line = lines[0]
Josh Gao9b6522b2018-08-07 14:31:17 -0700158 self.assertRegex(
159 version_line, rb'^Android Debug Bridge version \d+\.\d+\.\d+$')
Dan Albert8e1fdd72015-07-24 17:08:33 -0700160 if len(lines) == 2:
161 # Newer versions of ADB have a second line of output for the
162 # version that includes a specific revision (git SHA).
163 revision_line = lines[1]
Josh Gao9b6522b2018-08-07 14:31:17 -0700164 self.assertRegex(
165 revision_line, rb'^Revision [0-9a-f]{12}-android$')
Dan Albert8e1fdd72015-07-24 17:08:33 -0700166
167 def test_tcpip_error_messages(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700168 """Make sure 'adb tcpip' parsing is sane."""
Josh Gao9b6522b2018-08-07 14:31:17 -0700169 proc = subprocess.Popen(['adb', 'tcpip'],
170 stdout=subprocess.PIPE,
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700171 stderr=subprocess.STDOUT)
172 out, _ = proc.communicate()
173 self.assertEqual(1, proc.returncode)
Josh Gao9b6522b2018-08-07 14:31:17 -0700174 self.assertIn(b'requires an argument', out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700175
Josh Gao9b6522b2018-08-07 14:31:17 -0700176 proc = subprocess.Popen(['adb', 'tcpip', 'foo'],
177 stdout=subprocess.PIPE,
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700178 stderr=subprocess.STDOUT)
179 out, _ = proc.communicate()
180 self.assertEqual(1, proc.returncode)
Josh Gao9b6522b2018-08-07 14:31:17 -0700181 self.assertIn(b'invalid port', out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700182
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700183
184class ServerTest(unittest.TestCase):
185 """Tests for the ADB server."""
186
187 @staticmethod
188 def _read_pipe_and_set_event(pipe, event):
189 """Reads a pipe until it is closed, then sets the event."""
190 pipe.read()
Spencer Low1ce06082015-09-16 20:45:53 -0700191 event.set()
192
Spencer Low1ce06082015-09-16 20:45:53 -0700193 def test_handle_inheritance(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700194 """Test that launch_server() does not inherit handles.
195
196 launch_server() should not let the adb server inherit
197 stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
198 This test also runs fine on unix even though the impetus is an issue
199 unique to Windows.
200 """
Spencer Low1ce06082015-09-16 20:45:53 -0700201 # This test takes 5 seconds to run on Windows: if there is no adb server
202 # running on the the port used below, adb kill-server tries to make a
203 # TCP connection to a closed port and that takes 1 second on Windows;
204 # adb start-server does the same TCP connection which takes another
205 # second, and it waits 3 seconds after starting the server.
206
207 # Start adb client with redirected stdin/stdout/stderr to check if it
208 # passes those redirections to the adb server that it starts. To do
209 # this, run an instance of the adb server on a non-default port so we
210 # don't conflict with a pre-existing adb server that may already be
211 # setup with adb TCP/emulator connections. If there is a pre-existing
212 # adb server, this also tests whether multiple instances of the adb
213 # server conflict on adb.log.
214
215 port = 5038
216 # Kill any existing server on this non-default port.
217 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
218 stderr=subprocess.STDOUT)
219
220 try:
221 # Run the adb client and have it start the adb server.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700222 proc = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
223 stdin=subprocess.PIPE,
224 stdout=subprocess.PIPE,
225 stderr=subprocess.PIPE)
Spencer Low1ce06082015-09-16 20:45:53 -0700226
227 # Start threads that set events when stdout/stderr are closed.
228 stdout_event = threading.Event()
229 stdout_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700230 target=ServerTest._read_pipe_and_set_event,
231 args=(proc.stdout, stdout_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700232 stdout_thread.start()
233
234 stderr_event = threading.Event()
235 stderr_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700236 target=ServerTest._read_pipe_and_set_event,
237 args=(proc.stderr, stderr_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700238 stderr_thread.start()
239
240 # Wait for the adb client to finish. Once that has occurred, if
241 # stdin/stderr/stdout are still open, it must be open in the adb
242 # server.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700243 proc.wait()
Spencer Low1ce06082015-09-16 20:45:53 -0700244
245 # Try to write to stdin which we expect is closed. If it isn't
246 # closed, we should get an IOError. If we don't get an IOError,
247 # stdin must still be open in the adb server. The adb client is
248 # probably letting the adb server inherit stdin which would be
249 # wrong.
250 with self.assertRaises(IOError):
Josh Gao9b6522b2018-08-07 14:31:17 -0700251 proc.stdin.write(b'x')
252 proc.stdin.flush()
Spencer Low1ce06082015-09-16 20:45:53 -0700253
254 # Wait a few seconds for stdout/stderr to be closed (in the success
255 # case, this won't wait at all). If there is a timeout, that means
256 # stdout/stderr were not closed and and they must be open in the adb
257 # server, suggesting that the adb client is letting the adb server
258 # inherit stdout/stderr which would be wrong.
259 self.assertTrue(stdout_event.wait(5), "adb stdout not closed")
260 self.assertTrue(stderr_event.wait(5), "adb stderr not closed")
Josh Gao9b6522b2018-08-07 14:31:17 -0700261 stdout_thread.join()
262 stderr_thread.join()
Spencer Low1ce06082015-09-16 20:45:53 -0700263 finally:
264 # If we started a server, kill it.
265 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
266 stderr=subprocess.STDOUT)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700267
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700268
269class EmulatorTest(unittest.TestCase):
270 """Tests for the emulator connection."""
271
Spencer Low351ecd12015-10-14 17:32:44 -0700272 def _reset_socket_on_close(self, sock):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700273 """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
Spencer Low351ecd12015-10-14 17:32:44 -0700274 # The linger structure is two shorts on Windows, but two ints on Unix.
275 linger_format = 'hh' if os.name == 'nt' else 'ii'
276 l_onoff = 1
277 l_linger = 0
278
279 sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
280 struct.pack(linger_format, l_onoff, l_linger))
281 # Verify that we set the linger structure properly by retrieving it.
282 linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16)
283 self.assertEqual((l_onoff, l_linger),
284 struct.unpack_from(linger_format, linger))
285
286 def test_emu_kill(self):
287 """Ensure that adb emu kill works.
288
289 Bug: https://code.google.com/p/android/issues/detail?id=21021
290 """
Spencer Low351ecd12015-10-14 17:32:44 -0700291 with contextlib.closing(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700292 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
Spencer Low351ecd12015-10-14 17:32:44 -0700293 # Use SO_REUSEADDR so subsequent runs of the test can grab the port
294 # even if it is in TIME_WAIT.
295 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Josh Gaoc251ec52018-04-03 12:55:18 -0700296 listener.bind(('127.0.0.1', 0))
Spencer Low351ecd12015-10-14 17:32:44 -0700297 listener.listen(4)
Josh Gaoc251ec52018-04-03 12:55:18 -0700298 port = listener.getsockname()[1]
Spencer Low351ecd12015-10-14 17:32:44 -0700299
300 # Now that listening has started, start adb emu kill, telling it to
301 # connect to our mock emulator.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700302 proc = subprocess.Popen(
Spencer Low351ecd12015-10-14 17:32:44 -0700303 ['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'],
304 stderr=subprocess.STDOUT)
305
306 accepted_connection, addr = listener.accept()
307 with contextlib.closing(accepted_connection) as conn:
308 # If WSAECONNABORTED (10053) is raised by any socket calls,
309 # then adb probably isn't reading the data that we sent it.
Josh Gao9b6522b2018-08-07 14:31:17 -0700310 conn.sendall(('Android Console: type \'help\' for a list '
311 'of commands\r\n').encode("utf8"))
312 conn.sendall(b'OK\r\n')
Spencer Low351ecd12015-10-14 17:32:44 -0700313
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700314 with contextlib.closing(conn.makefile()) as connf:
315 line = connf.readline()
316 if line.startswith('auth'):
317 # Ignore the first auth line.
318 line = connf.readline()
319 self.assertEqual('kill\n', line)
320 self.assertEqual('quit\n', connf.readline())
Spencer Low351ecd12015-10-14 17:32:44 -0700321
Josh Gao9b6522b2018-08-07 14:31:17 -0700322 conn.sendall(b'OK: killing emulator, bye bye\r\n')
Spencer Low351ecd12015-10-14 17:32:44 -0700323
324 # Use SO_LINGER to send TCP RST segment to test whether adb
325 # ignores WSAECONNRESET on Windows. This happens with the
326 # real emulator because it just calls exit() without closing
327 # the socket or calling shutdown(SD_SEND). At process
328 # termination, Windows sends a TCP RST segment for every
329 # open socket that shutdown(SD_SEND) wasn't used on.
330 self._reset_socket_on_close(conn)
331
332 # Wait for adb to finish, so we can check return code.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700333 proc.communicate()
Spencer Low351ecd12015-10-14 17:32:44 -0700334
335 # If this fails, adb probably isn't ignoring WSAECONNRESET when
336 # reading the response from the adb emu kill command (on Windows).
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700337 self.assertEqual(0, proc.returncode)
338
Luis Hector Chavez32559742018-05-02 10:47:01 -0700339 def test_emulator_connect(self):
340 """Ensure that the emulator can connect.
341
342 Bug: http://b/78991667
343 """
344 with adb_server() as server_port:
345 with fake_adbd() as port:
346 serial = 'emulator-{}'.format(port - 1)
347 # Ensure that the emulator is not there.
348 try:
349 subprocess.check_output(['adb', '-P', str(server_port),
350 '-s', serial, 'get-state'],
351 stderr=subprocess.STDOUT)
352 self.fail('Device should not be available')
353 except subprocess.CalledProcessError as err:
354 self.assertEqual(
355 err.output.strip(),
Josh Gao9b6522b2018-08-07 14:31:17 -0700356 'error: device \'{}\' not found'.format(serial).encode("utf8"))
Luis Hector Chavez32559742018-05-02 10:47:01 -0700357
358 # Let the ADB server know that the emulator has started.
359 with contextlib.closing(
Josh Gao9b6522b2018-08-07 14:31:17 -0700360 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
Luis Hector Chavez32559742018-05-02 10:47:01 -0700361 sock.connect(('localhost', server_port))
Josh Gao9b6522b2018-08-07 14:31:17 -0700362 command = 'host:emulator:{}'.format(port).encode("utf8")
363 sock.sendall(b'%04x%s' % (len(command), command))
Luis Hector Chavez32559742018-05-02 10:47:01 -0700364
365 # Ensure the emulator is there.
366 subprocess.check_call(['adb', '-P', str(server_port),
367 '-s', serial, 'wait-for-device'])
368 output = subprocess.check_output(['adb', '-P', str(server_port),
369 '-s', serial, 'get-state'])
Josh Gao9b6522b2018-08-07 14:31:17 -0700370 self.assertEqual(output.strip(), b'device')
Luis Hector Chavez32559742018-05-02 10:47:01 -0700371
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700372
373class ConnectionTest(unittest.TestCase):
374 """Tests for adb connect."""
Spencer Low351ecd12015-10-14 17:32:44 -0700375
Josh Gao78cc20f2016-09-01 14:54:18 -0700376 def test_connect_ipv4_ipv6(self):
377 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
378
379 Bug: http://b/30313466
380 """
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700381 for protocol in (socket.AF_INET, socket.AF_INET6):
382 try:
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700383 with fake_adbd(protocol=protocol) as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700384 serial = 'localhost:{}'.format(port)
385 with adb_connect(self, serial):
386 pass
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700387 except socket.error:
388 print("IPv6 not available, skipping")
389 continue
Josh Gao78cc20f2016-09-01 14:54:18 -0700390
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700391 def test_already_connected(self):
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700392 """Ensure that an already-connected device stays connected."""
393
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700394 with fake_adbd() as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700395 serial = 'localhost:{}'.format(port)
396 with adb_connect(self, serial):
397 # b/31250450: this always returns 0 but probably shouldn't.
398 output = subprocess.check_output(['adb', 'connect', serial])
399 self.assertEqual(
Josh Gao9b6522b2018-08-07 14:31:17 -0700400 output.strip(),
401 'already connected to {}'.format(serial).encode("utf8"))
Josh Gao78cc20f2016-09-01 14:54:18 -0700402
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700403 def test_reconnect(self):
404 """Ensure that a disconnected device reconnects."""
Josh Gao78cc20f2016-09-01 14:54:18 -0700405
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700406 with fake_adbd() as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700407 serial = 'localhost:{}'.format(port)
408 with adb_connect(self, serial):
409 output = subprocess.check_output(['adb', '-s', serial,
410 'get-state'])
Josh Gao9b6522b2018-08-07 14:31:17 -0700411 self.assertEqual(output.strip(), b'device')
Josh Gaoc251ec52018-04-03 12:55:18 -0700412
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700413 # This will fail.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700414 proc = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'],
415 stdout=subprocess.PIPE,
416 stderr=subprocess.STDOUT)
417 output, _ = proc.communicate()
Josh Gao9b6522b2018-08-07 14:31:17 -0700418 self.assertEqual(output.strip(), b'error: closed')
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700419
420 subprocess.check_call(['adb', '-s', serial, 'wait-for-device'])
421
422 output = subprocess.check_output(['adb', '-s', serial,
423 'get-state'])
Josh Gao9b6522b2018-08-07 14:31:17 -0700424 self.assertEqual(output.strip(), b'device')
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700425
426 # Once we explicitly kick a device, it won't attempt to
427 # reconnect.
428 output = subprocess.check_output(['adb', 'disconnect', serial])
429 self.assertEqual(
Josh Gao9b6522b2018-08-07 14:31:17 -0700430 output.strip(),
431 'disconnected {}'.format(serial).encode("utf8"))
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700432 try:
433 subprocess.check_output(['adb', '-s', serial, 'get-state'],
434 stderr=subprocess.STDOUT)
435 self.fail('Device should not be available')
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700436 except subprocess.CalledProcessError as err:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700437 self.assertEqual(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700438 err.output.strip(),
Josh Gao9b6522b2018-08-07 14:31:17 -0700439 'error: device \'{}\' not found'.format(serial).encode("utf8"))
Spencer Low351ecd12015-10-14 17:32:44 -0700440
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700441
Dan Albert8e1fdd72015-07-24 17:08:33 -0700442def main():
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700443 """Main entrypoint."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700444 random.seed(0)
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700445 unittest.main(verbosity=3)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700446
447
448if __name__ == '__main__':
449 main()