1# Lint as: python2, python3 2# Copyright (c) 2011 The Chromium OS 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 6import dbus, os, subprocess, time 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.cros.cellular import cellular_logging 10from autotest_lib.client.cros.cellular import modem 11 12log = cellular_logging.SetupCellularLogging('mm_test') 13 14 15class ModemManagerTest(object): 16 """Wrapper for starting up ModemManager in an artificial testing 17 environment, connected to a fake modem program and talking to a 18 fake (tun) network device. 19 20 The test using this must ensure the setup of the fakegudev and 21 fakemodem deps. 22 """ 23 24 def __init__(self, autodir, modem_pattern_files): 25 self.autodir=autodir # not great. Examine deps directly? 26 self.modem_pattern_files = modem_pattern_files 27 self.modemmanager = None 28 self.fakemodem_process = None 29 self.fakenet_process = None 30 31 def _start_fake_network(self): 32 """Start the fakenetwork program and return the fake interface name 33 34 Start up the fakenet program, which uses the tun driver to create 35 a network device. 36 37 Returns the name of the fake network interface. 38 Sets self.fakenet_process as a handle to the process. 39 """ 40 self.fakenet_process = subprocess.Popen( 41 os.path.join(self.autodir,'deps/fakemodem/bin','fakenet'), 42 stdout=subprocess.PIPE) 43 return self.fakenet_process.stdout.readline().rstrip() 44 45 46 def _start_fake_modem(self, patternfiles): 47 """Start the fakemodem program and return the pty path to access it 48 49 Start up the fakemodem program 50 Argument: 51 patternfiles -- List of files to read for command/response patterns 52 53 Returns the device path of the pty that serves the fake modem, e.g. 54 /dev/pts/4. 55 Sets self.fakemodem_process as a handle to the process, and 56 self.fakemodem as a DBus interface to it. 57 """ 58 scriptargs = ["--patternfile=" + x for x in patternfiles] 59 name = os.path.join(self.autodir, 'deps/fakemodem/bin', 'fakemodem') 60 self.fakemodem_process = subprocess.Popen( 61 [os.path.join(self.autodir, 'deps/fakemodem/bin', 'fakemodem')] 62 + scriptargs, 63 stdout=subprocess.PIPE) 64 ptyname = self.fakemodem_process.stdout.readline().rstrip() 65 time.sleep(2) # XXX 66 self.fakemodem = dbus.Interface( 67 dbus.SystemBus().get_object('org.chromium.FakeModem', '/'), 68 'org.chromium.FakeModem') 69 return ptyname 70 71 72 def _start_modemmanager(self, netname, modemname): 73 """Start modemmanager under the control of fake devices. 74 75 Arguments: 76 netname -- fake network interface name (e.g. tun0) 77 modemname -- path to pty node device of fake modem (e.g. /dev/pts/4) 78 79 Returns... 80 81 """ 82 id_props = ['property_ID_MM_CANDIDATE=1', 83 'property_ID_VENDOR_ID=04e8', # Samsung USB VID 84 'property_ID_MODEL_ID=6872' # Y3300 modem PID 85 ] 86 tty_device = (['device_file=%s' % (modemname), 87 'name=%s' % (modemname[5:]), # remove leading /dev/ 88 'subsystem=tty', 89 'driver=fake', 90 'sysfs_path=/sys/devices/fake/tty', 91 'parent=/dev/fake-parent'] + 92 id_props) 93 net_device = (['device_file=/dev/fakenet', 94 'name=%s' % (netname), 95 'subsystem=net', 96 'driver=fake', 97 'sysfs_path=/sys/devices/fake/net', 98 'parent=/dev/fake-parent'] + 99 id_props) 100 parent_device=['device_file=/dev/fake-parent', 101 'sysfs_path=/sys/devices/fake/parent', 102 'devtype=usb_device', 103 'subsystem=usb'] 104 environment = { 'FAKEGUDEV_DEVICES' : ':'.join(tty_device + 105 net_device + 106 parent_device), 107 'FAKEGUDEV_BLOCK_REAL' : 'true', 108 'G_DEBUG' : 'fatal_criticals', 109 'LD_PRELOAD' : os.path.join(self.autodir, 110 "deps/fakegudev/lib", 111 "libfakegudev.so") } 112 self.modemmanager = subprocess.Popen(['/usr/sbin/modem-manager', 113 '--debug', 114 '--log-level=DEBUG', 115 '--log-file=/tmp/mm-log'], 116 env=environment) 117 time.sleep(3) # wait for DeviceAdded signal? 118 self.modemmanager.poll() 119 if self.modemmanager.returncode is not None: 120 self.modemmanager = None 121 raise error.TestFail("ModemManager quit early") 122 123 # wait for MM to stabilize? 124 return modem.ModemManager(provider='org.freedesktop') 125 126 def _stop_fake_network(self): 127 if self.fakenet_process: 128 self.fakenet_process.poll() 129 if self.fakenet_process.returncode is None: 130 self.fakenet_process.terminate() 131 self.fakenet_process.wait() 132 133 def _stop_fake_modem(self): 134 if self.fakemodem_process: 135 self.fakemodem_process.poll() 136 if self.fakemodem_process.returncode is None: 137 self.fakemodem_process.terminate() 138 self.fakemodem_process.wait() 139 140 def _stop_modemmanager(self): 141 if self.modemmanager: 142 self.modemmanager.poll() 143 if self.modemmanager.returncode is None: 144 self.modemmanager.terminate() 145 self.modemmanager.wait() 146 147 148 def __enter__(self): 149 fakenetname = self._start_fake_network() 150 fakemodemname = self._start_fake_modem(self.modem_pattern_files) 151 self.mm = self._start_modemmanager(fakenetname, fakemodemname) 152 # This would be better handled by listening for DeviceAdded, but 153 # since we've blocked everything else and only supplied data for 154 # one modem, it's going to be right 155 self.modem_object_path = self.mm.path + '/Modems/0' 156 return self 157 158 def __exit__(self, exception, value, traceback): 159 self._stop_modemmanager() 160 self._stop_fake_modem() 161 self._stop_fake_network() 162 return False 163