From 3632794f583fc02456cf4460ff3c8e54954b62b7 Mon Sep 17 00:00:00 2001 From: agessaman Date: Sat, 16 May 2026 12:13:23 -0700 Subject: [PATCH] fix(darc_mowas_service): assign ascending timestamps to chunks in send_chunks method Updated the _send_chunks method to assign timestamps based on the chunk index, ensuring each chunk receives a unique timestamp that increments by one second. This change facilitates proper ordering and deduplication of messages on the client side. Added a unit test to verify the correct behavior of timestamp assignment during chunk transmission. --- modules/service_plugins/darc_mowas_service.py | 5 +- tests/unit/test_darc_mowas.py | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/modules/service_plugins/darc_mowas_service.py b/modules/service_plugins/darc_mowas_service.py index b480ea4..2f60f9e 100644 --- a/modules/service_plugins/darc_mowas_service.py +++ b/modules/service_plugins/darc_mowas_service.py @@ -191,7 +191,7 @@ class DARC_MoWaS_Service(BaseServicePlugin): chunk, i, len(chunks), - ts_now + timedelta(seconds=1) + ts_now + timedelta(seconds=i) ) ) @@ -215,7 +215,8 @@ class DARC_MoWaS_Service(BaseServicePlugin): chunk, command_id=cmd_id, skip_user_rate_limit=True, - timestamp=timestamp + timestamp=timestamp, + scope=self.get_mesh_flood_scope(), ): self.logger.warning("Send failed for '%s'", channel) return diff --git a/tests/unit/test_darc_mowas.py b/tests/unit/test_darc_mowas.py index 17ae61b..b3fdff1 100644 --- a/tests/unit/test_darc_mowas.py +++ b/tests/unit/test_darc_mowas.py @@ -3,12 +3,16 @@ Unit tests for DARC MoWaS CAP alert parsing """ +import asyncio +import configparser import xml.dom.minidom from datetime import datetime, timedelta, timezone +from unittest.mock import MagicMock, patch import pytest from modules.service_plugins.darc_mowas_service import ( + DARC_MoWaS_Service, TRDECapAlert, TRDECapAlertArea, TRDECapAlertInfo, @@ -113,3 +117,49 @@ class TestMoWaSAlertParsing: assert isinstance(area, TRDECapAlertArea) assert area.areaDesc == "Deutschland" assert ("SHN", "100000000000") in area.geocode + + +def _mowas_service_bot(): + bot = MagicMock() + bot.logger = MagicMock() + cfg = configparser.ConfigParser() + cfg.add_section("DARC_MoWaS_Service") + bot.config = cfg + return bot + + +@pytest.mark.unit +@pytest.mark.asyncio +async def test_send_chunks_assigns_ascending_timestamps_per_index(): + """Each chunk gets ts_now + i seconds so clients can order and dedupe.""" + svc = DARC_MoWaS_Service(_mowas_service_bot()) + captured: list[tuple[int, datetime]] = [] + + async def capture(channel, chunk, index, total, timestamp): + captured.append((index, timestamp)) + + svc._send_chunk_with_retry = capture # type: ignore[method-assign] + + pending: list[asyncio.Task] = [] + real_create_task = asyncio.create_task + + def schedule(coro): + task = real_create_task(coro) + pending.append(task) + return task + + with patch( + "modules.service_plugins.darc_mowas_service.asyncio.create_task", + side_effect=schedule, + ): + await svc._send_chunks("mowas", ["a", "b", "c"]) + + await asyncio.gather(*pending) + + assert len(captured) == 3 + captured.sort(key=lambda x: x[0]) + timestamps = [ts for _, ts in captured] + assert timestamps == sorted(timestamps) + assert len(set(timestamps)) == 3 + for i in range(1, len(timestamps)): + assert timestamps[i] - timestamps[i - 1] == timedelta(seconds=1)