160 lines
5.7 KiB
Python
160 lines
5.7 KiB
Python
from datetime import datetime
|
|
|
|
import pytest
|
|
|
|
from banban.service.device import DeviceService
|
|
from banban.service.ota_firmware import OtaFirmwareSelection
|
|
from handlers.mqtt_handler import TalkingQMQTTService
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_simulated_device_force_ota_dispatches_once_and_completes(monkeypatch):
|
|
device_id = "TalkingQ_XQSN00001005"
|
|
service = DeviceService()
|
|
mqtt_service = TalkingQMQTTService({"broker": "127.0.0.1"})
|
|
record = None
|
|
ota_commands = []
|
|
published = []
|
|
|
|
async def fake_select_latest_for_device(status_row):
|
|
assert status_row["device_type"] == 2
|
|
return OtaFirmwareSelection(
|
|
channel_key="gps",
|
|
version="1.8.5",
|
|
firmware_url="https://example.com/gps-1.8.5.bin",
|
|
firmware_id=15,
|
|
force_update=True,
|
|
)
|
|
|
|
async def fake_get_firmware_update_dict(requested_device_id):
|
|
assert requested_device_id == device_id
|
|
return dict(record) if record else None
|
|
|
|
async def fake_update_firmware_update(*args, **kwargs):
|
|
nonlocal record
|
|
if args:
|
|
kwargs = {"device_id": args[0], **kwargs}
|
|
record = dict(record or {})
|
|
record.update(kwargs)
|
|
record.setdefault("device_id", device_id)
|
|
record.setdefault("updated_at", datetime.now())
|
|
return True
|
|
|
|
async def fake_claim_forced_update(**kwargs):
|
|
nonlocal record
|
|
if record and record.get("update_status") in {"sent", "accepted", "updating"}:
|
|
return False
|
|
record = dict(record or {})
|
|
record.update(
|
|
{
|
|
"device_id": device_id,
|
|
"firmware_version": kwargs["target_version"],
|
|
"target_version": kwargs["target_version"],
|
|
"firmware_url": kwargs["firmware_url"],
|
|
"firmware_id": kwargs["firmware_id"],
|
|
"ota_channel": kwargs["ota_channel"],
|
|
"update_status": "sent",
|
|
"progress": 0.0,
|
|
"source": "forced",
|
|
"updated_at": datetime.now(),
|
|
}
|
|
)
|
|
return True
|
|
|
|
class FakeMqttService:
|
|
async def send_ota_command(self, requested_device_id, url, version):
|
|
ota_commands.append({"device_id": requested_device_id, "url": url, "version": version})
|
|
return "003"
|
|
|
|
async def fake_get_instance():
|
|
return FakeMqttService()
|
|
|
|
async def fake_publish(topic, payload):
|
|
published.append((topic, payload))
|
|
return True
|
|
|
|
async def fake_schedule_persistence(requested_device_id, label, coro):
|
|
assert requested_device_id == device_id
|
|
await coro
|
|
|
|
async def fake_insert_or_update(**kwargs):
|
|
assert kwargs["device_id"] == device_id
|
|
|
|
async def fake_get_setting_by_device_id(requested_device_id):
|
|
return {"device_id": requested_device_id, "device_type": 2, "ota_channel": None}
|
|
|
|
monkeypatch.setattr(
|
|
"banban.service.device.ota_firmware_service.select_latest_for_device",
|
|
fake_select_latest_for_device,
|
|
)
|
|
monkeypatch.setattr(
|
|
"banban.service.device.device_firmware_update_manager.get_firmware_update_dict",
|
|
fake_get_firmware_update_dict,
|
|
)
|
|
monkeypatch.setattr(
|
|
"banban.service.device.device_firmware_update_manager.update_firmware_update",
|
|
fake_update_firmware_update,
|
|
)
|
|
monkeypatch.setattr(
|
|
"banban.service.device.device_firmware_update_manager.claim_forced_update",
|
|
fake_claim_forced_update,
|
|
)
|
|
monkeypatch.setattr("handlers.mqtt_handler.TalkingQMQTTService.get_instance", fake_get_instance)
|
|
monkeypatch.setattr(mqtt_service, "_publish", fake_publish)
|
|
monkeypatch.setattr(mqtt_service, "_schedule_persistence", fake_schedule_persistence)
|
|
monkeypatch.setattr("handlers.mqtt_handler.device_setting_service.insert_or_update", fake_insert_or_update)
|
|
monkeypatch.setattr("handlers.mqtt_handler.device_setting_service.get_setting_by_device_id", fake_get_setting_by_device_id)
|
|
monkeypatch.setattr(
|
|
"handlers.mqtt_handler.wechat_mp_notification_service.schedule_low_battery_notification",
|
|
lambda **kwargs: None,
|
|
)
|
|
|
|
simulated_device_info = {
|
|
"msg_id": "000",
|
|
"data": {
|
|
"id": device_id,
|
|
"version": "1.8.2",
|
|
"device_type": "2",
|
|
"power": 80,
|
|
"signal": 4,
|
|
},
|
|
}
|
|
await mqtt_service._handle_device_info(device_id, simulated_device_info)
|
|
await mqtt_service._handle_device_info(device_id, simulated_device_info)
|
|
|
|
assert ota_commands == [{
|
|
"device_id": device_id,
|
|
"url": "https://example.com/gps-1.8.5.bin",
|
|
"version": "1.8.5",
|
|
}]
|
|
assert record["update_status"] == "sent"
|
|
assert record["target_version"] == "1.8.5"
|
|
assert record["source"] == "forced"
|
|
assert published == [
|
|
(f"device/{device_id}/event_resp", {"msg_id": "000", "status": "success"}),
|
|
(f"device/{device_id}/event_resp", {"msg_id": "000", "status": "success"}),
|
|
]
|
|
|
|
await mqtt_service._handle_ota_response(
|
|
device_id,
|
|
{
|
|
"status": "accepted",
|
|
"data": {"current_version": "1.8.2", "target_version": "1.8.5"},
|
|
},
|
|
)
|
|
assert record["update_status"] == "accepted"
|
|
|
|
await mqtt_service._handle_ota_response(
|
|
device_id,
|
|
{"status": "updating", "data": {"version": "1.8.5", "progress": 65}},
|
|
)
|
|
assert record["update_status"] == "updating"
|
|
assert record["progress"] == 65.0
|
|
|
|
await mqtt_service._handle_ota_response(
|
|
device_id,
|
|
{"status": "success", "data": {"new_version": "1.8.5"}},
|
|
)
|
|
assert record["update_status"] == "success"
|
|
assert record["progress"] == 100.0
|