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