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