xref: /aosp_15_r20/external/chromium-trace/catapult/devil/devil/utils/find_usb_devices_test.py (revision 1fa4b3da657c0e9ad43c0220bacf9731820715a5)
1#!/usr/bin/env python
2# Copyright 2016 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6# pylint: disable=protected-access
7"""
8Unit tests for the contents of find_usb_devices.py.
9
10Device tree for these tests is as follows:
11Bus 001:
121: Device 011 "foo"
132: Device 012 "bar"
143: Device 013 "baz"
15
16Bus 002:
171: Device 011 "quux"
182: Device 020 "My Test HUB" #hub 1
192:1: Device 021 "usb_device_p7_h1_t0" #physical port 7 on hub 1, on ttyUSB0
202:3: Device 022 "usb_device_p5_h1_t1" #physical port 5 on hub 1, on ttyUSB1
212:4: Device 023 "My Test Internal HUB" #internal section of hub 1
222:4:2: Device 024 "usb_device_p3_h1_t2" #physical port 3 on hub 1, on ttyUSB2
232:4:3: Device 026 "Not a Battery Monitor" #physical port 1 on hub 1, on ttyUSB3
242:4:4: Device 025 "usb_device_p1_h1_t3" #physical port 1 on hub 1, on ttyUSB3
253: Device 100 "My Test HUB" #hub 2
263:4: Device 101 "My Test Internal HUB" #internal section of hub 2
273:4:4: Device 102 "usb_device_p1_h2_t4" #physical port 1 on hub 2, on ttyusb4
28"""
29
30import logging
31import unittest
32
33from devil import devil_env
34from devil.utils import find_usb_devices
35from devil.utils import lsusb
36from devil.utils import usb_hubs
37
38with devil_env.SysPath(devil_env.PYMOCK_PATH):
39  import mock  # pylint: disable=import-error
40
41# Output of lsusb.lsusb().
42# We just test that the dictionary is working by creating an
43# "ID number" equal to (bus_num*1000)+device_num and seeing if
44# it is picked up correctly. Also we test the description
45
46DEVLIST = [(1, 11, 'foo'), (1, 12, 'bar'), (1, 13, 'baz'), (2, 11, 'quux'),
47           (2, 20, 'My Test HUB'), (2, 21, 'ID 0403:6001 usb_device_p7_h1_t0'),
48           (2, 22, 'ID 0403:6001 usb_device_p5_h1_t1'),
49           (2, 23, 'My Test Internal HUB'),
50           (2, 24, 'ID 0403:6001 usb_device_p3_h1_t2'),
51           (2, 25, 'ID 0403:6001 usb_device_p1_h1_t3'),
52           (2, 26, 'Not a Battery Monitor'), (2, 100, 'My Test HUB'),
53           (2, 101, 'My Test Internal HUB'),
54           (2, 102, 'ID 0403:6001 usb_device_p1_h1_t4')]
55
56LSUSB_OUTPUT = [{
57    'bus': b,
58    'device': d,
59    'desc': t,
60    'id': (1000 * b) + d
61} for (b, d, t) in DEVLIST]
62
63# Note: "Lev", "Cnt", "Spd", and "MxCh" are not used by parser,
64# so we just leave them as zeros here. Also note that the port
65# numbers reported here start at 0, so they're 1 less than the
66# port numbers reported elsewhere.
67USB_DEVICES_OUTPUT = '''
68T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 11 Spd=000 MxCh=00
69S:  SerialNumber=FooSerial
70T:  Bus=01 Lev=00 Prnt=00 Port=01 Cnt=00 Dev#= 12 Spd=000 MxCh=00
71S:  SerialNumber=BarSerial
72T:  Bus=01 Lev=00 Prnt=00 Port=02 Cnt=00 Dev#= 13 Spd=000 MxCh=00
73S:  SerialNumber=BazSerial
74
75T:  Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 11 Spd=000 MxCh=00
76
77T:  Bus=02 Lev=00 Prnt=00 Port=01 Cnt=00 Dev#= 20 Spd=000 MxCh=00
78T:  Bus=02 Lev=00 Prnt=20 Port=00 Cnt=00 Dev#= 21 Spd=000 MxCh=00
79S:  SerialNumber=UsbDevice0
80T:  Bus=02 Lev=00 Prnt=20 Port=02 Cnt=00 Dev#= 22 Spd=000 MxCh=00
81S:  SerialNumber=UsbDevice1
82T:  Bus=02 Lev=00 Prnt=20 Port=03 Cnt=00 Dev#= 23 Spd=000 MxCh=00
83T:  Bus=02 Lev=00 Prnt=23 Port=01 Cnt=00 Dev#= 24 Spd=000 MxCh=00
84S:  SerialNumber=UsbDevice2
85T:  Bus=02 Lev=00 Prnt=23 Port=03 Cnt=00 Dev#= 25 Spd=000 MxCh=00
86S:  SerialNumber=UsbDevice3
87T:  Bus=02 Lev=00 Prnt=23 Port=02 Cnt=00 Dev#= 26 Spd=000 MxCh=00
88
89T:  Bus=02 Lev=00 Prnt=00 Port=02 Cnt=00 Dev#=100 Spd=000 MxCh=00
90T:  Bus=02 Lev=00 Prnt=100 Port=03 Cnt=00 Dev#=101 Spd=000 MxCh=00
91T:  Bus=02 Lev=00 Prnt=101 Port=03 Cnt=00 Dev#=102 Spd=000 MxCh=00
92'''
93
94RAW_LSUSB_OUTPUT = '''
95Bus 001 Device 011: FAST foo
96Bus 001 Device 012: FAST bar
97Bus 001 Device 013: baz
98Bus 002 Device 011: quux
99Bus 002 Device 020: My Test HUB
100Bus 002 Device 021: ID 0403:6001 usb_device_p7_h1_t0
101Bus 002 Device 022: ID 0403:6001 usb_device_p5_h1_t1
102Bus 002 Device 023: My Test Internal HUB
103Bus 002 Device 024: ID 0403:6001 usb_device_p3_h1_t2
104Bus 002 Device 025: ID 0403:6001 usb_device_p1_h1_t3
105Bus 002 Device 026: Not a Battery Monitor
106Bus 002 Device 100: My Test HUB
107Bus 002 Device 101: My Test Internal HUB
108Bus 002 Device 102: ID 0403:6001 usb_device_p1_h1_t4
109'''
110
111LIST_TTY_OUTPUT = '''
112ttyUSB0
113Something-else-0
114ttyUSB1
115ttyUSB2
116Something-else-1
117ttyUSB3
118ttyUSB4
119Something-else-2
120ttyUSB5
121'''
122
123# Note: The real output will have multiple lines with
124# ATTRS{busnum} and ATTRS{devnum}, but only the first
125# one counts. Thus the test output duplicates this.
126UDEVADM_USBTTY0_OUTPUT = '''
127ATTRS{busnum}=="2"
128ATTRS{devnum}=="21"
129ATTRS{busnum}=="0"
130ATTRS{devnum}=="0"
131'''
132
133UDEVADM_USBTTY1_OUTPUT = '''
134ATTRS{busnum}=="2"
135ATTRS{devnum}=="22"
136ATTRS{busnum}=="0"
137ATTRS{devnum}=="0"
138'''
139
140UDEVADM_USBTTY2_OUTPUT = '''
141ATTRS{busnum}=="2"
142ATTRS{devnum}=="24"
143ATTRS{busnum}=="0"
144ATTRS{devnum}=="0"
145'''
146
147UDEVADM_USBTTY3_OUTPUT = '''
148ATTRS{busnum}=="2"
149ATTRS{devnum}=="25"
150ATTRS{busnum}=="0"
151ATTRS{devnum}=="0"
152'''
153
154UDEVADM_USBTTY4_OUTPUT = '''
155ATTRS{busnum}=="2"
156ATTRS{devnum}=="102"
157ATTRS{busnum}=="0"
158ATTRS{devnum}=="0"
159'''
160
161UDEVADM_USBTTY5_OUTPUT = '''
162ATTRS{busnum}=="2"
163ATTRS{devnum}=="26"
164ATTRS{busnum}=="0"
165ATTRS{devnum}=="0"
166'''
167
168UDEVADM_OUTPUT_DICT = {
169    'ttyUSB0': UDEVADM_USBTTY0_OUTPUT,
170    'ttyUSB1': UDEVADM_USBTTY1_OUTPUT,
171    'ttyUSB2': UDEVADM_USBTTY2_OUTPUT,
172    'ttyUSB3': UDEVADM_USBTTY3_OUTPUT,
173    'ttyUSB4': UDEVADM_USBTTY4_OUTPUT,
174    'ttyUSB5': UDEVADM_USBTTY5_OUTPUT
175}
176
177
178# Identification criteria for Plugable 7-Port Hub
179def isTestHub(node):
180  """Check if a node is a Plugable 7-Port Hub
181  (Model USB2-HUB7BC)
182  The topology of this device is a 4-port hub,
183  with another 4-port hub connected on port 4.
184  """
185  if not isinstance(node, find_usb_devices.USBDeviceNode):
186    return False
187  if 'Test HUB' not in node.desc:
188    return False
189  if not node.HasPort(4):
190    return False
191  return 'Test Internal HUB' in node.PortToDevice(4).desc
192
193
194TEST_HUB = usb_hubs.HubType(isTestHub, {
195    1: 7,
196    2: 6,
197    3: 5,
198    4: {
199        1: 4,
200        2: 3,
201        3: 2,
202        4: 1
203    }
204})
205
206
207class USBScriptTest(unittest.TestCase):
208  def setUp(self):
209    find_usb_devices._GetTtyUSBInfo = mock.Mock(
210        side_effect=lambda x: UDEVADM_OUTPUT_DICT[x])
211    find_usb_devices._GetParsedLSUSBOutput = mock.Mock(
212        return_value=LSUSB_OUTPUT)
213    find_usb_devices._GetUSBDevicesOutput = mock.Mock(
214        return_value=USB_DEVICES_OUTPUT)
215    find_usb_devices._GetCommList = mock.Mock(return_value=LIST_TTY_OUTPUT)
216    lsusb.raw_lsusb = mock.Mock(return_value=RAW_LSUSB_OUTPUT)
217
218  def testGetTTYDevices(self):
219    pp = find_usb_devices.GetAllPhysicalPortToTTYMaps([TEST_HUB])
220    result = list(pp)
221    self.assertEquals(result[0], {
222        7: 'ttyUSB0',
223        5: 'ttyUSB1',
224        3: 'ttyUSB2',
225        2: 'ttyUSB5',
226        1: 'ttyUSB3'
227    })
228    self.assertEquals(result[1], {1: 'ttyUSB4'})
229
230  def testGetPortDeviceMapping(self):
231    pp = find_usb_devices.GetAllPhysicalPortToBusDeviceMaps([TEST_HUB])
232    result = list(pp)
233    self.assertEquals(result[0], {
234        7: (2, 21),
235        5: (2, 22),
236        3: (2, 24),
237        2: (2, 26),
238        1: (2, 25)
239    })
240    self.assertEquals(result[1], {1: (2, 102)})
241
242  def testGetSerialMapping(self):
243    pp = find_usb_devices.GetAllPhysicalPortToSerialMaps([TEST_HUB])
244    result = list(pp)
245    self.assertEquals(result[0], {
246        7: 'UsbDevice0',
247        5: 'UsbDevice1',
248        3: 'UsbDevice2',
249        1: 'UsbDevice3'
250    })
251    self.assertEquals(result[1], {})
252
253  def testFastDeviceDescriptions(self):
254    bd = find_usb_devices.GetBusNumberToDeviceTreeMap()
255    dev_foo = bd[1].FindDeviceNumber(11)
256    dev_bar = bd[1].FindDeviceNumber(12)
257    dev_usb_device_p7_h1_t0 = bd[2].FindDeviceNumber(21)
258    self.assertEquals(dev_foo.desc, 'FAST foo')
259    self.assertEquals(dev_bar.desc, 'FAST bar')
260    self.assertEquals(dev_usb_device_p7_h1_t0.desc,
261                      'ID 0403:6001 usb_device_p7_h1_t0')
262
263  def testDeviceDescriptions(self):
264    bd = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=False)
265    dev_foo = bd[1].FindDeviceNumber(11)
266    dev_bar = bd[1].FindDeviceNumber(12)
267    dev_usb_device_p7_h1_t0 = bd[2].FindDeviceNumber(21)
268    self.assertEquals(dev_foo.desc, 'foo')
269    self.assertEquals(dev_bar.desc, 'bar')
270    self.assertEquals(dev_usb_device_p7_h1_t0.desc,
271                      'ID 0403:6001 usb_device_p7_h1_t0')
272
273  def testDeviceInformation(self):
274    bd = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=False)
275    dev_foo = bd[1].FindDeviceNumber(11)
276    dev_bar = bd[1].FindDeviceNumber(12)
277    dev_usb_device_p7_h1_t0 = bd[2].FindDeviceNumber(21)
278    self.assertEquals(dev_foo.info['id'], 1011)
279    self.assertEquals(dev_bar.info['id'], 1012)
280    self.assertEquals(dev_usb_device_p7_h1_t0.info['id'], 2021)
281
282  def testSerialNumber(self):
283    bd = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=False)
284    dev_foo = bd[1].FindDeviceNumber(11)
285    dev_bar = bd[1].FindDeviceNumber(12)
286    dev_usb_device_p7_h1_t0 = bd[2].FindDeviceNumber(21)
287    self.assertEquals(dev_foo.serial, 'FooSerial')
288    self.assertEquals(dev_bar.serial, 'BarSerial')
289    self.assertEquals(dev_usb_device_p7_h1_t0.serial, 'UsbDevice0')
290
291
292if __name__ == "__main__":
293  logging.getLogger().setLevel(logging.DEBUG)
294  unittest.main(verbosity=2)
295