forked from IQ.Lvbs/IQ.Pilot
IQ.Pilot Release Commit @ b6534c0
This commit is contained in:
238
iqpilot/system/hardware/tici/tests/test_esim.py
Normal file
238
iqpilot/system/hardware/tici/tests/test_esim.py
Normal file
@@ -0,0 +1,238 @@
|
||||
import pytest
|
||||
|
||||
from iqpilot.system.hardware import HARDWARE
|
||||
from iqpilot.system.hardware.base import LPAError, LPAProfileNotFoundError, Profile
|
||||
from iqpilot.system.hardware.tici import lpa as lpa_module
|
||||
from iqpilot.system.hardware.tici.esim_manager import EsimManager
|
||||
|
||||
# https://euicc-manual.osmocom.org/docs/rsp/known-test-profile
|
||||
# iccid is always the same for the given activation code
|
||||
TEST_ACTIVATION_CODE = 'LPA:1$rsp.truphone.com$QRF-BETTERROAMING-PMRDGIR2EARDEIT5'
|
||||
TEST_ICCID = '8944476500001944011'
|
||||
|
||||
TEST_NICKNAME = 'test_profile'
|
||||
|
||||
def cleanup():
|
||||
lpa = HARDWARE.get_sim_lpa()
|
||||
try:
|
||||
lpa.delete_profile(TEST_ICCID)
|
||||
except LPAProfileNotFoundError:
|
||||
pass
|
||||
lpa.process_notifications()
|
||||
|
||||
@pytest.mark.tici
|
||||
class TestEsim:
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cleanup()
|
||||
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
cleanup()
|
||||
|
||||
def test_provision_enable_disable(self):
|
||||
lpa = HARDWARE.get_sim_lpa()
|
||||
current_active = lpa.get_active_profile()
|
||||
|
||||
lpa.download_profile(TEST_ACTIVATION_CODE, TEST_NICKNAME)
|
||||
assert any(p.iccid == TEST_ICCID and p.nickname == TEST_NICKNAME for p in lpa.list_profiles())
|
||||
|
||||
lpa.enable_profile(TEST_ICCID)
|
||||
new_active = lpa.get_active_profile()
|
||||
assert new_active is not None
|
||||
assert new_active.iccid == TEST_ICCID
|
||||
assert new_active.nickname == TEST_NICKNAME
|
||||
|
||||
lpa.disable_profile(TEST_ICCID)
|
||||
new_active = lpa.get_active_profile()
|
||||
assert new_active is None
|
||||
|
||||
if current_active:
|
||||
lpa.enable_profile(current_active.iccid)
|
||||
|
||||
|
||||
class TestEsimDeleteHandling:
|
||||
def test_delete_ignores_notification_cleanup_if_profile_is_gone(self, monkeypatch):
|
||||
target_iccid = "89012804332267989477"
|
||||
lpa = lpa_module.TiciLPA()
|
||||
|
||||
monkeypatch.setattr(lpa, "_validate_profile_exists", lambda iccid: None)
|
||||
monkeypatch.setattr(lpa, "get_active_profile", lambda: Profile("8901240527117095243", "US Mobile", True, "Wireless"))
|
||||
monkeypatch.setattr(lpa, "_restart_modem", lambda: None)
|
||||
monkeypatch.setattr(
|
||||
lpa,
|
||||
"list_profiles",
|
||||
lambda: [Profile("8901240527117095243", "US Mobile", True, "Wireless")],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(lpa, "_ensure_client", lambda: object())
|
||||
monkeypatch.setattr(lpa_module, "delete_profile", lambda client, iccid: None)
|
||||
|
||||
def fail_notifications(client):
|
||||
raise RuntimeError('AT command failed (AT+CGLA=2,16,"80E2910003BF2800"): AT command failed')
|
||||
|
||||
monkeypatch.setattr(lpa_module, "process_notifications", fail_notifications)
|
||||
|
||||
lpa.delete_profile(target_iccid)
|
||||
|
||||
def test_delete_raises_clear_error_if_profile_still_present_after_cleanup_failure(self, monkeypatch):
|
||||
target_iccid = "89012804332267989477"
|
||||
lpa = lpa_module.TiciLPA()
|
||||
|
||||
monkeypatch.setattr(lpa, "_validate_profile_exists", lambda iccid: None)
|
||||
monkeypatch.setattr(lpa, "get_active_profile", lambda: Profile("8901240527117095243", "US Mobile", True, "Wireless"))
|
||||
monkeypatch.setattr(lpa, "_restart_modem", lambda: None)
|
||||
monkeypatch.setattr(
|
||||
lpa,
|
||||
"list_profiles",
|
||||
lambda: [
|
||||
Profile("8901240527117095243", "US Mobile", True, "Wireless"),
|
||||
Profile(target_iccid, "RedPocket", False, "RedPocket"),
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(lpa, "_ensure_client", lambda: object())
|
||||
monkeypatch.setattr(lpa_module, "delete_profile", lambda client, iccid: None)
|
||||
|
||||
def fail_notifications(client):
|
||||
raise RuntimeError('AT command failed (AT+CGLA=2,16,"80E2910003BF2800"): AT command failed')
|
||||
|
||||
monkeypatch.setattr(lpa_module, "process_notifications", fail_notifications)
|
||||
|
||||
with pytest.raises(LPAError, match="Profile delete did not finish cleanly"):
|
||||
lpa.delete_profile(target_iccid)
|
||||
|
||||
def test_manager_maps_notification_cleanup_error(self):
|
||||
error = LPAError('AT command failed (AT+CGLA=2,16,"80E2910003BF2800"): AT command failed')
|
||||
assert EsimManager._map_error(error) == "Modem notification cleanup failed; refresh profiles"
|
||||
|
||||
|
||||
class TestEsimNotificationCleanupRecovery:
|
||||
def test_switch_ignores_notification_cleanup_if_target_is_enabled(self, monkeypatch):
|
||||
target_iccid = "8901240527117194095"
|
||||
lpa = lpa_module.TiciLPA()
|
||||
|
||||
monkeypatch.setattr(lpa, "_validate_profile_exists", lambda iccid: None)
|
||||
monkeypatch.setattr(lpa, "_ensure_switchable_profile", lambda iccid: None)
|
||||
monkeypatch.setattr(lpa, "get_active_profile", lambda: Profile("8901240527117113293", "US Mobile", True, "Wireless"))
|
||||
monkeypatch.setattr(lpa, "_wait_for_modem", lambda: None)
|
||||
monkeypatch.setattr(lpa, "_ensure_client", lambda: type("Client", (), {"channel": "2", "_use_csim": False})())
|
||||
monkeypatch.setattr(
|
||||
lpa,
|
||||
"list_profiles",
|
||||
lambda: [
|
||||
Profile("8901240527117113293", "US Mobile", False, "Wireless"),
|
||||
Profile(target_iccid, "T-Mobile", True, "Wireless"),
|
||||
],
|
||||
)
|
||||
monkeypatch.setattr(lpa_module, "enable_profile", lambda client, iccid, refresh=True: None)
|
||||
monkeypatch.setattr(
|
||||
lpa_module,
|
||||
"process_notifications",
|
||||
lambda client: (_ for _ in ()).throw(RuntimeError('AT command failed (AT+CGLA=2,16,"80E2910003BF2800"): AT command failed')),
|
||||
)
|
||||
|
||||
lpa.switch_profile(target_iccid)
|
||||
|
||||
@pytest.mark.parametrize(("is_eg25", "expected_refresh", "expected_waits", "expected_reboots"), [
|
||||
(True, True, 1, 0),
|
||||
(False, False, 0, 1),
|
||||
])
|
||||
def test_switch_profile_uses_modem_specific_refresh_behavior(self, monkeypatch, is_eg25, expected_refresh, expected_waits, expected_reboots):
|
||||
target_iccid = "8901240527117194095"
|
||||
lpa = object.__new__(lpa_module.TiciLPA)
|
||||
lpa._is_eg25 = is_eg25
|
||||
lpa.verbose = False
|
||||
|
||||
waits = []
|
||||
reboots = []
|
||||
refresh_values = []
|
||||
|
||||
monkeypatch.setattr(lpa, "_validate_profile_exists", lambda iccid: None)
|
||||
monkeypatch.setattr(lpa, "_ensure_switchable_profile", lambda iccid: None)
|
||||
monkeypatch.setattr(lpa, "get_active_profile", lambda: Profile("8901240527117113293", "US Mobile", True, "Wireless"))
|
||||
monkeypatch.setattr(lpa, "_wait_for_modem", lambda: waits.append(True))
|
||||
monkeypatch.setattr(lpa, "_restart_modem", lambda: reboots.append(True))
|
||||
monkeypatch.setattr(lpa, "_with_lpa_error", lambda fn: fn())
|
||||
monkeypatch.setattr(lpa, "_ensure_client", lambda: type("Client", (), {"channel": "2", "_use_csim": False})())
|
||||
monkeypatch.setattr(
|
||||
lpa,
|
||||
"_process_notifications_after_state_change",
|
||||
lambda validator, _recovery_message, _failure_message: validator(),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
lpa,
|
||||
"list_profiles",
|
||||
lambda: [
|
||||
Profile("8901240527117113293", "US Mobile", False, "Wireless"),
|
||||
Profile(target_iccid, "T-Mobile", True, "Wireless"),
|
||||
],
|
||||
)
|
||||
|
||||
def fake_enable_profile(client, iccid, refresh=True):
|
||||
refresh_values.append(refresh)
|
||||
|
||||
monkeypatch.setattr(lpa_module, "enable_profile", fake_enable_profile)
|
||||
|
||||
lpa.switch_profile(target_iccid)
|
||||
|
||||
assert refresh_values == [expected_refresh]
|
||||
assert len(waits) == expected_waits
|
||||
assert len(reboots) == expected_reboots
|
||||
|
||||
def test_download_ignores_notification_cleanup_if_profile_exists(self, monkeypatch, mocker):
|
||||
target_iccid = "8901240527117194095"
|
||||
lpa = lpa_module.TiciLPA()
|
||||
profiles = [
|
||||
[Profile("8901240527117113293", "US Mobile", True, "Wireless")],
|
||||
[
|
||||
Profile("8901240527117113293", "US Mobile", True, "Wireless"),
|
||||
Profile(target_iccid, "T-Mobile", False, "Wireless"),
|
||||
],
|
||||
[
|
||||
Profile("8901240527117113293", "US Mobile", True, "Wireless"),
|
||||
Profile(target_iccid, "T-Mobile", False, "Wireless"),
|
||||
],
|
||||
]
|
||||
|
||||
monkeypatch.setattr(lpa, "_ensure_client", lambda: object())
|
||||
monkeypatch.setattr(lpa, "_wait_for_modem", lambda: None)
|
||||
profile_states = iter(profiles)
|
||||
current_profiles = profiles[-1]
|
||||
|
||||
def list_profiles():
|
||||
nonlocal current_profiles
|
||||
current_profiles = next(profile_states, current_profiles)
|
||||
return current_profiles
|
||||
|
||||
monkeypatch.setattr(lpa, "list_profiles", list_profiles)
|
||||
monkeypatch.setattr(lpa_module, "download_profile", lambda client, qr: target_iccid)
|
||||
set_nickname = mocker.MagicMock()
|
||||
monkeypatch.setattr(lpa_module, "set_profile_nickname", set_nickname)
|
||||
monkeypatch.setattr(
|
||||
lpa_module,
|
||||
"process_notifications",
|
||||
lambda client: (_ for _ in ()).throw(RuntimeError('AT command failed (AT+CGLA=2,16,"80E2910003BF2800"): AT command failed')),
|
||||
)
|
||||
|
||||
lpa.download_profile(TEST_ACTIVATION_CODE, "T-Mobile")
|
||||
|
||||
set_nickname.assert_called_once_with(mocker.ANY, target_iccid, "T-Mobile")
|
||||
|
||||
|
||||
class TestEsimManagerSupportGating:
|
||||
def test_refresh_profiles_does_not_touch_lpa_without_euicc(self, monkeypatch, mocker):
|
||||
manager = EsimManager()
|
||||
|
||||
monkeypatch.setattr(manager, "_query_euicc_support", lambda: False)
|
||||
manager._params = mocker.MagicMock()
|
||||
manager._params.get.return_value = None
|
||||
manager._params.get_bool.return_value = True
|
||||
monkeypatch.setattr(HARDWARE, "get_device_type", lambda: "tici")
|
||||
monkeypatch.setattr(HARDWARE, "get_sim_lpa", lambda: (_ for _ in ()).throw(AssertionError("LPA should not be touched")))
|
||||
|
||||
manager.refresh_profiles()
|
||||
|
||||
assert manager.get_state().profiles == []
|
||||
assert manager.get_state().message == "Insert the original comma SIM card that came with the device to use eSIM"
|
||||
Reference in New Issue
Block a user