Skip to content

Commit 40ffe13

Browse files
JeffLIrionfahhem
authored andcommitted
Fix strings and add tests (google#128)
* Fix python3-ism with byte v. str (copied from @rustyhowell) * Changed binary strings to regular strings * Version bump to 1.3.0.dev * If 'serial' is bytes, convert it to unicode * Version bump to 1.3.0.1 * Add changes from @tuxuser
1 parent 82bfd52 commit 40ffe13

File tree

7 files changed

+146
-64
lines changed

7 files changed

+146
-64
lines changed

adb/adb_commands.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,17 @@ def ConnectDevice(self, port_path=None, serial=None, default_timeout_ms=None, **
127127
# If there isnt a handle override (used by tests), build one here
128128
if 'handle' in kwargs:
129129
self._handle = kwargs.pop('handle')
130-
elif serial and b':' in serial:
131-
self._handle = common.TcpHandle(serial, timeout_ms=default_timeout_ms)
132130
else:
133-
self._handle = common.UsbHandle.FindAndOpen(
134-
DeviceIsAvailable, port_path=port_path, serial=serial,
135-
timeout_ms=default_timeout_ms)
131+
# if necessary, convert serial to a unicode string
132+
if isinstance(serial, (bytes, bytearray)):
133+
serial = serial.decode('utf-8')
134+
135+
if serial and ':' in serial:
136+
self._handle = common.TcpHandle(serial, timeout_ms=default_timeout_ms)
137+
else:
138+
self._handle = common.UsbHandle.FindAndOpen(
139+
DeviceIsAvailable, port_path=port_path, serial=serial,
140+
timeout_ms=default_timeout_ms)
136141

137142
self._Connect(**kwargs)
138143

adb/adb_protocol.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ def Connect(cls, usb, banner=b'notadb', rsa_keys=None, auth_timeout_ms=100):
302302
InvalidResponseError: When the device does authentication in an
303303
unexpected way.
304304
"""
305+
# In py3, convert unicode to bytes. In py2, convert str to bytes.
306+
# It's later joined into a byte string, so in py2, this ends up kind of being a no-op.
307+
if isinstance(banner, str):
308+
banner = bytearray(banner, 'utf-8')
309+
305310
msg = cls(
306311
command=b'CNXN', arg0=VERSION, arg1=MAX_ADB_DATA,
307312
data=b'host::%s\0' % banner)

adb/common.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,15 +298,26 @@ def __init__(self, serial, timeout_ms=None):
298298
299299
Host may be an IP address or a host name.
300300
"""
301-
if b':' in serial:
302-
(host, port) = serial.split(b':')
301+
# if necessary, convert serial to a unicode string
302+
if isinstance(serial, (bytes, bytearray)):
303+
serial = serial.decode('utf-8')
304+
305+
if ':' in serial:
306+
self.host, self.port = serial.split(':')
303307
else:
304-
host = serial
305-
port = 5555
306-
self._serial_number = '%s:%s' % (host, port)
308+
self.host = serial
309+
self.port = 5555
310+
311+
self._connection = None
312+
self._serial_number = '%s:%s' % (self.host, self.port)
307313
self._timeout_ms = float(timeout_ms) if timeout_ms else None
314+
315+
self._connect()
316+
317+
def _connect(self):
308318
timeout = self.TimeoutSeconds(self._timeout_ms)
309-
self._connection = socket.create_connection((host, port), timeout=timeout)
319+
self._connection = socket.create_connection((self.host, self.port),
320+
timeout=timeout)
310321
if timeout:
311322
self._connection.setblocking(0)
312323

test/adb_test.py

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
from io import BytesIO
1818
import struct
1919
import unittest
20+
from mock import mock
2021

22+
23+
from adb import common
2124
from adb import adb_commands
2225
from adb import adb_protocol
23-
from adb.usb_exceptions import TcpTimeoutException
26+
from adb.usb_exceptions import TcpTimeoutException, DeviceNotFoundError
2427
import common_stub
2528

2629

@@ -78,10 +81,9 @@ def _Connect(cls, usb):
7881

7982

8083
class AdbTest(BaseAdbTest):
81-
8284
@classmethod
8385
def _ExpectCommand(cls, service, command, *responses):
84-
usb = common_stub.StubUsb()
86+
usb = common_stub.StubUsb(device=None, setting=None)
8587
cls._ExpectConnection(usb)
8688
cls._ExpectOpen(usb, b'%s:%s\0' % (service, command))
8789

@@ -91,12 +93,19 @@ def _ExpectCommand(cls, service, command, *responses):
9193
return usb
9294

9395
def testConnect(self):
94-
usb = common_stub.StubUsb()
96+
usb = common_stub.StubUsb(device=None, setting=None)
9597
self._ExpectConnection(usb)
9698

9799
dev = adb_commands.AdbCommands()
98100
dev.ConnectDevice(handle=usb, banner=BANNER)
99101

102+
def testConnectSerialString(self):
103+
dev = adb_commands.AdbCommands()
104+
105+
with mock.patch.object(common.UsbHandle, 'FindAndOpen', return_value=None):
106+
with mock.patch.object(adb_commands.AdbCommands, '_Connect', return_value=None):
107+
dev.ConnectDevice(serial='/dev/invalidHandle')
108+
100109
def testSmallResponseShell(self):
101110
command = b'keepin it real'
102111
response = 'word.'
@@ -196,7 +205,7 @@ def _MakeWriteSyncPacket(cls, command, data=b'', size=None):
196205

197206
@classmethod
198207
def _ExpectSyncCommand(cls, write_commands, read_commands):
199-
usb = common_stub.StubUsb()
208+
usb = common_stub.StubUsb(device=None, setting=None)
200209
cls._ExpectConnection(usb)
201210
cls._ExpectOpen(usb, b'sync:\0')
202211

@@ -246,7 +255,7 @@ class TcpTimeoutAdbTest(BaseAdbTest):
246255

247256
@classmethod
248257
def _ExpectCommand(cls, service, command, *responses):
249-
tcp = common_stub.StubTcp()
258+
tcp = common_stub.StubTcp('10.0.0.123')
250259
cls._ExpectConnection(tcp)
251260
cls._ExpectOpen(tcp, b'%s:%s\0' % (service, command))
252261

@@ -262,7 +271,7 @@ def _run_shell(self, cmd, timeout_ms=None):
262271
dev.Shell(cmd, timeout_ms=timeout_ms)
263272

264273
def testConnect(self):
265-
tcp = common_stub.StubTcp()
274+
tcp = common_stub.StubTcp('10.0.0.123')
266275
self._ExpectConnection(tcp)
267276
dev = adb_commands.AdbCommands()
268277
dev.ConnectDevice(handle=tcp, banner=BANNER)
@@ -276,5 +285,31 @@ def testTcpTimeout(self):
276285
command,
277286
timeout_ms=timeout_ms)
278287

288+
289+
class TcpHandleTest(unittest.TestCase):
290+
def testInitWithHost(self):
291+
tcp = common_stub.StubTcp('10.11.12.13')
292+
293+
self.assertEqual('10.11.12.13:5555', tcp._serial_number)
294+
self.assertEqual(None, tcp._timeout_ms)
295+
296+
def testInitWithHostAndPort(self):
297+
tcp = common_stub.StubTcp('10.11.12.13:5678')
298+
299+
self.assertEqual('10.11.12.13:5678', tcp._serial_number)
300+
self.assertEqual(None, tcp._timeout_ms)
301+
302+
def testInitWithTimeout(self):
303+
tcp = common_stub.StubTcp('10.0.0.2', timeout_ms=234.5)
304+
305+
self.assertEqual('10.0.0.2:5555', tcp._serial_number)
306+
self.assertEqual(234.5, tcp._timeout_ms)
307+
308+
def testInitWithTimeoutInt(self):
309+
tcp = common_stub.StubTcp('10.0.0.2', timeout_ms=234)
310+
311+
self.assertEqual('10.0.0.2:5555', tcp._serial_number)
312+
self.assertEqual(234.0, tcp._timeout_ms)
313+
279314
if __name__ == '__main__':
280315
unittest.main()

test/common_stub.py

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
import string
66
import sys
77
import time
8-
from adb.usb_exceptions import TcpTimeoutException
8+
from mock import mock
9+
10+
from adb.common import TcpHandle, UsbHandle
11+
from adb.usb_exceptions import TcpTimeoutException
912

1013
PRINTABLE_DATA = set(string.printable) - set(string.whitespace)
1114

@@ -16,33 +19,23 @@ def _Dotify(data):
1619
return ''.join(char if char in PRINTABLE_DATA else '.' for char in data)
1720

1821

19-
class StubUsb(object):
20-
"""UsbHandle stub."""
21-
22-
def __init__(self):
22+
class StubHandleBase(object):
23+
def __init__(self, timeout_ms, is_tcp=False):
2324
self.written_data = []
2425
self.read_data = []
25-
self.timeout_ms = 0
26+
self.is_tcp = is_tcp
27+
self.timeout_ms = timeout_ms
2628

27-
def BulkWrite(self, data, unused_timeout_ms=None):
28-
expected_data = self.written_data.pop(0)
29-
if isinstance(data, bytearray):
30-
data = bytes(data)
31-
if not isinstance(data, bytes):
32-
data = data.encode('utf8')
33-
if expected_data != data:
34-
raise ValueError('Expected %s (%s) got %s (%s)' % (
35-
binascii.hexlify(expected_data), _Dotify(expected_data),
36-
binascii.hexlify(data), _Dotify(data)))
29+
def _signal_handler(self, signum, frame):
30+
raise TcpTimeoutException('End of time')
3731

38-
def BulkRead(self, length,
39-
timeout_ms=None): # pylint: disable=unused-argument
40-
data = self.read_data.pop(0)
41-
if length < len(data):
42-
raise ValueError(
43-
'Overflow packet length. Read %d bytes, got %d bytes: %s',
44-
length, len(data))
45-
return bytearray(data)
32+
def _return_seconds(self, time_ms):
33+
return (float(time_ms)/1000) if time_ms else 0
34+
35+
def _alarm_sounder(self, timeout_ms):
36+
signal.signal(signal.SIGALRM, self._signal_handler)
37+
signal.setitimer(signal.ITIMER_REAL,
38+
self._return_seconds(timeout_ms))
4639

4740
def ExpectWrite(self, data):
4841
if not isinstance(data, bytes):
@@ -54,22 +47,6 @@ def ExpectRead(self, data):
5447
data = data.encode('utf8')
5548
self.read_data.append(data)
5649

57-
def Timeout(self, timeout_ms):
58-
return timeout_ms if timeout_ms is not None else self.timeout_ms
59-
60-
class StubTcp(StubUsb):
61-
62-
def _signal_handler(self, signum, frame):
63-
raise TcpTimeoutException('End of time')
64-
65-
def _return_seconds(self, time_ms):
66-
return (float(time_ms)/1000) if time_ms else 0
67-
68-
def _alarm_sounder(self, timeout_ms):
69-
signal.signal(signal.SIGALRM, self._signal_handler)
70-
signal.setitimer(signal.ITIMER_REAL,
71-
self._return_seconds(timeout_ms))
72-
7350
def BulkWrite(self, data, timeout_ms=None):
7451
expected_data = self.written_data.pop(0)
7552
if isinstance(data, bytearray):
@@ -80,8 +57,8 @@ def BulkWrite(self, data, timeout_ms=None):
8057
raise ValueError('Expected %s (%s) got %s (%s)' % (
8158
binascii.hexlify(expected_data), _Dotify(expected_data),
8259
binascii.hexlify(data), _Dotify(data)))
83-
if b'i_need_a_timeout' in data:
84-
self._alarm_sounder(timeout_ms)
60+
if self.is_tcp and b'i_need_a_timeout' in data:
61+
self._alarm_sounder(timeout_ms)
8562
time.sleep(2*self._return_seconds(timeout_ms))
8663

8764
def BulkRead(self, length,
@@ -91,8 +68,56 @@ def BulkRead(self, length,
9168
raise ValueError(
9269
'Overflow packet length. Read %d bytes, got %d bytes: %s',
9370
length, len(data))
94-
if b'i_need_a_timeout' in data:
95-
self._alarm_sounder(timeout_ms)
71+
if self.is_tcp and b'i_need_a_timeout' in data:
72+
self._alarm_sounder(timeout_ms)
9673
time.sleep(2*self._return_seconds(timeout_ms))
97-
return bytearray(data)
74+
return bytearray(data)
75+
76+
def Timeout(self, timeout_ms):
77+
return timeout_ms if timeout_ms is not None else self.timeout_ms
78+
79+
80+
class StubUsb(UsbHandle):
81+
"""UsbHandle stub."""
82+
def __init__(self, device, setting, usb_info=None, timeout_ms=None):
83+
super(StubUsb, self).__init__(device, setting, usb_info, timeout_ms)
84+
self.stub_base = StubHandleBase(0)
85+
86+
def ExpectWrite(self, data):
87+
return self.stub_base.ExpectWrite(data)
88+
89+
def ExpectRead(self, data):
90+
return self.stub_base.ExpectRead(data)
91+
92+
def BulkWrite(self, data, unused_timeout_ms=None):
93+
return self.stub_base.BulkWrite(data, unused_timeout_ms)
94+
95+
def BulkRead(self, length, timeout_ms=None):
96+
return self.stub_base.BulkRead(length, timeout_ms)
97+
98+
def Timeout(self, timeout_ms):
99+
return self.stub_base.Timeout(timeout_ms)
100+
101+
102+
class StubTcp(TcpHandle):
103+
def __init__(self, serial, timeout_ms=None):
104+
"""TcpHandle stub."""
105+
self._connect = mock.MagicMock(return_value=None)
106+
107+
super(StubTcp, self).__init__(serial, timeout_ms)
108+
self.stub_base = StubHandleBase(0, is_tcp=True)
98109

110+
def ExpectWrite(self, data):
111+
return self.stub_base.ExpectWrite(data)
112+
113+
def ExpectRead(self, data):
114+
return self.stub_base.ExpectRead(data)
115+
116+
def BulkWrite(self, data, unused_timeout_ms=None):
117+
return self.stub_base.BulkWrite(data, unused_timeout_ms)
118+
119+
def BulkRead(self, length, timeout_ms=None):
120+
return self.stub_base.BulkRead(length, timeout_ms)
121+
122+
def Timeout(self, timeout_ms):
123+
return self.stub_base.Timeout(timeout_ms)

test/fastboot_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
class FastbootTest(unittest.TestCase):
2727

2828
def setUp(self):
29-
self.usb = common_stub.StubUsb()
29+
self.usb = common_stub.StubUsb(device=None, setting=None)
3030

3131
@staticmethod
3232
def _SumLengths(items):

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ envlist =
1212
deps =
1313
pytest
1414
pytest-cov
15+
mock
1516
usedevelop = True
1617
commands = py.test --cov adb test

0 commit comments

Comments
 (0)