summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis Hector Chavez2018-05-02 11:10:29 -0500
committerLuis Hector Chavez2018-05-16 17:20:48 -0500
commitfbee0a9133ef9d94421f06888e6d147d3fbe2c5e (patch)
tree4eb21e825d4d2f825001be98484e25501fe865ce
parent454bc7c0be9757c583b6f9fd8912a1b158773f28 (diff)
downloadplatform-system-core-fbee0a9133ef9d94421f06888e6d147d3fbe2c5e.tar.gz
platform-system-core-fbee0a9133ef9d94421f06888e6d147d3fbe2c5e.tar.xz
platform-system-core-fbee0a9133ef9d94421f06888e6d147d3fbe2c5e.zip
adb: Improve test_adb a bit more
This change: * uses unittest.main(), which allows for a subset of the tests to be selected. * drops the requirement to have a device already connected since all the tests that need a device now spin their own mock device. * Splits the monolithic test class into more granular classes. * Makes this file be pylint-compliant. Bug: None Test: python system/core/adb/test_adb.py Test: pylint system/core/adb/test_adb.py Change-Id: I91c7ced520c3c69f855d639e0dbf7e57bb690e97
-rw-r--r--adb/test_adb.py161
1 files changed, 91 insertions, 70 deletions
diff --git a/adb/test_adb.py b/adb/test_adb.py
index ce4d4ecfe..8f31a5366 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -36,10 +36,11 @@ import adb
36 36
37 37
38@contextlib.contextmanager 38@contextlib.contextmanager
39def fake_adb_server(protocol=socket.AF_INET, port=0): 39def fake_adbd(protocol=socket.AF_INET, port=0):
40 """Creates a fake ADB server that just replies with a CNXN packet.""" 40 """Creates a fake ADB daemon that just replies with a CNXN packet."""
41 41
42 serversock = socket.socket(protocol, socket.SOCK_STREAM) 42 serversock = socket.socket(protocol, socket.SOCK_STREAM)
43 serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
43 if protocol == socket.AF_INET: 44 if protocol == socket.AF_INET:
44 serversock.bind(('127.0.0.1', port)) 45 serversock.bind(('127.0.0.1', port))
45 else: 46 else:
@@ -60,33 +61,33 @@ def fake_adb_server(protocol=socket.AF_INET, port=0):
60 rlist = [readpipe, serversock] 61 rlist = [readpipe, serversock]
61 cnxn_sent = {} 62 cnxn_sent = {}
62 while True: 63 while True:
63 ready, _, _ = select.select(rlist, [], []) 64 read_ready, _, _ = select.select(rlist, [], [])
64 for r in ready: 65 for ready in read_ready:
65 if r == readpipe: 66 if ready == readpipe:
66 # Closure pipe 67 # Closure pipe
67 os.close(r) 68 os.close(ready)
68 serversock.shutdown(socket.SHUT_RDWR) 69 serversock.shutdown(socket.SHUT_RDWR)
69 serversock.close() 70 serversock.close()
70 return 71 return
71 elif r == serversock: 72 elif ready == serversock:
72 # Server socket 73 # Server socket
73 conn, _ = r.accept() 74 conn, _ = ready.accept()
74 rlist.append(conn) 75 rlist.append(conn)
75 else: 76 else:
76 # Client socket 77 # Client socket
77 data = r.recv(1024) 78 data = ready.recv(1024)
78 if not data or data.startswith('OPEN'): 79 if not data or data.startswith('OPEN'):
79 if r in cnxn_sent: 80 if ready in cnxn_sent:
80 del cnxn_sent[r] 81 del cnxn_sent[ready]
81 r.shutdown(socket.SHUT_RDWR) 82 ready.shutdown(socket.SHUT_RDWR)
82 r.close() 83 ready.close()
83 rlist.remove(r) 84 rlist.remove(ready)
84 continue 85 continue
85 if r in cnxn_sent: 86 if ready in cnxn_sent:
86 continue 87 continue
87 cnxn_sent[r] = True 88 cnxn_sent[ready] = True
88 r.sendall(_adb_packet('CNXN', 0x01000001, 1024 * 1024, 89 ready.sendall(_adb_packet('CNXN', 0x01000001, 1024 * 1024,
89 'device::ro.product.name=fakeadb')) 90 'device::ro.product.name=fakeadb'))
90 91
91 port = serversock.getsockname()[1] 92 port = serversock.getsockname()[1]
92 server_thread = threading.Thread(target=_handle) 93 server_thread = threading.Thread(target=_handle)
@@ -113,13 +114,13 @@ def adb_connect(unittest, serial):
113 yield 114 yield
114 finally: 115 finally:
115 # Perform best-effort disconnection. Discard the output. 116 # Perform best-effort disconnection. Discard the output.
116 p = subprocess.Popen(['adb', 'disconnect', serial], 117 subprocess.Popen(['adb', 'disconnect', serial],
117 stdout=subprocess.PIPE, stderr=subprocess.PIPE) 118 stdout=subprocess.PIPE,
118 p.communicate() 119 stderr=subprocess.PIPE).communicate()
119 120
120 121
121class NonApiTest(unittest.TestCase): 122class CommandlineTest(unittest.TestCase):
122 """Tests for ADB that aren't a part of the AndroidDevice API.""" 123 """Tests for the ADB commandline."""
123 124
124 def test_help(self): 125 def test_help(self):
125 """Make sure we get _something_ out of help.""" 126 """Make sure we get _something_ out of help."""
@@ -141,28 +142,37 @@ class NonApiTest(unittest.TestCase):
141 revision_line, r'^Revision [0-9a-f]{12}-android$') 142 revision_line, r'^Revision [0-9a-f]{12}-android$')
142 143
143 def test_tcpip_error_messages(self): 144 def test_tcpip_error_messages(self):
144 p = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE, 145 """Make sure 'adb tcpip' parsing is sane."""
145 stderr=subprocess.STDOUT) 146 proc = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
146 out, _ = p.communicate() 147 stderr=subprocess.STDOUT)
147 self.assertEqual(1, p.returncode) 148 out, _ = proc.communicate()
149 self.assertEqual(1, proc.returncode)
148 self.assertIn('requires an argument', out) 150 self.assertIn('requires an argument', out)
149 151
150 p = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE, 152 proc = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
151 stderr=subprocess.STDOUT) 153 stderr=subprocess.STDOUT)
152 out, _ = p.communicate() 154 out, _ = proc.communicate()
153 self.assertEqual(1, p.returncode) 155 self.assertEqual(1, proc.returncode)
154 self.assertIn('invalid port', out) 156 self.assertIn('invalid port', out)
155 157
156 # Helper method that reads a pipe until it is closed, then sets the event. 158
157 def _read_pipe_and_set_event(self, pipe, event): 159class ServerTest(unittest.TestCase):
158 x = pipe.read() 160 """Tests for the ADB server."""
161
162 @staticmethod
163 def _read_pipe_and_set_event(pipe, event):
164 """Reads a pipe until it is closed, then sets the event."""
165 pipe.read()
159 event.set() 166 event.set()
160 167
161 # Test that launch_server() does not let the adb server inherit
162 # stdin/stdout/stderr handles which can cause callers of adb.exe to hang.
163 # This test also runs fine on unix even though the impetus is an issue
164 # unique to Windows.
165 def test_handle_inheritance(self): 168 def test_handle_inheritance(self):
169 """Test that launch_server() does not inherit handles.
170
171 launch_server() should not let the adb server inherit
172 stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
173 This test also runs fine on unix even though the impetus is an issue
174 unique to Windows.
175 """
166 # This test takes 5 seconds to run on Windows: if there is no adb server 176 # This test takes 5 seconds to run on Windows: if there is no adb server
167 # running on the the port used below, adb kill-server tries to make a 177 # running on the the port used below, adb kill-server tries to make a
168 # TCP connection to a closed port and that takes 1 second on Windows; 178 # TCP connection to a closed port and that takes 1 second on Windows;
@@ -184,29 +194,30 @@ class NonApiTest(unittest.TestCase):
184 194
185 try: 195 try:
186 # Run the adb client and have it start the adb server. 196 # Run the adb client and have it start the adb server.
187 p = subprocess.Popen(['adb', '-P', str(port), 'start-server'], 197 proc = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
188 stdin=subprocess.PIPE, stdout=subprocess.PIPE, 198 stdin=subprocess.PIPE,
189 stderr=subprocess.PIPE) 199 stdout=subprocess.PIPE,
200 stderr=subprocess.PIPE)
190 201
191 # Start threads that set events when stdout/stderr are closed. 202 # Start threads that set events when stdout/stderr are closed.
192 stdout_event = threading.Event() 203 stdout_event = threading.Event()
193 stdout_thread = threading.Thread( 204 stdout_thread = threading.Thread(
194 target=self._read_pipe_and_set_event, 205 target=ServerTest._read_pipe_and_set_event,
195 args=(p.stdout, stdout_event)) 206 args=(proc.stdout, stdout_event))
196 stdout_thread.daemon = True 207 stdout_thread.daemon = True
197 stdout_thread.start() 208 stdout_thread.start()
198 209
199 stderr_event = threading.Event() 210 stderr_event = threading.Event()
200 stderr_thread = threading.Thread( 211 stderr_thread = threading.Thread(
201 target=self._read_pipe_and_set_event, 212 target=ServerTest._read_pipe_and_set_event,
202 args=(p.stderr, stderr_event)) 213 args=(proc.stderr, stderr_event))
203 stderr_thread.daemon = True 214 stderr_thread.daemon = True
204 stderr_thread.start() 215 stderr_thread.start()
205 216
206 # Wait for the adb client to finish. Once that has occurred, if 217 # Wait for the adb client to finish. Once that has occurred, if
207 # stdin/stderr/stdout are still open, it must be open in the adb 218 # stdin/stderr/stdout are still open, it must be open in the adb
208 # server. 219 # server.
209 p.wait() 220 proc.wait()
210 221
211 # Try to write to stdin which we expect is closed. If it isn't 222 # Try to write to stdin which we expect is closed. If it isn't
212 # closed, we should get an IOError. If we don't get an IOError, 223 # closed, we should get an IOError. If we don't get an IOError,
@@ -214,7 +225,7 @@ class NonApiTest(unittest.TestCase):
214 # probably letting the adb server inherit stdin which would be 225 # probably letting the adb server inherit stdin which would be
215 # wrong. 226 # wrong.
216 with self.assertRaises(IOError): 227 with self.assertRaises(IOError):
217 p.stdin.write('x') 228 proc.stdin.write('x')
218 229
219 # Wait a few seconds for stdout/stderr to be closed (in the success 230 # Wait a few seconds for stdout/stderr to be closed (in the success
220 # case, this won't wait at all). If there is a timeout, that means 231 # case, this won't wait at all). If there is a timeout, that means
@@ -228,8 +239,12 @@ class NonApiTest(unittest.TestCase):
228 subprocess.check_output(['adb', '-P', str(port), 'kill-server'], 239 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
229 stderr=subprocess.STDOUT) 240 stderr=subprocess.STDOUT)
230 241
231 # Use SO_LINGER to cause TCP RST segment to be sent on socket close. 242
243class EmulatorTest(unittest.TestCase):
244 """Tests for the emulator connection."""
245
232 def _reset_socket_on_close(self, sock): 246 def _reset_socket_on_close(self, sock):
247 """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
233 # The linger structure is two shorts on Windows, but two ints on Unix. 248 # The linger structure is two shorts on Windows, but two ints on Unix.
234 linger_format = 'hh' if os.name == 'nt' else 'ii' 249 linger_format = 'hh' if os.name == 'nt' else 'ii'
235 l_onoff = 1 250 l_onoff = 1
@@ -248,7 +263,7 @@ class NonApiTest(unittest.TestCase):
248 Bug: https://code.google.com/p/android/issues/detail?id=21021 263 Bug: https://code.google.com/p/android/issues/detail?id=21021
249 """ 264 """
250 with contextlib.closing( 265 with contextlib.closing(
251 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener: 266 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
252 # Use SO_REUSEADDR so subsequent runs of the test can grab the port 267 # Use SO_REUSEADDR so subsequent runs of the test can grab the port
253 # even if it is in TIME_WAIT. 268 # even if it is in TIME_WAIT.
254 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 269 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -258,7 +273,7 @@ class NonApiTest(unittest.TestCase):
258 273
259 # Now that listening has started, start adb emu kill, telling it to 274 # Now that listening has started, start adb emu kill, telling it to
260 # connect to our mock emulator. 275 # connect to our mock emulator.
261 p = subprocess.Popen( 276 proc = subprocess.Popen(
262 ['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'], 277 ['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'],
263 stderr=subprocess.STDOUT) 278 stderr=subprocess.STDOUT)
264 279
@@ -267,12 +282,16 @@ class NonApiTest(unittest.TestCase):
267 # If WSAECONNABORTED (10053) is raised by any socket calls, 282 # If WSAECONNABORTED (10053) is raised by any socket calls,
268 # then adb probably isn't reading the data that we sent it. 283 # then adb probably isn't reading the data that we sent it.
269 conn.sendall('Android Console: type \'help\' for a list ' + 284 conn.sendall('Android Console: type \'help\' for a list ' +
270 'of commands\r\n') 285 'of commands\r\n')
271 conn.sendall('OK\r\n') 286 conn.sendall('OK\r\n')
272 287
273 with contextlib.closing(conn.makefile()) as f: 288 with contextlib.closing(conn.makefile()) as connf:
274 self.assertEqual('kill\n', f.readline()) 289 line = connf.readline()
275 self.assertEqual('quit\n', f.readline()) 290 if line.startswith('auth'):
291 # Ignore the first auth line.
292 line = connf.readline()
293 self.assertEqual('kill\n', line)
294 self.assertEqual('quit\n', connf.readline())
276 295
277 conn.sendall('OK: killing emulator, bye bye\r\n') 296 conn.sendall('OK: killing emulator, bye bye\r\n')
278 297
@@ -285,11 +304,15 @@ class NonApiTest(unittest.TestCase):
285 self._reset_socket_on_close(conn) 304 self._reset_socket_on_close(conn)
286 305
287 # Wait for adb to finish, so we can check return code. 306 # Wait for adb to finish, so we can check return code.
288 p.communicate() 307 proc.communicate()
289 308
290 # If this fails, adb probably isn't ignoring WSAECONNRESET when 309 # If this fails, adb probably isn't ignoring WSAECONNRESET when
291 # reading the response from the adb emu kill command (on Windows). 310 # reading the response from the adb emu kill command (on Windows).
292 self.assertEqual(0, p.returncode) 311 self.assertEqual(0, proc.returncode)
312
313
314class ConnectionTest(unittest.TestCase):
315 """Tests for adb connect."""
293 316
294 def test_connect_ipv4_ipv6(self): 317 def test_connect_ipv4_ipv6(self):
295 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6. 318 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
@@ -298,7 +321,7 @@ class NonApiTest(unittest.TestCase):
298 """ 321 """
299 for protocol in (socket.AF_INET, socket.AF_INET6): 322 for protocol in (socket.AF_INET, socket.AF_INET6):
300 try: 323 try:
301 with fake_adb_server(protocol=protocol) as port: 324 with fake_adbd(protocol=protocol) as port:
302 serial = 'localhost:{}'.format(port) 325 serial = 'localhost:{}'.format(port)
303 with adb_connect(self, serial): 326 with adb_connect(self, serial):
304 pass 327 pass
@@ -309,7 +332,7 @@ class NonApiTest(unittest.TestCase):
309 def test_already_connected(self): 332 def test_already_connected(self):
310 """Ensure that an already-connected device stays connected.""" 333 """Ensure that an already-connected device stays connected."""
311 334
312 with fake_adb_server() as port: 335 with fake_adbd() as port:
313 serial = 'localhost:{}'.format(port) 336 serial = 'localhost:{}'.format(port)
314 with adb_connect(self, serial): 337 with adb_connect(self, serial):
315 # b/31250450: this always returns 0 but probably shouldn't. 338 # b/31250450: this always returns 0 but probably shouldn't.
@@ -320,7 +343,7 @@ class NonApiTest(unittest.TestCase):
320 def test_reconnect(self): 343 def test_reconnect(self):
321 """Ensure that a disconnected device reconnects.""" 344 """Ensure that a disconnected device reconnects."""
322 345
323 with fake_adb_server() as port: 346 with fake_adbd() as port:
324 serial = 'localhost:{}'.format(port) 347 serial = 'localhost:{}'.format(port)
325 with adb_connect(self, serial): 348 with adb_connect(self, serial):
326 output = subprocess.check_output(['adb', '-s', serial, 349 output = subprocess.check_output(['adb', '-s', serial,
@@ -328,10 +351,10 @@ class NonApiTest(unittest.TestCase):
328 self.assertEqual(output.strip(), 'device') 351 self.assertEqual(output.strip(), 'device')
329 352
330 # This will fail. 353 # This will fail.
331 p = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'], 354 proc = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'],
332 stdout=subprocess.PIPE, 355 stdout=subprocess.PIPE,
333 stderr=subprocess.STDOUT) 356 stderr=subprocess.STDOUT)
334 output, _ = p.communicate() 357 output, _ = proc.communicate()
335 self.assertEqual(output.strip(), 'error: closed') 358 self.assertEqual(output.strip(), 'error: closed')
336 359
337 subprocess.check_call(['adb', '-s', serial, 'wait-for-device']) 360 subprocess.check_call(['adb', '-s', serial, 'wait-for-device'])
@@ -349,18 +372,16 @@ class NonApiTest(unittest.TestCase):
349 subprocess.check_output(['adb', '-s', serial, 'get-state'], 372 subprocess.check_output(['adb', '-s', serial, 'get-state'],
350 stderr=subprocess.STDOUT) 373 stderr=subprocess.STDOUT)
351 self.fail('Device should not be available') 374 self.fail('Device should not be available')
352 except subprocess.CalledProcessError as e: 375 except subprocess.CalledProcessError as err:
353 self.assertEqual( 376 self.assertEqual(
354 e.output.strip(), 377 err.output.strip(),
355 'error: device \'{}\' not found'.format(serial)) 378 'error: device \'{}\' not found'.format(serial))
356 379
380
357def main(): 381def main():
382 """Main entrypoint."""
358 random.seed(0) 383 random.seed(0)
359 if len(adb.get_devices()) > 0: 384 unittest.main(verbosity=3)
360 suite = unittest.TestLoader().loadTestsFromName(__name__)
361 unittest.TextTestRunner(verbosity=3).run(suite)
362 else:
363 print('Test suite must be run with attached devices')
364 385
365 386
366if __name__ == '__main__': 387if __name__ == '__main__':