upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-18 19:14:45 +0530
committerYour Name <you@example.com>2026-05-18 19:14:45 +0530
commit78d0c3795e9a90a9f99178e38346a53d9b2ebe57 (patch)
treed9583018e6318d389452bcd3a2b505d1716051d5
parent859f9b14e033de9a0690ccbbb975b4b472b688ce (diff)
Add test_mint_health: 14 host unit tests for mint health module
Tests: init, get_all, initial state, is_reachable, mark_unreachable, overflow handling, empty init, callback registration, reinit, start/stop. Adds freertos/semphr.h stub and pdTRUE to FreeRTOS.h stub.
-rw-r--r--tests/unit/Makefile5
-rw-r--r--tests/unit/stubs/freertos/FreeRTOS.h1
-rw-r--r--tests/unit/stubs/freertos/semphr.h7
-rw-r--r--tests/unit/test_mint_health.c194
4 files changed, 206 insertions, 1 deletions
diff --git a/tests/unit/Makefile b/tests/unit/Makefile
index f47ef23..fc84c4e 100644
--- a/tests/unit/Makefile
+++ b/tests/unit/Makefile
@@ -22,7 +22,7 @@ LDFLAGS := -lmbedcrypto -lcjson -lm
22 22
23SECP256K1_OBJ := secp256k1.o precomputed_ecmult.o precomputed_ecmult_gen.o 23SECP256K1_OBJ := secp256k1.o precomputed_ecmult.o precomputed_ecmult_gen.o
24 24
25TESTS := test_geohash test_identity test_nostr_event test_cashu test_session test_tollgate_client test_lnurl_pay test_lightning_payout test_mcp_handler test_nip04 test_cvm_server 25TESTS := test_geohash test_identity test_nostr_event test_cashu test_session test_tollgate_client test_lnurl_pay test_lightning_payout test_mcp_handler test_nip04 test_cvm_server test_mint_health
26 26
27.PHONY: all test clean $(TESTS) 27.PHONY: all test clean $(TESTS)
28 28
@@ -81,5 +81,8 @@ test_nip04: test_nip04.c $(REPO_ROOT)/main/nip04.c $(SECP256K1_OBJ)
81test_cvm_server: test_cvm_server.c 81test_cvm_server: test_cvm_server.c
82 $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) 82 $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
83 83
84test_mint_health: test_mint_health.c $(REPO_ROOT)/main/mint_health.c
85 $(CC) -Wall -Wextra -Wno-unused-parameter -Wno-unused-function -Wno-sign-compare -std=gnu17 -g -O0 -DTEST_HOST -include stubs/esp_err.h -I $(REPO_ROOT)/main -I stubs -I $(SECP256K1_INC) -I $(SECP256K1_CFG) -I /usr/include/cjson $< $(REPO_ROOT)/main/mint_health.c -o $@ $(LDFLAGS)
86
84clean: 87clean:
85 rm -f $(TESTS) $(SECP256K1_OBJ) 88 rm -f $(TESTS) $(SECP256K1_OBJ)
diff --git a/tests/unit/stubs/freertos/FreeRTOS.h b/tests/unit/stubs/freertos/FreeRTOS.h
index 696da87..2d2b967 100644
--- a/tests/unit/stubs/freertos/FreeRTOS.h
+++ b/tests/unit/stubs/freertos/FreeRTOS.h
@@ -8,5 +8,6 @@ static inline void vTaskDelay(uint32_t ticks) { (void)ticks; }
8#define pdMS_TO_TICKS(ms) ((ms) / 10) 8#define pdMS_TO_TICKS(ms) ((ms) / 10)
9#define portTICK_PERIOD_MS 10 9#define portTICK_PERIOD_MS 10
10#define portMAX_DELAY 0xFFFFFFFF 10#define portMAX_DELAY 0xFFFFFFFF
11#define pdTRUE 1
11 12
12#endif 13#endif
diff --git a/tests/unit/stubs/freertos/semphr.h b/tests/unit/stubs/freertos/semphr.h
new file mode 100644
index 0000000..0389b11
--- /dev/null
+++ b/tests/unit/stubs/freertos/semphr.h
@@ -0,0 +1,7 @@
1#ifndef STUBS_FREERTOS_SEMPHR_H
2#define STUBS_FREERTOS_SEMPHR_H
3
4#include "FreeRTOS.h"
5#include "task.h"
6
7#endif
diff --git a/tests/unit/test_mint_health.c b/tests/unit/test_mint_health.c
new file mode 100644
index 0000000..d170d55
--- /dev/null
+++ b/tests/unit/test_mint_health.c
@@ -0,0 +1,194 @@
1#include <stdio.h>
2#include <string.h>
3#include <assert.h>
4#include "mint_health.h"
5
6static int test_count = 0;
7static int pass_count = 0;
8
9#define TEST(name) do { \
10 test_count++; \
11 printf(" TEST: %s ... ", name); \
12} while(0)
13
14#define PASS() do { \
15 pass_count++; \
16 printf("PASS\n"); \
17} while(0)
18
19#define FAIL(msg) do { \
20 printf("FAIL: %s\n", msg); \
21} while(0)
22
23#define ASSERT_EQ(a, b, msg) do { \
24 if ((a) != (b)) { FAIL(msg); return; } \
25} while(0)
26
27#define ASSERT_TRUE(a, msg) do { \
28 if (!(a)) { FAIL(msg); return; } \
29} while(0)
30
31#define ASSERT_FALSE(a, msg) do { \
32 if ((a)) { FAIL(msg); return; } \
33} while(0)
34
35static void test_init_basic(void) {
36 TEST("init with 4 mints");
37 const char urls[4][256] = {
38 "https://mint.minibits.cash/Bitcoin",
39 "https://mint.coinos.io",
40 "https://21mint.me",
41 "https://mint.lnvoltz.com"
42 };
43 esp_err_t err = mint_health_init(urls, 4);
44 ASSERT_EQ(err, 0, "init should return ESP_OK");
45 PASS();
46}
47
48static void test_get_all(void) {
49 TEST("get_all returns correct count");
50 int count = 0;
51 const mint_status_t *mints = mint_health_get_all(&count);
52 ASSERT_EQ(count, 4, "should have 4 mints");
53 ASSERT_TRUE(mints != NULL, "mints should not be NULL");
54 PASS();
55}
56
57static void test_initial_state_unreachable(void) {
58 TEST("initial state: all mints unreachable (no probes run)");
59 const char *expected_urls[] = {
60 "https://mint.minibits.cash/Bitcoin",
61 "https://mint.coinos.io",
62 "https://21mint.me",
63 "https://mint.lnvoltz.com"
64 };
65 int count = 0;
66 const mint_status_t *mints = mint_health_get_all(&count);
67 ASSERT_EQ(count, 4, "should have 4 mints");
68 for (int i = 0; i < count; i++) {
69 ASSERT_FALSE(mints[i].reachable, "initial mint should be unreachable");
70 ASSERT_EQ(mints[i].consecutive_successes, 0, "initial successes should be 0");
71 ASSERT_TRUE(strcmp(mints[i].url, expected_urls[i]) == 0, "URL mismatch");
72 }
73 PASS();
74}
75
76static void test_is_reachable_before_probes(void) {
77 TEST("is_reachable returns false before probes");
78 bool r = mint_health_is_reachable("https://mint.minibits.cash/Bitcoin");
79 ASSERT_FALSE(r, "should be unreachable before probes");
80 PASS();
81}
82
83static void test_is_reachable_null(void) {
84 TEST("is_reachable returns false for NULL");
85 bool r = mint_health_is_reachable(NULL);
86 ASSERT_FALSE(r, "NULL should return false");
87 PASS();
88}
89
90static void test_is_reachable_unknown_url(void) {
91 TEST("is_reachable returns false for unknown URL");
92 bool r = mint_health_is_reachable("https://unknown.mint.example.com");
93 ASSERT_FALSE(r, "unknown URL should return false");
94 PASS();
95}
96
97static void test_mark_unreachable(void) {
98 TEST("mark_unreachable on already-unreachable mint");
99 mint_health_mark_unreachable("https://mint.coinos.io");
100 bool r = mint_health_is_reachable("https://mint.coinos.io");
101 ASSERT_FALSE(r, "should still be unreachable");
102 PASS();
103}
104
105static void test_mark_unreachable_null(void) {
106 TEST("mark_unreachable with NULL does not crash");
107 mint_health_mark_unreachable(NULL);
108 PASS();
109}
110
111static void test_init_overflow(void) {
112 TEST("init with more than MAX mints truncates");
113 const char urls[MINT_HEALTH_MAX + 2][256];
114 for (int i = 0; i < MINT_HEALTH_MAX + 2; i++) {
115 snprintf((char *)urls[i], 256, "https://mint%d.example.com", i);
116 }
117 esp_err_t err = mint_health_init(urls, MINT_HEALTH_MAX + 2);
118 ASSERT_EQ(err, 0, "init should succeed");
119
120 int count = 0;
121 mint_health_get_all(&count);
122 ASSERT_EQ(count, MINT_HEALTH_MAX, "should be truncated to MAX");
123 PASS();
124}
125
126static void test_init_empty(void) {
127 TEST("init with 0 mints");
128 esp_err_t err = mint_health_init(NULL, 0);
129 ASSERT_EQ(err, 0, "init with 0 should succeed");
130
131 int count = -1;
132 mint_health_get_all(&count);
133 ASSERT_EQ(count, 0, "should have 0 mints");
134 PASS();
135}
136
137static void dummy_cb(void) { }
138
139static void test_register_callback(void) {
140 TEST("register_callback does not crash");
141 mint_health_register_callback(dummy_cb);
142 PASS();
143}
144
145static void test_register_callback_null(void) {
146 TEST("register_callback NULL does not crash");
147 mint_health_register_callback(NULL);
148 PASS();
149}
150
151static void test_reinit_resets_state(void) {
152 TEST("re-init resets state");
153 const char urls[2][256] = {
154 "https://mint-a.example.com",
155 "https://mint-b.example.com"
156 };
157 mint_health_init(urls, 2);
158
159 int count = 0;
160 const mint_status_t *mints = mint_health_get_all(&count);
161 ASSERT_EQ(count, 2, "should have 2 mints");
162 ASSERT_TRUE(strcmp(mints[0].url, "https://mint-a.example.com") == 0, "first URL");
163 ASSERT_TRUE(strcmp(mints[1].url, "https://mint-b.example.com") == 0, "second URL");
164 PASS();
165}
166
167static void test_start_stop(void) {
168 TEST("start/stop do not crash (task stubbed)");
169 mint_health_start();
170 mint_health_stop();
171 PASS();
172}
173
174int main(void) {
175 printf("\n=== Mint Health Unit Tests ===\n\n");
176
177 test_init_basic();
178 test_get_all();
179 test_initial_state_unreachable();
180 test_is_reachable_before_probes();
181 test_is_reachable_null();
182 test_is_reachable_unknown_url();
183 test_mark_unreachable();
184 test_mark_unreachable_null();
185 test_init_overflow();
186 test_init_empty();
187 test_register_callback();
188 test_register_callback_null();
189 test_reinit_resets_state();
190 test_start_stop();
191
192 printf("\n=== Results: %d passed, %d failed ===\n\n", pass_count, test_count - pass_count);
193 return (pass_count == test_count) ? 0 : 1;
194}