xref: /aosp_15_r20/external/autotest/client/cros/cellular/mmtest.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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