feat(firmware): add NVS-backed event log ring buffer

Persistent 32-slot ring buffer of tagged diagnostic events (boot, wifi
up/down, http ok/fail, heartbeat miss, reboot). Used to diagnose field
failures post-hoc via the heartbeat payload, without needing serial
access. Native-native stub lets policy be unit-tested.
This commit is contained in:
2026-04-23 13:06:38 -07:00
parent a37207b6ff
commit 9232766e60
3 changed files with 204 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
// firmware/test/test_native/test_event_log.cpp
#include <unity.h>
#include <string.h>
#include "event_log.h"
// --- Native NVS stub (declared in event_log.cpp for native builds) ---
extern "C" void event_log_test_reset();
void setUp() { event_log_test_reset(); }
void tearDown() {}
void test_entry_is_32_bytes() {
TEST_ASSERT_EQUAL(32, sizeof(EventLogEntry));
}
void test_path_hash_is_stable_and_differs() {
uint16_t a = event_log_path_hash("/api/v1/heartbeat");
uint16_t b = event_log_path_hash("/api/v1/heartbeat");
uint16_t c = event_log_path_hash("/api/v1/camera/events/batch");
TEST_ASSERT_EQUAL(a, b);
TEST_ASSERT_NOT_EQUAL(a, c);
}
void test_write_then_read_recent_returns_newest_first() {
event_log_init();
event_log_write(EVT_BOOT, 1, 0);
event_log_write(EVT_WIFI_UP, 2, 0);
event_log_write(EVT_HTTP_FAIL, 3, 500);
EventLogEntry buf[8];
size_t n = event_log_read_recent(buf, 8);
TEST_ASSERT_EQUAL(3, n);
TEST_ASSERT_EQUAL(EVT_HTTP_FAIL, buf[0].tag);
TEST_ASSERT_EQUAL(500, buf[0].data1);
TEST_ASSERT_EQUAL(EVT_WIFI_UP, buf[1].tag);
TEST_ASSERT_EQUAL(EVT_BOOT, buf[2].tag);
}
void test_ring_buffer_wraps_after_32_entries() {
event_log_init();
for (int i = 0; i < 40; i++) event_log_write(EVT_HTTP_OK, (uint16_t)i, 0);
EventLogEntry buf[32];
size_t n = event_log_read_recent(buf, 32);
TEST_ASSERT_EQUAL(32, n);
// Newest first: data0 should be 39, 38, 37, ... down to 8
TEST_ASSERT_EQUAL(39, buf[0].data0);
TEST_ASSERT_EQUAL(8, buf[31].data0);
}
int main() {
UNITY_BEGIN();
RUN_TEST(test_entry_is_32_bytes);
RUN_TEST(test_path_hash_is_stable_and_differs);
RUN_TEST(test_write_then_read_recent_returns_newest_first);
RUN_TEST(test_ring_buffer_wraps_after_32_entries);
return UNITY_END();
}