Example #1
0
    def get():
        cell_mgmt = CellMgmt()

        try:
            signal = cell_mgmt.signal_adv()

        except CellMgmtError:
            signal = Signal(mode="n/a", rssi_dbm=0, ecio_dbm=0.0, csq=0)

        try:
            operator = cell_mgmt.operator()

        except CellMgmtError:
            operator = "n/a"

        try:
            cellular_location = cell_mgmt.get_cellular_location()

        except CellMgmtError:
            cellular_location = CellularLocation(
                lac="n/a",
                cell_id="n/a")

        return CellularInformation(
            signal.mode,
            signal.csq,
            signal.rssi_dbm,
            signal.ecio_dbm,
            operator,
            cellular_location.lac,
            cellular_location.tac,
            cellular_location.nid,
            cellular_location.cell_id,
            cellular_location.bid)
Example #2
0
    def __initial_procedure(self):
        """
        Continuously check Cellular modem existence.
        Set self._dev_name, self._mgr, self._vnstat properly.
        """
        cell_mgmt = CellMgmt()
        wwan_node = None

        for retry in xrange(0, 4):
            if retry == 3:
                return

            try:
                wwan_node = cell_mgmt.m_info().wwan_node
                break
            except CellMgmtError:
                _logger.warning("get wwan_node failure: " + format_exc())
                cell_mgmt.power_cycle(timeout_sec=60)

        self._dev_name = wwan_node
        self.__init_monit_config(
            enable=(self.model.db[0]["enable"]
                    and self.model.db[0]["keepalive"]["enable"] and True
                    and self.model.db[0]["keepalive"]["reboot"]["enable"]
                    and True),
            target_host=self.model.db[0]["keepalive"]["targetHost"],
            iface=self._dev_name,
            cycles=self.model.db[0]["keepalive"]["reboot"]["cycles"])
        self.__create_manager()

        self._vnstat = VnStat(self._dev_name)
Example #3
0
    def __init__(
            self,
            period_sec):
        self._period_sec = period_sec

        self._cell_mgmt = CellMgmt()

        self._stop = True
        self._thread = None

        self._cellular_information = None
Example #4
0
 def setUp(self, mock_sh):
     self.cell_mgmt = CellMgmt()
