feat: abstract MQTT network transport

This commit is contained in:
agessaman committed 2026-09-01 16:31:28 -07:00
1 parent f8fc35a11a
commit 03c0ad81fe
19 files changed
+731 -306

No files matched your search

+1
View File
@@ -29,6 +29,7 @@ does not reflect the GoogleTest count — run the built binary directly
| `test_topic_template` | `src/helpers/MQTTTopicTemplate.h` | `{iata}/{device}/{token}/{type}` expansion, overflow/NUL-termination, and a buffer-size fuzz |
| `test_mqtt_topic_router` | `src/helpers/MQTTTopicRouter.h` | complete preset/custom topic-routing contract; MeshRank all types except raw; required identifiers; invalid inputs/slots; exact buffer boundaries |
| `test_mqtt_connection_policy` | `src/helpers/MQTTConnectionPolicy.h` | reconnect guard/backoff/stagger and breaker transitions; stable reset; JWT lifetime/renewal policy; exact timing boundaries and 32-bit `millis()` rollover; WiFi current-outage start sticky across STA reconnect attempts |
| `test_network_policy` | `src/helpers/NetworkPolicy.h` | transport-neutral MQTT link-transition actions and `start ota` selected-LAN versus forced/fallback SoftAP choice |
| `test_alert_fault_policy` | `src/helpers/AlertFaultPolicy.h` | WiFi/MQTT fault edge detector; `OutageSnapshot` (down / started_ms / initiating reason) fed to tick and `formatWifiAlert`; reason-8 reconnects change neither duration nor initiating reason; flap between status polls; down at `millis()==0`; packed 64-bit cross-task word; rate-limit floor and first-fire; 5 s poll cadence and `millis()` rollover |
| `test_display_viewport` | `src/helpers/ui/DisplayViewport.h`, `src/helpers/ui/DisplayFrameSignature.h` | logical-to-physical portrait mapping; fractional span coverage; fitted-width conversion; preferred/fallback text scaling; stable visible-frame change detection |
| `test_mqtt_packet_queue_policy` | `src/helpers/MQTTPacketQueuePolicy.h` | queue-full eviction; stale-disconnect flush; adaptive drain limits; bounded QoS0 retries; exact timing boundaries and 32-bit `millis()` rollover |
@@ -350,6 +350,17 @@ TEST(AlertFaultPolicy, FormatWifiAlertUsesSnapshotReason) {
EXPECT_STREQ("WiFi down 47m", text);
}
TEST(AlertFaultPolicy, FormatNetworkAlertUsesSelectedMediumLabel) {
Alert::Fault f = OkFault();
const Alert::OutageSnapshot snap = Down(1000, 0);
const Alert::TickResult r = Alert::tick(
f, 1000 + kWifiThresh, snap, kWifiThresh, kMinInterval);
char text[80];
ASSERT_TRUE(Alert::formatNetworkAlert(
text, sizeof(text), "Ethernet", r, snap));
EXPECT_STREQ("Ethernet down 30m", text);
}
TEST(AlertFaultPolicy, FormatMqttSlotMessages) {
char text[100];
Alert::formatMqttDown(text, sizeof(text), 1, "analyzer-us", 30U * 60000U);
@@ -0,0 +1,36 @@
#include <gtest/gtest.h>
#include "helpers/NetworkPolicy.h"
TEST(NetworkPolicy, MqttDownDisconnectsSlotsWithoutRequestingImmediateRetry) {
const auto actions = NetworkPolicy::mqttActions(NetworkTransition::Down);
EXPECT_TRUE(actions.disconnect_slots);
EXPECT_FALSE(actions.retry_disconnected_slots_now);
}
TEST(NetworkPolicy, MqttUpRequestsImmediateRetryWithoutDisconnectingSlots) {
const auto actions = NetworkPolicy::mqttActions(NetworkTransition::Up);
EXPECT_FALSE(actions.disconnect_slots);
EXPECT_TRUE(actions.retry_disconnected_slots_now);
}
TEST(NetworkPolicy, NoTransitionHasNoMqttSideEffects) {
const auto actions = NetworkPolicy::mqttActions(NetworkTransition::None);
EXPECT_FALSE(actions.disconnect_slots);
EXPECT_FALSE(actions.retry_disconnected_slots_now);
}
TEST(NetworkPolicy, StartOtaUsesReachableSelectedNetworkByDefault) {
EXPECT_TRUE(NetworkPolicy::startOtaUsesSelectedNetwork(false, true));
EXPECT_FALSE(NetworkPolicy::startOtaUsesSelectedNetwork(false, false));
}
TEST(NetworkPolicy, StartOtaForceApOverridesAReachableSelectedNetwork) {
EXPECT_FALSE(NetworkPolicy::startOtaUsesSelectedNetwork(true, true));
EXPECT_FALSE(NetworkPolicy::startOtaUsesSelectedNetwork(true, false));
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}