blob: c494cbb90a26bf6035ae5ef194b9b2ec8c87752f [file] [log] [blame]
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import time
from autotest_lib.client.bin import test
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros.cellular import cell_tools, mm
from autotest_lib.client.cros.cellular.pseudomodem import mm1
from autotest_lib.client.cros.cellular.pseudomodem import modem_3gpp
from autotest_lib.client.cros.cellular.pseudomodem import modem_cdma
from autotest_lib.client.cros.cellular.pseudomodem import pseudomodem
from autotest_lib.client.cros import backchannel, network, flimflam_test_path
import flimflam
CONNECT_CONFIG_TIMEOUT = 120
CONNECT_SERVICE_TIMEOUT = 30
DISCONNECT_TIMEOUT = 60
class DisconnectFailTest(object):
"""
DisconnectFailTest implements common functionality in all test cases.
"""
def __init__(self, pmm_context, test):
self.pmm_context = pmm_context
self.test_modem = None
self.test = test
self._SetupTestModem()
def Run(self):
"""
Runs the test.
@raises test.TestFail, if |test_modem| hasn't been initialized.
"""
if not self.test_modem:
raise test.TestFail('Uninitialized test modem')
self.pmm_context.SetModem(self.test_modem)
self._RunTest()
def _SetupTestModem(self):
raise NotImplementedError()
def _GetModemClass(self):
if self.test.family == '3GPP':
modem_class = modem_3gpp.Modem3gpp
elif self.test.family == 'CDMA':
modem_class = modem_cdma.ModemCdma
else:
raise error.TestError('Invalid pseudo modem family: ' + \
str(self.test.family))
return modem_class
def _RunTest(self):
raise NotImplementedError()
class DisconnectWhileStateIsDisconnectingTest(DisconnectFailTest):
"""
Simulates a disconnect failure while the modem is still disconnecting.
Fails if the service doesn't remain connected.
"""
def _SetupTestModem(self):
modem_class = self._GetModemClass()
class _TestModem(modem_class):
def Disconnect(
self, bearer_path, return_cb, raise_cb, *return_cb_args):
"""
Test implementation of
org.freedesktop.ModemManager1.Modem.Simple.Disconnect. Sets the
modem state to DISCONNECTING and then fails, fooling shill into
thinking that the disconnect failed while disconnecting.
Refer to modem_simple.ModemSimple.Connect for documentation.
"""
# Proceed normally, if this Disconnect was initiated by a call
# to Disable, which may happen due to auto-connect.
if self.disable_step:
modem_class.Disconnect(
self, bearer_path, return_cb, raise_cb, return_cb_args)
return
self.ChangeState(mm1.MM_MODEM_STATE_DISCONNECTING,
mm1.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN)
time.sleep(5)
raise mm1.MMCoreError(mm1.MMCoreError.FAILED)
self.test_modem = _TestModem()
def _RunTest(self):
network.ResetAllModems(self.test.flim)
time.sleep(5)
# Connect to the service if not already connected.
if not self.test.IsServiceConnected():
cell_tools.ConnectToCellular(self.test.flim)
# Disconnect attempt should fail.
service = self.test.FindCellularService()
self.test.flim.DisconnectService(service=service,
wait_timeout=DISCONNECT_TIMEOUT)
# Service should remain connected.
if not self.test.IsServiceConnected():
raise error.TestError('Service should remain connected after '
'disconnect failure.')
class DisconnectWhileDisconnectInProgressTest(DisconnectFailTest):
"""
Simulates a disconnect failure on successive disconnects. Fails if the
service doesn't remain connected.
"""
def _SetupTestModem(self):
modem_class = self._GetModemClass()
class _TestModem(modem_class):
def __init__(self):
modem_class.__init__(self)
self.disconnect_count = 0
def Disconnect(
self, bearer_path, return_cb, raise_cb, *return_cb_args):
"""
Test implementation of
org.freedesktop.ModemManager1.Modem.Simple.Disconnect. Keeps
count of successive disconnect operations and fails during all
but the first one.
Refer to modem_simple.ModemSimple.Connect for documentation.
"""
# Proceed normally, if this Disconnect was initiated by a call
# to Disable, which may happen due to auto-connect.
if self.disable_step:
modem_class.Disconnect(
self, bearer_path, return_cb, raise_cb, return_cb_args)
return
# On the first call, set the state to DISCONNECTING.
self.disconnect_count += 1
if self.disconnect_count == 1:
self.ChangeState(mm1.MM_MODEM_STATE_DISCONNECTING,
mm1.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN)
time.sleep(5)
else:
raise mm1.MMCoreError(mm1.MMCoreError.FAILED)
self.test_modem = _TestModem()
def _RunTest(self):
network.ResetAllModems(self.test.flim)
time.sleep(5)
# Connect to the service if not already connected.
if not self.test.IsServiceConnected():
cell_tools.ConnectToCellular(self.test.flim)
# Issue first disconnect. Service should remain connected.
service = self.test.FindCellularService()
self.test.flim.DisconnectService(service=service,
wait_timeout=DISCONNECT_TIMEOUT)
if not self.test.IsServiceConnected():
raise error.TestError('Service should remain connected after '
'first disconnect.')
# Modem state should be disconnecting.
manager, modem_path = mm.PickOneModem('')
modem = manager.GetModem(modem_path)
props = modem.GetAll(mm1.I_MODEM)
if not props['State'] == mm1.MM_MODEM_STATE_DISCONNECTING:
raise error.TestError('Modem should be in the DISCONNECTING state.')
# Issue second disconnect. Service should remain connected.
self.test.flim.DisconnectService(service=service,
wait_timeout=DISCONNECT_TIMEOUT)
if not self.test.IsServiceConnected():
raise error.TestError('Service should remain connected after '
'disconnect failure.')
class DisconnectFailOtherTest(DisconnectFailTest):
"""
Simulates a disconnect failure. Fails if the service doesn't disconnect.
"""
def _SetupTestModem(self):
modem_class = self._GetModemClass()
class _TestModem(modem_class):
def Disconnect(
self, bearer_path, return_cb, raise_cb, *return_cb_args):
"""
Test implementation of
org.freedesktop.ModemManager1.Modem.Simple.Disconnect.
Fails with an error.
Refer to modem_simple.ModemSimple.Connect for documentation.
"""
# Proceed normally, if this Disconnect was initiated by a call
# to Disable, which may happen due to auto-connect.
if self.disable_step:
modem_class.Disconnect(
self, bearer_path, return_cb, raise_cb, return_cb_args)
return
raise mm1.MMCoreError(mm1.MMCoreError.FAILED)
self.test_modem = _TestModem()
def _RunTest(self):
network.ResetAllModems(self.test.flim)
time.sleep(5)
# Connect to the service if not already connected.
if not self.test.IsServiceConnected():
cell_tools.ConnectToCellular(self.test.flim)
# Disconnect attempt should fail.
service = self.test.FindCellularService()
self.test.flim.DisconnectService(service=service,
wait_timeout=DISCONNECT_TIMEOUT)
# Service should be cleaned up as if disconnect succeeded.
if not self.test.IsServiceDisconnected():
raise error.TestError('Service should be disconnected.')
class network_3GDisconnectFailure(test.test):
"""
The test uses the pseudo modem manager to simulate two failure scenarios of
a Disconnect call: failure while the modem state is DISCONNECTING and
failure while it is CONNECTED. The expected behavior of shill is to do
nothing if the modem state is DISCONNECTING and to clean up the service
otherwise.
"""
version = 1
def IsServiceConnected(self):
"""
@return True, if service is connected.
"""
service = self.FindCellularService()
properties = service.GetProperties(utf8_strings=True)
state = properties.get('State', None)
return state in ['portal', 'online']
def IsServiceDisconnected(self):
"""
@return True, if service is disconnected.
"""
service = self.FindCellularService()
properties = service.GetProperties(utf8_strings=True)
state = properties.get('State', None)
return state == 'idle'
def FindCellularService(self):
"""
Looks for a cellular service.
@return A Service DBus proxy object.
@raises error.TestError, if no cellular service can be found.
"""
service = self.flim.FindCellularService()
if not service:
raise error.TestError('Could not find cellular service.')
return service
def run_once(self, pseudomodem_family='3GPP'):
self.family = pseudomodem_family
with backchannel.Backchannel():
with pseudomodem.TestModemManagerContext(True) as tmmc:
self.flim = flimflam.FlimFlam()
self.device_manager = flimflam.DeviceManager(self.flim)
self.flim.SetDebugTags(
'dbus+service+device+modem+cellular+portal+network+'
'manager+dhcp')
tests = [
DisconnectWhileStateIsDisconnectingTest(
tmmc.GetPseudoModemManager(), self),
DisconnectWhileDisconnectInProgressTest(
tmmc.GetPseudoModemManager(), self),
DisconnectFailOtherTest(tmmc.GetPseudoModemManager(), self)
]
try:
self.device_manager.ShutdownAllExcept('cellular')
for test in tests:
test.Run()
finally:
self.device_manager.RestoreDevices()