Example #5
0
class TestCellMgmt(unittest.TestCase):
    @patch("cellular_utility.cell_mgmt.sh")
    def setUp(self, mock_sh):
        self.cell_mgmt = CellMgmt()

    def tearDown(self):
        pass

    def test_start_ip_regex_should_pass(self):
        # arrange
        SUT = ("IP=111.70.154.149\n"
               "SubnetMask=255.255.255.252\n"
               "Gateway=111.70.154.150\n"
               "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_ip_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("111.70.154.149", match.group(1))

    def test_start_netmask_regex_should_pass(self):
        # arrange
        SUT = ("IP=111.70.154.149\n"
               "SubnetMask=255.255.255.252\n"
               "Gateway=111.70.154.150\n"
               "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_netmask_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("255.255.255.252", match.group(1))

    def test_start_gateway_regex_should_pass(self):
        # arrange
        SUT = ("IP=111.70.154.149\n"
               "SubnetMask=255.255.255.252\n"
               "Gateway=111.70.154.150\n"
               "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_gateway_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("111.70.154.150", match.group(1))

    def test_start_dns_regex_should_pass(self):
        # arrange
        SUT = ("IP=111.70.154.149\n"
               "SubnetMask=255.255.255.252\n"
               "Gateway=111.70.154.150\n"
               "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_dns_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("168.95.1.1 168.95.192.1", match.group(1))

    def test_signal_regex_should_pass(self):
        # arrange
        SUT = "umts -41 dbm\n"

        # act
        match = CellMgmt._signal_regex.match(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("umts", match.group(1))
        self.assertEqual("-41", match.group(2))

    def test_m_info_regex_should_pass(self):
        # arrange
        SUT = ("Module=MC7304\n"
               "WWAN_node=wwan0\n"
               "AT_port=/dev/ttyUSB2\n"
               "GPS_port=/dev/ttyUSB1\n"
               "LAC=2817\n"
               "CellID=01073AEE\n"
               "ICC-ID=1234567890123456\n"
               "IMEI=0123456789012345\n"
               "QMI_port=/dev/cdc-wdm0\n")

        # act
        match = CellMgmt._m_info_regex.match(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("MC7304", match.group(1))
        self.assertEqual("wwan0", match.group(2))
        self.assertEqual("2817", match.group(3))
        self.assertEqual("01073AEE", match.group(4))
        self.assertEqual("1234567890123456", match.group(5))
        self.assertEqual("0123456789012345", match.group(6))
        self.assertEqual("/dev/cdc-wdm0", match.group(7))

    def test_operator_regex_should_pass(self):
        # arrange
        SUT = "Chunghwa Telecom\n"

        # act
        match = CellMgmt._operator_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_sim_status_ready_regex_should_pass(self):
        # arrange
        SUT = "+CPIN: READY\n"

        # act
        match = CellMgmt._sim_status_ready_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_sim_status_sim_pin_regex_should_pass(self):
        # arrange
        SUT = "+CPIN: SIM PIN\n"

        # act
        match = CellMgmt._sim_status_sim_pin_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_pin_retry_remain_regex_should_pass(self):
        # arrange
        SUT = ("[/dev/cdc-wdm1] Successfully got card status\n"
               "Provisioning applications:\n"
               "\tPrimary GW:   slot '0', application '0'\n"
               "\tPrimary 1X:   session doesn't exist\n"
               "\tSecondary GW: session doesn't exist\n"
               "\tSecondary 1X: session doesn't exist\n"
               "Card [0]:\n"
               "\tCard state: 'present'\n"
               "\tUPIN state: 'not-initialized'\n"
               "\t\tUPIN retries: '0'\n"
               "\t\tUPUK retries: '0'\n"
               "\tApplication [0]:\n"
               "\t\tApplication type:  'usim (2)'\n"
               "\t\tApplication state: 'ready'\n"
               "\t\tApplication ID:\n"
               "\t\t\tA0:00:00:00:87:10:02:FF:33:FF:01:89:06:05:00:FF\n"
               "\t\tPersonalization state: 'ready'\n"
               "\t\tUPIN replaces PIN1: 'no'\n"
               "\t\tPIN1 state: 'enabled-verified'\n"
               "\t\t\tPIN1 retries: '3'\n"
               "\t\t\tPUK1 retries: '10'\n"
               "\t\tPIN2 state: 'blocked'\n"
               "\t\t\tPIN2 retries: '0'\n"
               "\t\t\tPUK2 retries: '10'\n")

        # act
        match = CellMgmt._pin_retry_remain_regex.match(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("3", match.group(2))

    def test_attach_status_regex_should_pass(self):
        # arrange
        SUT = "CS: attached\nPS: attached\n"

        # act
        found = CellMgmt._attach_status_regex.search(SUT)

        # assert
        self.assertTrue(found)

    def test_at_response_ok_regex_should_pass(self):
        # arrange
        SUT = "\n\nOK\n\n"

        # act
        match = CellMgmt._at_response_ok_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_at_response_err_regex_should_pass(self):
        # arrange
        SUT = "\n\nERROR\n\n"

        # act
        match = CellMgmt._at_response_err_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_at_response_cme_err_regex_should_pass(self):
        # arrange
        SUT = "\n\n+CME ERROR: Unknown error\n\n"

        # act
        match = CellMgmt._at_response_cme_err_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_at_with_response_ok(self):
        # arrange
        SUT = "\n\nOK\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("ok", res["status"])

    def test_at_with_response_ok_and_data(self):
        # arrange
        SUT = "\n\n+CFUN: 1\n\nOK\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("ok", res["status"])
        self.assertEqual("+CFUN: 1", res["info"])

    def test_at_with_response_cme_err(self):
        # arrange
        SUT = "\n\n+CME ERROR: Unknown error\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("cme-err", res["status"])
        self.assertEqual("Unknown error", res["info"])

    def test_at_with_response_err(self):
        # arrange
        SUT = "\n\nERROR\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("err", res["status"])

    def test_at_with_unexpected_output_should_raise_fail(self):
        # arrange
        SUT = "\n\nERR\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)

        # assert
        with self.assertRaises(CellMgmtError):
            self.cell_mgmt.at("at")
Example #6
0
    def __init__(
            self,
            dev_name=None,
            enabled=None,
            pin=None,
            pdp_context_static=None,
            pdp_context_id=None,
            pdp_context_primary_apn=None,
            pdp_context_primary_type=None,
            pdp_context_secondary_apn=None,
            pdp_context_secondary_type=None,
            pdp_context_retry_timeout=None,
            keepalive_enabled=None,
            keepalive_host=None,
            keepalive_period_sec=None,
            log_period_sec=None):

        if (not isinstance(dev_name, str) or
                not isinstance(enabled, bool) or
                not isinstance(pdp_context_static, bool) or
                not isinstance(pdp_context_id, int) or
                not (isinstance(pdp_context_primary_apn, str) or
                     isinstance(pdp_context_primary_apn, unicode) or
                     pdp_context_primary_apn is None) or
                not (isinstance(pdp_context_primary_type, str) or
                     pdp_context_primary_type is None) or
                not (isinstance(pdp_context_secondary_apn, str) or
                     isinstance(pdp_context_secondary_apn, unicode) or
                     pdp_context_secondary_apn is None) or
                not (isinstance(pdp_context_secondary_type, str) or
                     pdp_context_secondary_type is None) or
                not isinstance(pdp_context_retry_timeout, int) or
                not isinstance(keepalive_enabled, bool) or
                not isinstance(keepalive_host, str) or
                not isinstance(keepalive_period_sec, int) or
                not isinstance(log_period_sec, int)):
            raise ValueError

        if pin is not None:
            if not isinstance(pin, str) or len(pin) != 4:
                raise ValueError

        self._dev_name = dev_name
        self._enabled = enabled
        self._pin = pin
        self._pdp_context_static = pdp_context_static
        self._pdp_context_id = pdp_context_id
        self._pdp_context_primary_apn = pdp_context_primary_apn
        self._pdp_context_primary_type = pdp_context_primary_type
        self._pdp_context_secondary_apn = pdp_context_secondary_apn
        self._pdp_context_secondary_type = pdp_context_secondary_type
        self._pdp_context_retry_timeout = pdp_context_retry_timeout
        self._keepalive_enabled = keepalive_enabled
        self._keepalive_host = keepalive_host
        self._keepalive_period_sec = keepalive_period_sec
        self._log_period_sec = log_period_sec

        self._status = Manager.Status.initializing

        self._static_information = None

        self._cell_mgmt = CellMgmt()
        self._stop = True

        self._thread = None

        self._cellular_logger = None
        self._observer = None

        # instance of CellularInformation
        self._cellular_information = None

        # instance of NetworkInformation
        self._network_information = None

        self._update_network_information_callback = None

        self._log = Log()

        # verify SIM card at very beginning
        self.verify_sim()
Example #7
0
class Manager(object):
    PING_REQUEST_COUNT = 3
    PING_TIMEOUT_SEC = 20

    class Status(Enum):
        initializing = 0
        nosim = 1
        pin = 2
        ready = 3
        connecting = 4
        connect_failure = 5
        connected = 6
        power_cycle = 7
        service_searching = 8
        service_attached = 9
        pin_error = 10

    class StaticInformation(object):
        def __init__(
                self,
                pin_retry_remain=None,
                iccid=None,
                imsi=None,
                imei=None):

            if (not isinstance(pin_retry_remain, int) or
                    not isinstance(iccid, str) or
                    not isinstance(imsi, str) or
                    not isinstance(imei, str)):
                raise ValueError

            self._pin_retry_remain = pin_retry_remain
            self._iccid = iccid
            self._imsi = imsi
            self._imei = imei

        @property
        def pin_retry_remain(self):
            return self._pin_retry_remain

        @property
        def iccid(self):
            return self._iccid

        @property
        def imsi(self):
            return self._imsi

        @property
        def imei(self):
            return self._imei

    def __init__(
            self,
            dev_name=None,
            enabled=None,
            pin=None,
            pdp_context_static=None,
            pdp_context_id=None,
            pdp_context_primary_apn=None,
            pdp_context_primary_type=None,
            pdp_context_secondary_apn=None,
            pdp_context_secondary_type=None,
            pdp_context_retry_timeout=None,
            keepalive_enabled=None,
            keepalive_host=None,
            keepalive_period_sec=None,
            log_period_sec=None):

        if (not isinstance(dev_name, str) or
                not isinstance(enabled, bool) or
                not isinstance(pdp_context_static, bool) or
                not isinstance(pdp_context_id, int) or
                not (isinstance(pdp_context_primary_apn, str) or
                     isinstance(pdp_context_primary_apn, unicode) or
                     pdp_context_primary_apn is None) or
                not (isinstance(pdp_context_primary_type, str) or
                     pdp_context_primary_type is None) or
                not (isinstance(pdp_context_secondary_apn, str) or
                     isinstance(pdp_context_secondary_apn, unicode) or
                     pdp_context_secondary_apn is None) or
                not (isinstance(pdp_context_secondary_type, str) or
                     pdp_context_secondary_type is None) or
                not isinstance(pdp_context_retry_timeout, int) or
                not isinstance(keepalive_enabled, bool) or
                not isinstance(keepalive_host, str) or
                not isinstance(keepalive_period_sec, int) or
                not isinstance(log_period_sec, int)):
            raise ValueError

        if pin is not None:
            if not isinstance(pin, str) or len(pin) != 4:
                raise ValueError

        self._dev_name = dev_name
        self._enabled = enabled
        self._pin = pin
        self._pdp_context_static = pdp_context_static
        self._pdp_context_id = pdp_context_id
        self._pdp_context_primary_apn = pdp_context_primary_apn
        self._pdp_context_primary_type = pdp_context_primary_type
        self._pdp_context_secondary_apn = pdp_context_secondary_apn
        self._pdp_context_secondary_type = pdp_context_secondary_type
        self._pdp_context_retry_timeout = pdp_context_retry_timeout
        self._keepalive_enabled = keepalive_enabled
        self._keepalive_host = keepalive_host
        self._keepalive_period_sec = keepalive_period_sec
        self._log_period_sec = log_period_sec

        self._status = Manager.Status.initializing

        self._static_information = None

        self._cell_mgmt = CellMgmt()
        self._stop = True

        self._thread = None

        self._cellular_logger = None
        self._observer = None

        # instance of CellularInformation
        self._cellular_information = None

        # instance of NetworkInformation
        self._network_information = None

        self._update_network_information_callback = None

        self._log = Log()

        # verify SIM card at very beginning
        self.verify_sim()

    def set_update_network_information_callback(
            self,
            callback):
        self._update_network_information_callback = callback

    def status(self):
        return self._status

    def static_information(self):
        return self._static_information

    def cellular_information(self):
        """Return an instance of CellularInformation or None."""
        if self._observer is not None:
            cinfo = self._observer.cellular_information()
            if cinfo is not None:
                self._cellular_information = cinfo

        return self._cellular_information

    def network_information(self):
        """Return an instance of NetworkInformation or None."""
        return self._network_information

    def pdp_context_list(self):
        """Return a list of PDP context."""
        return self._cell_mgmt.pdp_context_list()

    def verify_sim(self):
        sim_status = self._cell_mgmt.sim_status()
        _logger.debug("sim_status = " + sim_status.name)

        if sim_status == SimStatus.nosim:
            self._status = Manager.Status.nosim
            return sim_status

        if sim_status == SimStatus.pin:
            self._status = Manager.Status.pin
            if self._pin is None:
                self._log.log_event_no_pin()
                return sim_status

            # set pin
            pin_retries_prev = self._cell_mgmt.get_pin_retry_remain()
            try:
                self._cell_mgmt.set_pin(self._pin)
            except CellMgmtError:
                _logger.warning(format_exc())
                sim_status = self._cell_mgmt.sim_status()
                pin_retries_after = self._cell_mgmt.get_pin_retry_remain()
                if sim_status == SimStatus.pin and \
                        (pin_retries_after - pin_retries_prev < 0):
                    self._status = Manager.Status.pin_error
                    self._pin = None
                    self._log.log_event_pin_error()
                    return sim_status

            self._sleep(3, critical_section=True)
            sim_status = self._cell_mgmt.sim_status()
            if sim_status == SimStatus.ready:
                self._status = Manager.Status.ready
                return sim_status

        if sim_status == SimStatus.ready:
            self._status = Manager.Status.ready

        return sim_status

    def start(self):
        self._stop = False

        self._thread = Thread(target=self._main_thread)
        self._thread.daemon = True
        self._thread.start()

        self._cellular_logger = CellularLogger(self._log_period_sec)
        self._cellular_logger.start(self)

    def stop(self):
        self._stop = True
        self._thread.join()

        self._cellular_logger.stop()

    def _main_thread(self):
        while True:
            try:
                self._loop()

            except StopException:
                if self._observer is not None:
                    self._observer.stop()
                    self._observer = None

                self._log.log_event_cellular_disconnect()
                self._network_information = self._cell_mgmt.stop()
                # update nwk_info
                if self._update_network_information_callback is not None:
                    self._update_network_information_callback(
                        self._network_information)
                break

            except Exception:
                _logger.error("should not reach here")
                _logger.warning(format_exc())
                self._power_cycle(force=True)

    def _loop(self):
        try:
            if not self._initialize():
                if self._enabled:
                    self._power_cycle()

                return

            # start observation
            self._observer = CellularObserver(period_sec=30)
            self._observer.start()

            if self._enabled:
                self._operate()
            else:
                while True:
                    self._sleep(60)

            # stop observation
            self._observer.stop()
            self._observer = None

            self._power_cycle()

        except CellMgmtError:
            _logger.warning(format_exc())
            self._power_cycle()

    def _interrupt_point(self):
        if self._stop:
            raise StopException

    def _initialize(self):
        """Return True on success, False on failure."""
        self._status = Manager.Status.initializing
        self._static_information = None
        self._cellular_information = None
        self._network_information = None

        retry = 0
        max_retry = 10
        while retry < max_retry:
            self._interrupt_point()

            self._status = Manager.Status.initializing

            sim_status = self.verify_sim()
            if sim_status == SimStatus.nosim:
                self._sleep(10)
                retry += 1
                continue

            self._initialize_static_information()
            self._cellular_information = CellularInformation.get()

            if sim_status != SimStatus.ready:
                raise StopException

            self._status = Manager.Status.ready
            return True

        sim_status = self._cell_mgmt.sim_status()
        if sim_status == SimStatus.nosim:
            self._log.log_event_nosim()

        return False

    def _initialize_static_information(self):
        _logger.debug("_initialize_static_information")
        while True:
            try:
                pin_retry_remain = self._cell_mgmt.get_pin_retry_remain()
                minfo = self._cell_mgmt.m_info()
                sinfo = self._cell_mgmt.get_cellular_sim_info()

                self._static_information = Manager.StaticInformation(
                    pin_retry_remain=pin_retry_remain,
                    iccid=sinfo.iccid,
                    imsi=sinfo.imsi,
                    imei=minfo.imei)

                break

            except CellMgmtError:
                _logger.warning(format_exc())
                self._sleep(10)
                continue

    def _operate(self):
        while True:
            self._interrupt_point()

            self._status = Manager.Status.connecting

            if not self._try_connect(self._pdp_context_primary_apn,
                                     self._pdp_context_primary_type,
                                     self._pdp_context_retry_timeout):

                if self._pdp_context_static is False or \
                        self._pdp_context_secondary_apn is None or \
                        self._pdp_context_secondary_apn == "":
                    break

                if not self._try_connect(self._pdp_context_secondary_apn,
                                         self._pdp_context_secondary_type,
                                         self._pdp_context_retry_timeout):
                    break

            self._status = Manager.Status.connected

            while True:
                self._interrupt_point()

                connected = self._cell_mgmt.status()
                if not connected:
                    self._log.log_event_cellular_disconnect()
                    break

                if self._keepalive_enabled:
                    if not self._checkalive_ping():
                        self._log.log_event_checkalive_failure()
                        break

                self._sleep(
                    self._keepalive_period_sec
                    if self._keepalive_enabled
                    else 60)

    def _attach(self):
        """Return True on success, False on failure.
        """
        _logger.debug("check if module attached with service")

        retry = 0
        while True:
            if self._status == Manager.Status.power_cycle:
                self._sleep(1)
                continue

            self._status = Manager.Status.service_searching

            if not self._cell_mgmt.attach():
                retry += 1
                if retry > 180:
                    return False
                self._sleep(1)
                continue
            break

        self._status = Manager.Status.service_attached
        return True

    def _try_connect(self, pdpc_apn, pdpc_type, retry_timeout):
        retry = monotonic() + retry_timeout
        while True:
            self._interrupt_point()

            self._status = Manager.Status.connecting
            if not self._connect(pdpc_apn, pdpc_type):
                self._status = Manager.Status.connect_failure

                if monotonic() >= retry:
                    break

                self._sleep(10)
            else:
                return True

    def _connect(self, pdpc_apn, pdpc_type):
        """Return True on success, False on failure.
        """
        self._network_information = None

        try:
            self._log.log_event_connect_begin()

            self._network_information = self._cell_mgmt.stop()
            # update nwk_info
            if self._update_network_information_callback is not None:
                self._update_network_information_callback(
                    self._network_information)

            try:
                pdpc = (item for item in self.pdp_context_list()
                        if item["id"] == self._pdp_context_id).next()
                apn = pdpc["apn"]

                if self._pdp_context_static is True and apn != pdpc_apn:
                    self._cell_mgmt.set_pdp_context(
                        self._pdp_context_id, pdpc_apn, pdpc_type)
                    if self.verify_sim() != SimStatus.ready:
                        raise StopException

                pdpc = (item for item in self.pdp_context_list()
                        if item["id"] == self._pdp_context_id).next()
                apn = pdpc["apn"]
            except:
                self._log.log_event_no_pdp_context()
                return False
            if apn == "":
                self._log.log_event_no_apn()
                return False

            # try to attach before connect
            if not self._attach():
                return False

            nwk_info = self._cell_mgmt.start(apn=apn)

            self._log.log_event_connect_success(nwk_info)

            connected = self._cell_mgmt.status()
            if not connected:
                self._log.log_event_cellular_disconnect()
                return False

        except CellMgmtError:
            _logger.warning(format_exc())

            self._log.log_event_connect_failure()
            return False

        if self._keepalive_enabled:
            if not self._checkalive_ping():
                self._log.log_event_checkalive_failure()
                return False

        self._network_information = nwk_info
        # update nwk_info
        if self._update_network_information_callback is not None:
            self._update_network_information_callback(nwk_info)

        return True

    def _power_cycle(self, force=False):
        try:
            self._log.log_event_power_cycle()
            self._status = Manager.Status.power_cycle

            self._cell_mgmt.power_cycle(force, timeout_sec=60)
        except CellMgmtError:
            _logger.warning(format_exc())

    def _sleep(self, sec, critical_section=False):
        until = monotonic() + sec

        while monotonic() < until:
            if not critical_section:
                self._interrupt_point()
            sleep(1)

    def _checkalive_ping(self):
        """Return True on ping success, False on failure."""
        for _ in xrange(0, self.PING_REQUEST_COUNT):
            try:
                sh.ping(
                    "-c", "1",
                    "-I", self._dev_name,
                    "-W", str(self.PING_TIMEOUT_SEC),
                    self._keepalive_host,
                    _timeout=self.PING_TIMEOUT_SEC + 5
                )

                return True
            except (ErrorReturnCode, TimeoutException):
                _logger.warning(format_exc())

                continue

        return False
 def setUp(self, mock_sh):
     self.cell_mgmt = CellMgmt()
class TestCellMgmt(unittest.TestCase):
    @patch("cellular_utility.cell_mgmt.sh")
    def setUp(self, mock_sh):
        self.cell_mgmt = CellMgmt()

    def tearDown(self):
        pass

    def test_start_ip_regex_should_pass(self):
        # arrange
        SUT = (
            "IP=111.70.154.149\n"
            "SubnetMask=255.255.255.252\n"
            "Gateway=111.70.154.150\n"
            "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_ip_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("111.70.154.149", match.group(1))

    def test_start_netmask_regex_should_pass(self):
        # arrange
        SUT = (
            "IP=111.70.154.149\n"
            "SubnetMask=255.255.255.252\n"
            "Gateway=111.70.154.150\n"
            "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_netmask_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("255.255.255.252", match.group(1))

    def test_start_gateway_regex_should_pass(self):
        # arrange
        SUT = (
            "IP=111.70.154.149\n"
            "SubnetMask=255.255.255.252\n"
            "Gateway=111.70.154.150\n"
            "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_gateway_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("111.70.154.150", match.group(1))

    def test_start_dns_regex_should_pass(self):
        # arrange
        SUT = (
            "IP=111.70.154.149\n"
            "SubnetMask=255.255.255.252\n"
            "Gateway=111.70.154.150\n"
            "DNS=168.95.1.1 168.95.192.1\n")

        # act
        match = CellMgmt._start_dns_regex.search(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("168.95.1.1 168.95.192.1", match.group(1))

    def test_signal_regex_should_pass(self):
        # arrange
        SUT = "umts -41 dbm\n"

        # act
        match = CellMgmt._signal_regex.match(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("umts", match.group(1))
        self.assertEqual("-41", match.group(2))

    def test_m_info_regex_should_pass(self):
        # arrange
        SUT = (
            "Module=MC7304\n"
            "WWAN_node=wwan0\n"
            "AT_port=/dev/ttyUSB2\n"
            "GPS_port=/dev/ttyUSB1\n"
            "LAC=2817\n"
            "CellID=01073AEE\n"
            "ICC-ID=1234567890123456\n"
            "IMEI=0123456789012345\n"
            "QMI_port=/dev/cdc-wdm0\n")

        # act
        match = CellMgmt._m_info_regex.match(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("MC7304", match.group(1))
        self.assertEqual("wwan0", match.group(2))
        self.assertEqual("2817", match.group(3))
        self.assertEqual("01073AEE", match.group(4))
        self.assertEqual("1234567890123456", match.group(5))
        self.assertEqual("0123456789012345", match.group(6))
        self.assertEqual("/dev/cdc-wdm0", match.group(7))

    def test_operator_regex_should_pass(self):
        # arrange
        SUT = "Chunghwa Telecom\n"

        # act
        match = CellMgmt._operator_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_sim_status_ready_regex_should_pass(self):
        # arrange
        SUT = "+CPIN: READY\n"

        # act
        match = CellMgmt._sim_status_ready_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_sim_status_sim_pin_regex_should_pass(self):
        # arrange
        SUT = "+CPIN: SIM PIN\n"

        # act
        match = CellMgmt._sim_status_sim_pin_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_pin_retry_remain_regex_should_pass(self):
        # arrange
        SUT = ("[/dev/cdc-wdm1] Successfully got card status\n"
               "Provisioning applications:\n"
               "\tPrimary GW:   slot '0', application '0'\n"
               "\tPrimary 1X:   session doesn't exist\n"
               "\tSecondary GW: session doesn't exist\n"
               "\tSecondary 1X: session doesn't exist\n"
               "Card [0]:\n"
               "\tCard state: 'present'\n"
               "\tUPIN state: 'not-initialized'\n"
               "\t\tUPIN retries: '0'\n"
               "\t\tUPUK retries: '0'\n"
               "\tApplication [0]:\n"
               "\t\tApplication type:  'usim (2)'\n"
               "\t\tApplication state: 'ready'\n"
               "\t\tApplication ID:\n"
               "\t\t\tA0:00:00:00:87:10:02:FF:33:FF:01:89:06:05:00:FF\n"
               "\t\tPersonalization state: 'ready'\n"
               "\t\tUPIN replaces PIN1: 'no'\n"
               "\t\tPIN1 state: 'enabled-verified'\n"
               "\t\t\tPIN1 retries: '3'\n"
               "\t\t\tPUK1 retries: '10'\n"
               "\t\tPIN2 state: 'blocked'\n"
               "\t\t\tPIN2 retries: '0'\n"
               "\t\t\tPUK2 retries: '10'\n")

        # act
        match = CellMgmt._pin_retry_remain_regex.match(SUT)

        # assert
        self.assertTrue(match)
        self.assertEqual("3", match.group(2))

    def test_attach_status_regex_should_pass(self):
        # arrange
        SUT = "CS: attached\nPS: attached\n"

        # act
        found = CellMgmt._attach_status_regex.search(SUT)

        # assert
        self.assertTrue(found)

    def test_at_response_ok_regex_should_pass(self):
        # arrange
        SUT = "\n\nOK\n\n"

        # act
        match = CellMgmt._at_response_ok_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_at_response_err_regex_should_pass(self):
        # arrange
        SUT = "\n\nERROR\n\n"

        # act
        match = CellMgmt._at_response_err_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_at_response_cme_err_regex_should_pass(self):
        # arrange
        SUT = "\n\n+CME ERROR: Unknown error\n\n"

        # act
        match = CellMgmt._at_response_cme_err_regex.match(SUT)

        # assert
        self.assertTrue(match)

    def test_at_with_response_ok(self):
        # arrange
        SUT = "\n\nOK\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("ok", res["status"])

    def test_at_with_response_ok_and_data(self):
        # arrange
        SUT = "\n\n+CFUN: 1\n\nOK\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("ok", res["status"])
        self.assertEqual("+CFUN: 1", res["info"])

    def test_at_with_response_cme_err(self):
        # arrange
        SUT = "\n\n+CME ERROR: Unknown error\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("cme-err", res["status"])
        self.assertEqual("Unknown error", res["info"])

    def test_at_with_response_err(self):
        # arrange
        SUT = "\n\nERROR\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)
        res = self.cell_mgmt.at("at")

        # assert
        self.assertEqual("err", res["status"])

    def test_at_with_unexpected_output_should_raise_fail(self):
        # arrange
        SUT = "\n\nERR\n\n"

        # act
        self.cell_mgmt._cell_mgmt = Mock(return_value=SUT)

        # assert
        with self.assertRaises(CellMgmtError):
            self.cell_mgmt.at("at")