diff options
| author | Your Name <you@example.com> | 2026-05-23 15:26:52 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-23 15:26:52 +0530 |
| commit | be4d490e96de3d20cc6c9921f09534cde0ca0765 (patch) | |
| tree | 624cdbaff079e14a26fc22f7741a1452b54555b9 /tests/unit | |
| parent | 4ce93d0470e8ab2402486c893f50bfdf216752e6 (diff) | |
Phase 8c-8f: Extract portal, stratum_client, mint_health, client into tollgate_core
New component modules:
- tollgate_core_portal.c/h: template rendering, usage calc, captive URI detection
- tollgate_core_stratum_client.c/h: Stratum V1 JSON protocol parsing, message building
- tollgate_core_mint_health.c/h: mint health state tracking, recovery threshold logic
- tollgate_core_client.c/h: discovery/session/usage JSON parsing, renewal check, price calc
Main shims updated to delegate pure logic to component:
- captive_portal.c: uses tollgate_core_portal_render(), format_usage(), is_captive_uri()
- stratum_client.c: uses tollgate_core_stratum_parse_notify/build_*()
- mint_health.c: uses tollgate_core_mint_health_update/is_reachable/mark_unreachable()
- tollgate_client.c: uses tollgate_core_client_parse_*/should_renew/calc_price_per_min()
4 new unit tests (test_portal, test_stratum_client, test_mint_health_core, test_client_core)
All 25 unit tests pass. ESP-IDF build passes (68% partition free).
Diffstat (limited to 'tests/unit')
| -rw-r--r-- | tests/unit/Makefile | 26 | ||||
| -rw-r--r-- | tests/unit/test_client_core.c | 189 | ||||
| -rw-r--r-- | tests/unit/test_mint_health_core.c | 130 | ||||
| -rw-r--r-- | tests/unit/test_portal.c | 153 | ||||
| -rw-r--r-- | tests/unit/test_stratum_client.c | 125 |
5 files changed, 616 insertions, 7 deletions
diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 9347516..591ec0f 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile | |||
| @@ -26,7 +26,7 @@ LDFLAGS := -lmbedcrypto -lcjson -lm | |||
| 26 | 26 | ||
| 27 | SECP256K1_OBJ := secp256k1.o precomputed_ecmult.o precomputed_ecmult_gen.o | 27 | SECP256K1_OBJ := secp256k1.o precomputed_ecmult.o precomputed_ecmult_gen.o |
| 28 | 28 | ||
| 29 | TESTS := 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_beacon_price test_market test_mint_health test_mining_payment test_stratum_proxy test_session_payment_method test_tollgate_client_mining test_firewall_sandbox test_relay_selector test_relay_validator | 29 | TESTS := 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_beacon_price test_market test_mint_health test_mining_payment test_stratum_proxy test_session_payment_method test_tollgate_client_mining test_firewall_sandbox test_relay_selector test_relay_validator test_portal test_stratum_client test_mint_health_core test_client_core |
| 30 | 30 | ||
| 31 | .PHONY: all test clean $(TESTS) | 31 | .PHONY: all test clean $(TESTS) |
| 32 | 32 | ||
| @@ -69,8 +69,8 @@ TG_CORE_OBJS_CFLAGS := -include stubs/mint_health.h -include stubs/esp_netif.h - | |||
| 69 | test_session: test_session.c $(TG_CORE_SRC)/tollgate_core_cashu.c $(TG_CORE_SRC)/tollgate_core_session.c $(TG_CORE_SRC)/tollgate_core_firewall.c $(TG_CORE_SRC)/tollgate_core.c $(TG_CORE_SRC)/tollgate_core_mining.c $(TG_CORE_SRC)/tollgate_core_dns.c $(TG_CORE_SRC)/tollgate_core_stratum_proxy.c | 69 | test_session: test_session.c $(TG_CORE_SRC)/tollgate_core_cashu.c $(TG_CORE_SRC)/tollgate_core_session.c $(TG_CORE_SRC)/tollgate_core_firewall.c $(TG_CORE_SRC)/tollgate_core.c $(TG_CORE_SRC)/tollgate_core_mining.c $(TG_CORE_SRC)/tollgate_core_dns.c $(TG_CORE_SRC)/tollgate_core_stratum_proxy.c |
| 70 | $(CC) $(CFLAGS) $(TG_CORE_OBJS_CFLAGS) $^ -o $@ $(LDFLAGS) | 70 | $(CC) $(CFLAGS) $(TG_CORE_OBJS_CFLAGS) $^ -o $@ $(LDFLAGS) |
| 71 | 71 | ||
| 72 | test_tollgate_client: test_tollgate_client.c $(REPO_ROOT)/main/market.c $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c $(TG_CORE_SRC)/tollgate_core_market.c | 72 | test_tollgate_client: test_tollgate_client.c $(REPO_ROOT)/main/market.c $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c $(TG_CORE_SRC)/tollgate_core_market.c $(TG_CORE_SRC)/tollgate_core_client.c |
| 73 | $(CC) $(CFLAGS) -I $(REPO_ROOT)/main $< $(REPO_ROOT)/main/market.c $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c $(TG_CORE_SRC)/tollgate_core_market.c -o $@ $(LDFLAGS) | 73 | $(CC) $(CFLAGS) -I $(REPO_ROOT)/main $< $(REPO_ROOT)/main/market.c $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c $(TG_CORE_SRC)/tollgate_core_market.c $(TG_CORE_SRC)/tollgate_core_client.c -o $@ $(LDFLAGS) |
| 74 | 74 | ||
| 75 | test_lnurl_pay: test_lnurl_pay.c | 75 | test_lnurl_pay: test_lnurl_pay.c |
| 76 | $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) | 76 | $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) |
| @@ -87,8 +87,8 @@ test_nip04: test_nip04.c $(REPO_ROOT)/main/nip04.c $(SECP256K1_OBJ) | |||
| 87 | test_cvm_server: test_cvm_server.c | 87 | test_cvm_server: test_cvm_server.c |
| 88 | $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) | 88 | $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) |
| 89 | 89 | ||
| 90 | test_mint_health: test_mint_health.c $(REPO_ROOT)/main/mint_health.c | 90 | test_mint_health: test_mint_health.c $(REPO_ROOT)/main/mint_health.c $(TG_CORE_SRC)/tollgate_core_mint_health.c |
| 91 | $(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) | 91 | $(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 -I $(TG_CORE_SRC) -I $(TG_CORE_INC) $^ -o $@ $(LDFLAGS) |
| 92 | 92 | ||
| 93 | test_beacon_price: test_beacon_price.c $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c | 93 | test_beacon_price: test_beacon_price.c $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c |
| 94 | $(CC) $(CFLAGS) -I $(REPO_ROOT)/main $< $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c -o $@ $(LDFLAGS) | 94 | $(CC) $(CFLAGS) -I $(REPO_ROOT)/main $< $(REPO_ROOT)/main/beacon_price.c $(TG_CORE_SRC)/tollgate_core_beacon.c -o $@ $(LDFLAGS) |
| @@ -105,8 +105,8 @@ test_stratum_proxy: test_stratum_proxy.c $(REPO_ROOT)/main/stratum_proxy.c $(TG_ | |||
| 105 | test_session_payment_method: test_session_payment_method.c $(TG_CORE_SRC)/tollgate_core_cashu.c $(TG_CORE_SRC)/tollgate_core_session.c $(TG_CORE_SRC)/tollgate_core_firewall.c $(TG_CORE_SRC)/tollgate_core.c $(TG_CORE_SRC)/tollgate_core_mining.c $(TG_CORE_SRC)/tollgate_core_dns.c $(TG_CORE_SRC)/tollgate_core_stratum_proxy.c | 105 | test_session_payment_method: test_session_payment_method.c $(TG_CORE_SRC)/tollgate_core_cashu.c $(TG_CORE_SRC)/tollgate_core_session.c $(TG_CORE_SRC)/tollgate_core_firewall.c $(TG_CORE_SRC)/tollgate_core.c $(TG_CORE_SRC)/tollgate_core_mining.c $(TG_CORE_SRC)/tollgate_core_dns.c $(TG_CORE_SRC)/tollgate_core_stratum_proxy.c |
| 106 | $(CC) $(CFLAGS) $(TG_CORE_OBJS_CFLAGS) $^ -o $@ $(LDFLAGS) | 106 | $(CC) $(CFLAGS) $(TG_CORE_OBJS_CFLAGS) $^ -o $@ $(LDFLAGS) |
| 107 | 107 | ||
| 108 | test_tollgate_client_mining: test_tollgate_client_mining.c | 108 | test_tollgate_client_mining: test_tollgate_client_mining.c $(TG_CORE_SRC)/tollgate_core_client.c |
| 109 | $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) | 109 | $(CC) $(CFLAGS) -I $(REPO_ROOT)/main $< $(TG_CORE_SRC)/tollgate_core_client.c -o $@ $(LDFLAGS) |
| 110 | 110 | ||
| 111 | test_firewall_sandbox: test_firewall_sandbox.c $(TG_CORE_SRC)/tollgate_core_firewall.c $(TG_CORE_SRC)/tollgate_core.c $(TG_CORE_SRC)/tollgate_core_session.c $(TG_CORE_SRC)/tollgate_core_cashu.c $(TG_CORE_SRC)/tollgate_core_mining.c $(TG_CORE_SRC)/tollgate_core_dns.c $(TG_CORE_SRC)/tollgate_core_stratum_proxy.c | 111 | test_firewall_sandbox: test_firewall_sandbox.c $(TG_CORE_SRC)/tollgate_core_firewall.c $(TG_CORE_SRC)/tollgate_core.c $(TG_CORE_SRC)/tollgate_core_session.c $(TG_CORE_SRC)/tollgate_core_cashu.c $(TG_CORE_SRC)/tollgate_core_mining.c $(TG_CORE_SRC)/tollgate_core_dns.c $(TG_CORE_SRC)/tollgate_core_stratum_proxy.c |
| 112 | $(CC) $(CFLAGS) -include stubs/dns_server.h $(TG_CORE_OBJS_CFLAGS) $^ -o $@ $(LDFLAGS) | 112 | $(CC) $(CFLAGS) -include stubs/dns_server.h $(TG_CORE_OBJS_CFLAGS) $^ -o $@ $(LDFLAGS) |
| @@ -117,5 +117,17 @@ test_relay_selector: test_relay_selector.c | |||
| 117 | test_relay_validator: test_relay_validator.c $(REPO_ROOT)/main/nostr_event.c $(REPO_ROOT)/main/identity.c $(REPO_ROOT)/components/wisp_relay/relay_validator.c $(SECP256K1_OBJ) | 117 | test_relay_validator: test_relay_validator.c $(REPO_ROOT)/main/nostr_event.c $(REPO_ROOT)/main/identity.c $(REPO_ROOT)/components/wisp_relay/relay_validator.c $(SECP256K1_OBJ) |
| 118 | $(CC) $(CFLAGS) -I $(SECP256K1_PRIV_INC) -I $(REPO_ROOT)/main -I $(REPO_ROOT)/components/wisp_relay $< $(REPO_ROOT)/main/nostr_event.c $(REPO_ROOT)/main/identity.c $(REPO_ROOT)/components/wisp_relay/relay_validator.c $(SECP256K1_OBJ) -o $@ $(LDFLAGS) | 118 | $(CC) $(CFLAGS) -I $(SECP256K1_PRIV_INC) -I $(REPO_ROOT)/main -I $(REPO_ROOT)/components/wisp_relay $< $(REPO_ROOT)/main/nostr_event.c $(REPO_ROOT)/main/identity.c $(REPO_ROOT)/components/wisp_relay/relay_validator.c $(SECP256K1_OBJ) -o $@ $(LDFLAGS) |
| 119 | 119 | ||
| 120 | test_portal: test_portal.c $(TG_CORE_SRC)/tollgate_core_portal.c | ||
| 121 | $(CC) $(CFLAGS) $(TG_CORE_OBJS_CFLAGS) $^ -o $@ $(LDFLAGS) | ||
| 122 | |||
| 123 | test_stratum_client: test_stratum_client.c $(TG_CORE_SRC)/tollgate_core_stratum_client.c | ||
| 124 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) | ||
| 125 | |||
| 126 | test_mint_health_core: test_mint_health_core.c $(TG_CORE_SRC)/tollgate_core_mint_health.c | ||
| 127 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) | ||
| 128 | |||
| 129 | test_client_core: test_client_core.c $(TG_CORE_SRC)/tollgate_core_client.c | ||
| 130 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) | ||
| 131 | |||
| 120 | clean: | 132 | clean: |
| 121 | rm -f $(TESTS) $(SECP256K1_OBJ) | 133 | rm -f $(TESTS) $(SECP256K1_OBJ) |
diff --git a/tests/unit/test_client_core.c b/tests/unit/test_client_core.c new file mode 100644 index 0000000..7cc6cc7 --- /dev/null +++ b/tests/unit/test_client_core.c | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | #include "test_framework.h" | ||
| 2 | #include "../../components/tollgate_core/src/tollgate_core_client.h" | ||
| 3 | #include <cjson/cJSON.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include <stdio.h> | ||
| 6 | |||
| 7 | int main(void) | ||
| 8 | { | ||
| 9 | printf("=== test_client_core ===\n"); | ||
| 10 | |||
| 11 | printf("\n--- parse_discovery valid ---\n"); | ||
| 12 | { | ||
| 13 | const char *json = "{\"kind\":10021,\"content\":\"discovery\"," | ||
| 14 | "\"tags\":[" | ||
| 15 | "[\"metric\",\"milliseconds\"]," | ||
| 16 | "[\"step_size\",\"60000\"]," | ||
| 17 | "[\"price_per_step\",\"21\",\"21\",\"sha256\",\"https://test.mint\"]" | ||
| 18 | "]}"; | ||
| 19 | tollgate_discovery_t disc = {0}; | ||
| 20 | bool ok = tollgate_core_client_parse_discovery(json, &disc); | ||
| 21 | ASSERT(ok, "parse_discovery returns true"); | ||
| 22 | ASSERT(disc.is_tollgate, "is_tollgate set"); | ||
| 23 | ASSERT_EQ_INT(21, disc.price_per_step, "price_per_step"); | ||
| 24 | ASSERT_EQ_INT(60000, disc.step_size_ms, "step_size_ms"); | ||
| 25 | ASSERT(strcmp(disc.metric, "milliseconds") == 0, "metric"); | ||
| 26 | ASSERT(strcmp(disc.mint_url, "https://test.mint") == 0, "mint_url"); | ||
| 27 | } | ||
| 28 | |||
| 29 | printf("\n--- parse_discovery wrong kind ---\n"); | ||
| 30 | { | ||
| 31 | const char *json = "{\"kind\":9999}"; | ||
| 32 | tollgate_discovery_t disc = {0}; | ||
| 33 | bool ok = tollgate_core_client_parse_discovery(json, &disc); | ||
| 34 | ASSERT(!ok, "wrong kind returns false"); | ||
| 35 | } | ||
| 36 | |||
| 37 | printf("\n--- parse_discovery mining payment ---\n"); | ||
| 38 | { | ||
| 39 | const char *json = "{\"kind\":10021,\"content\":\"\"," | ||
| 40 | "\"tags\":[" | ||
| 41 | "[\"metric\",\"milliseconds\"]," | ||
| 42 | "[\"step_size\",\"60000\"]," | ||
| 43 | "[\"price_per_step\",\"0\",\"mining\",\"3333\",\"extra\"]" | ||
| 44 | "]}"; | ||
| 45 | tollgate_discovery_t disc = {0}; | ||
| 46 | bool ok = tollgate_core_client_parse_discovery(json, &disc); | ||
| 47 | ASSERT(ok, "parse_discovery mining returns true"); | ||
| 48 | ASSERT(disc.mining_available, "mining_available set"); | ||
| 49 | ASSERT_EQ_INT(3333, (int)disc.mining_port, "mining_port"); | ||
| 50 | } | ||
| 51 | |||
| 52 | printf("\n--- parse_discovery empty tags ---\n"); | ||
| 53 | { | ||
| 54 | const char *json = "{\"kind\":10021,\"tags\":[]}"; | ||
| 55 | tollgate_discovery_t disc = {0}; | ||
| 56 | bool ok = tollgate_core_client_parse_discovery(json, &disc); | ||
| 57 | ASSERT(ok, "empty tags returns true"); | ||
| 58 | ASSERT(disc.is_tollgate, "is_tollgate set"); | ||
| 59 | } | ||
| 60 | |||
| 61 | printf("\n--- parse_discovery no tags ---\n"); | ||
| 62 | { | ||
| 63 | const char *json = "{\"kind\":10021}"; | ||
| 64 | tollgate_discovery_t disc = {0}; | ||
| 65 | bool ok = tollgate_core_client_parse_discovery(json, &disc); | ||
| 66 | ASSERT(ok, "no tags returns true"); | ||
| 67 | } | ||
| 68 | |||
| 69 | printf("\n--- parse_discovery invalid JSON ---\n"); | ||
| 70 | { | ||
| 71 | tollgate_discovery_t disc = {0}; | ||
| 72 | bool ok = tollgate_core_client_parse_discovery("not json", &disc); | ||
| 73 | ASSERT(!ok, "invalid JSON returns false"); | ||
| 74 | } | ||
| 75 | |||
| 76 | printf("\n--- parse_session valid ---\n"); | ||
| 77 | { | ||
| 78 | const char *json = "{\"kind\":1022,\"content\":\"session\"," | ||
| 79 | "\"tags\":[[\"allotment\",\"120000\"]]}"; | ||
| 80 | int64_t allotment = 0; | ||
| 81 | bool ok = tollgate_core_client_parse_session(json, &allotment); | ||
| 82 | ASSERT(ok, "parse_session returns true"); | ||
| 83 | ASSERT_EQ_UINT64(120000, (unsigned long long)allotment, "allotment_ms"); | ||
| 84 | } | ||
| 85 | |||
| 86 | printf("\n--- parse_session wrong kind ---\n"); | ||
| 87 | { | ||
| 88 | const char *json = "{\"kind\":10021}"; | ||
| 89 | int64_t allotment = 0; | ||
| 90 | bool ok = tollgate_core_client_parse_session(json, &allotment); | ||
| 91 | ASSERT(!ok, "wrong kind returns false"); | ||
| 92 | } | ||
| 93 | |||
| 94 | printf("\n--- parse_session no allotment tag ---\n"); | ||
| 95 | { | ||
| 96 | const char *json = "{\"kind\":1022,\"tags\":[]}"; | ||
| 97 | int64_t allotment = 999; | ||
| 98 | bool ok = tollgate_core_client_parse_session(json, &allotment); | ||
| 99 | ASSERT(ok, "returns true"); | ||
| 100 | ASSERT_EQ_UINT64(999, (unsigned long long)allotment, "allotment unchanged when no tag"); | ||
| 101 | } | ||
| 102 | |||
| 103 | printf("\n--- parse_usage valid ---\n"); | ||
| 104 | { | ||
| 105 | int64_t remaining = 0, total = 0; | ||
| 106 | bool ok = tollgate_core_client_parse_usage("45000/60000", &remaining, &total); | ||
| 107 | ASSERT(ok, "parse_usage returns true"); | ||
| 108 | ASSERT_EQ_UINT64(45000, (unsigned long long)remaining, "remaining"); | ||
| 109 | ASSERT_EQ_UINT64(60000, (unsigned long long)total, "total"); | ||
| 110 | } | ||
| 111 | |||
| 112 | printf("\n--- parse_usage no slash ---\n"); | ||
| 113 | { | ||
| 114 | int64_t remaining = 0, total = 0; | ||
| 115 | bool ok = tollgate_core_client_parse_usage("45000", &remaining, &total); | ||
| 116 | ASSERT(!ok, "no slash returns false"); | ||
| 117 | } | ||
| 118 | |||
| 119 | printf("\n--- parse_usage zero values ---\n"); | ||
| 120 | { | ||
| 121 | int64_t remaining = 0, total = 0; | ||
| 122 | bool ok = tollgate_core_client_parse_usage("0/0", &remaining, &total); | ||
| 123 | ASSERT(ok, "parse_usage zero values"); | ||
| 124 | ASSERT_EQ_UINT64(0, (unsigned long long)remaining, "remaining is 0"); | ||
| 125 | ASSERT_EQ_UINT64(0, (unsigned long long)total, "total is 0"); | ||
| 126 | } | ||
| 127 | |||
| 128 | printf("\n--- should_renew ---\n"); | ||
| 129 | { | ||
| 130 | ASSERT(tollgate_core_client_should_renew(1000, 60000, 20), | ||
| 131 | "1.6% remaining → should renew"); | ||
| 132 | ASSERT(tollgate_core_client_should_renew(0, 60000, 20), | ||
| 133 | "0% remaining → should renew"); | ||
| 134 | ASSERT(!tollgate_core_client_should_renew(30000, 60000, 20), | ||
| 135 | "50% remaining → should not renew"); | ||
| 136 | ASSERT(!tollgate_core_client_should_renew(60000, 60000, 20), | ||
| 137 | "100% remaining → should not renew"); | ||
| 138 | ASSERT(tollgate_core_client_should_renew(11999, 60000, 20), | ||
| 139 | "19.99% → should renew"); | ||
| 140 | ASSERT(tollgate_core_client_should_renew(12000, 60000, 20), | ||
| 141 | "20% exactly at threshold → should renew"); | ||
| 142 | } | ||
| 143 | |||
| 144 | printf("\n--- should_renew default threshold ---\n"); | ||
| 145 | { | ||
| 146 | ASSERT(tollgate_core_client_should_renew(1000, 60000, 0), | ||
| 147 | "threshold=0 defaults to 20%"); | ||
| 148 | ASSERT(tollgate_core_client_should_renew(1000, 60000, -1), | ||
| 149 | "negative threshold defaults to 20%"); | ||
| 150 | } | ||
| 151 | |||
| 152 | printf("\n--- should_renew edge cases ---\n"); | ||
| 153 | { | ||
| 154 | ASSERT(!tollgate_core_client_should_renew(-1, 60000, 20), | ||
| 155 | "negative remaining → false"); | ||
| 156 | ASSERT(!tollgate_core_client_should_renew(1000, 0, 20), | ||
| 157 | "zero allotment → false"); | ||
| 158 | } | ||
| 159 | |||
| 160 | printf("\n--- calc_price_per_min ---\n"); | ||
| 161 | { | ||
| 162 | ASSERT_EQ_INT(21, tollgate_core_client_calc_price_per_min(21, 60000), | ||
| 163 | "21 sats/60s = 21 sats/min"); | ||
| 164 | ASSERT_EQ_INT(42, tollgate_core_client_calc_price_per_min(21, 30000), | ||
| 165 | "21 sats/30s = 42 sats/min"); | ||
| 166 | ASSERT_EQ_INT(21000, tollgate_core_client_calc_price_per_min(21, 60), | ||
| 167 | "21 sats/60ms effective"); | ||
| 168 | } | ||
| 169 | |||
| 170 | printf("\n--- calc_price_per_min zero step ---\n"); | ||
| 171 | { | ||
| 172 | int result = tollgate_core_client_calc_price_per_min(21, 0); | ||
| 173 | ASSERT(result > 0, "zero step_size_ms doesn't crash"); | ||
| 174 | } | ||
| 175 | |||
| 176 | printf("\n--- calc_steps ---\n"); | ||
| 177 | { | ||
| 178 | ASSERT_EQ_INT(21, tollgate_core_client_calc_steps(1, 21, 21), | ||
| 179 | "1 step * 21 = 21"); | ||
| 180 | ASSERT_EQ_INT(42, tollgate_core_client_calc_steps(2, 21, 21), | ||
| 181 | "2 steps * 21 = 42"); | ||
| 182 | ASSERT_EQ_INT(21, tollgate_core_client_calc_steps(0, 21, 21), | ||
| 183 | "0 steps defaults to 1"); | ||
| 184 | ASSERT_EQ_INT(21, tollgate_core_client_calc_steps(-1, 21, 21), | ||
| 185 | "negative steps defaults to 1"); | ||
| 186 | } | ||
| 187 | |||
| 188 | TEST_SUMMARY(); | ||
| 189 | } | ||
diff --git a/tests/unit/test_mint_health_core.c b/tests/unit/test_mint_health_core.c new file mode 100644 index 0000000..9727edb --- /dev/null +++ b/tests/unit/test_mint_health_core.c | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | #include "test_framework.h" | ||
| 2 | #include "../../components/tollgate_core/src/tollgate_core_mint_health.h" | ||
| 3 | #include <string.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | |||
| 6 | int main(void) | ||
| 7 | { | ||
| 8 | printf("=== test_mint_health_core ===\n"); | ||
| 9 | |||
| 10 | printf("\n--- update: probe success ---\n"); | ||
| 11 | { | ||
| 12 | tollgate_mint_health_t state = {0}; | ||
| 13 | strncpy(state.mints[0].url, "https://test.mint", sizeof(state.mints[0].url) - 1); | ||
| 14 | state.count = 1; | ||
| 15 | |||
| 16 | tollgate_core_mint_health_update(&state, 0, true, 200, 0, 1000); | ||
| 17 | ASSERT_EQ_INT(1, state.mints[0].consecutive_successes, "1st success"); | ||
| 18 | ASSERT(!state.mints[0].reachable, "not yet reachable (threshold=3)"); | ||
| 19 | |||
| 20 | tollgate_core_mint_health_update(&state, 0, true, 200, 0, 2000); | ||
| 21 | ASSERT_EQ_INT(2, state.mints[0].consecutive_successes, "2nd success"); | ||
| 22 | ASSERT(!state.mints[0].reachable, "still not reachable"); | ||
| 23 | |||
| 24 | tollgate_core_mint_health_update(&state, 0, true, 200, 0, 3000); | ||
| 25 | ASSERT_EQ_INT(3, state.mints[0].consecutive_successes, "3rd success"); | ||
| 26 | ASSERT(state.mints[0].reachable, "now reachable after threshold"); | ||
| 27 | } | ||
| 28 | |||
| 29 | printf("\n--- update: failure resets ---\n"); | ||
| 30 | { | ||
| 31 | tollgate_mint_health_t state = {0}; | ||
| 32 | strncpy(state.mints[0].url, "https://test.mint", sizeof(state.mints[0].url) - 1); | ||
| 33 | state.count = 1; | ||
| 34 | state.mints[0].reachable = true; | ||
| 35 | state.mints[0].consecutive_successes = 5; | ||
| 36 | |||
| 37 | tollgate_core_mint_health_update(&state, 0, false, 0, -1, 1000); | ||
| 38 | ASSERT(!state.mints[0].reachable, "failure marks unreachable"); | ||
| 39 | ASSERT_EQ_INT(0, state.mints[0].consecutive_successes, "successes reset to 0"); | ||
| 40 | ASSERT_EQ_INT(-1, state.mints[0].last_err, "error code recorded"); | ||
| 41 | } | ||
| 42 | |||
| 43 | printf("\n--- update_initial: success ---\n"); | ||
| 44 | { | ||
| 45 | tollgate_mint_health_t state = {0}; | ||
| 46 | strncpy(state.mints[0].url, "https://test.mint", sizeof(state.mints[0].url) - 1); | ||
| 47 | state.count = 1; | ||
| 48 | |||
| 49 | tollgate_core_mint_health_update_initial(&state, 0, true, 200, 0, 1000); | ||
| 50 | ASSERT(state.mints[0].reachable, "immediately reachable on initial success"); | ||
| 51 | ASSERT_EQ_INT(TG_MINT_HEALTH_RECOVERY_THRESHOLD, | ||
| 52 | state.mints[0].consecutive_successes, "successes set to threshold"); | ||
| 53 | } | ||
| 54 | |||
| 55 | printf("\n--- update_initial: failure ---\n"); | ||
| 56 | { | ||
| 57 | tollgate_mint_health_t state = {0}; | ||
| 58 | strncpy(state.mints[0].url, "https://test.mint", sizeof(state.mints[0].url) - 1); | ||
| 59 | state.count = 1; | ||
| 60 | |||
| 61 | tollgate_core_mint_health_update_initial(&state, 0, false, 0, -2, 1000); | ||
| 62 | ASSERT(!state.mints[0].reachable, "not reachable on initial failure"); | ||
| 63 | ASSERT_EQ_INT(0, state.mints[0].consecutive_successes, "successes is 0"); | ||
| 64 | } | ||
| 65 | |||
| 66 | printf("\n--- is_reachable ---\n"); | ||
| 67 | { | ||
| 68 | tollgate_mint_health_t state = {0}; | ||
| 69 | strncpy(state.mints[0].url, "https://test.mint", sizeof(state.mints[0].url) - 1); | ||
| 70 | state.count = 1; | ||
| 71 | state.mints[0].reachable = true; | ||
| 72 | |||
| 73 | ASSERT(tollgate_core_mint_health_is_reachable(&state, "https://test.mint"), | ||
| 74 | "exact URL match"); | ||
| 75 | ASSERT(tollgate_core_mint_health_is_reachable(&state, "https://test.mint/v1/info"), | ||
| 76 | "substring match"); | ||
| 77 | ASSERT(!tollgate_core_mint_health_is_reachable(&state, "https://other.mint"), | ||
| 78 | "no match for other URL"); | ||
| 79 | ASSERT(!tollgate_core_mint_health_is_reachable(NULL, "https://test.mint"), | ||
| 80 | "NULL state"); | ||
| 81 | ASSERT(!tollgate_core_mint_health_is_reachable(&state, NULL), | ||
| 82 | "NULL url"); | ||
| 83 | } | ||
| 84 | |||
| 85 | printf("\n--- mark_unreachable ---\n"); | ||
| 86 | { | ||
| 87 | tollgate_mint_health_t state = {0}; | ||
| 88 | strncpy(state.mints[0].url, "https://test.mint", sizeof(state.mints[0].url) - 1); | ||
| 89 | state.count = 1; | ||
| 90 | state.mints[0].reachable = true; | ||
| 91 | state.mints[0].consecutive_successes = 5; | ||
| 92 | |||
| 93 | tollgate_core_mint_health_mark_unreachable(&state, "https://test.mint"); | ||
| 94 | ASSERT(!state.mints[0].reachable, "marked unreachable"); | ||
| 95 | ASSERT_EQ_INT(0, state.mints[0].consecutive_successes, "successes cleared"); | ||
| 96 | |||
| 97 | tollgate_core_mint_health_mark_unreachable(&state, "https://test.mint"); | ||
| 98 | ASSERT(!state.mints[0].reachable, "idempotent"); | ||
| 99 | } | ||
| 100 | |||
| 101 | printf("\n--- count_reachable ---\n"); | ||
| 102 | { | ||
| 103 | tollgate_mint_health_t state = {0}; | ||
| 104 | state.count = 3; | ||
| 105 | strncpy(state.mints[0].url, "https://a.mint", sizeof(state.mints[0].url) - 1); | ||
| 106 | strncpy(state.mints[1].url, "https://b.mint", sizeof(state.mints[1].url) - 1); | ||
| 107 | strncpy(state.mints[2].url, "https://c.mint", sizeof(state.mints[2].url) - 1); | ||
| 108 | state.mints[0].reachable = true; | ||
| 109 | state.mints[1].reachable = false; | ||
| 110 | state.mints[2].reachable = true; | ||
| 111 | |||
| 112 | ASSERT_EQ_INT(2, tollgate_core_mint_health_count_reachable(&state), | ||
| 113 | "2 out of 3 reachable"); | ||
| 114 | ASSERT_EQ_INT(0, tollgate_core_mint_health_count_reachable(NULL), | ||
| 115 | "NULL returns 0"); | ||
| 116 | } | ||
| 117 | |||
| 118 | printf("\n--- update with invalid index ---\n"); | ||
| 119 | { | ||
| 120 | tollgate_mint_health_t state = {0}; | ||
| 121 | state.count = 1; | ||
| 122 | |||
| 123 | tollgate_core_mint_health_update(&state, -1, true, 200, 0, 1000); | ||
| 124 | tollgate_core_mint_health_update(&state, 5, true, 200, 0, 1000); | ||
| 125 | tollgate_core_mint_health_update(NULL, 0, true, 200, 0, 1000); | ||
| 126 | ASSERT(true, "no crash on invalid inputs"); | ||
| 127 | } | ||
| 128 | |||
| 129 | TEST_SUMMARY(); | ||
| 130 | } | ||
diff --git a/tests/unit/test_portal.c b/tests/unit/test_portal.c new file mode 100644 index 0000000..575921e --- /dev/null +++ b/tests/unit/test_portal.c | |||
| @@ -0,0 +1,153 @@ | |||
| 1 | #include "test_framework.h" | ||
| 2 | #include "../../components/tollgate_core/src/tollgate_core_portal.h" | ||
| 3 | #include "../../components/tollgate_core/src/tollgate_core_session.h" | ||
| 4 | #include <string.h> | ||
| 5 | #include <stdio.h> | ||
| 6 | #include <stdlib.h> | ||
| 7 | |||
| 8 | int main(void) | ||
| 9 | { | ||
| 10 | printf("=== test_portal ===\n"); | ||
| 11 | |||
| 12 | printf("\n--- template_replace single key ---\n"); | ||
| 13 | { | ||
| 14 | char *result = tollgate_core_portal_template_replace( | ||
| 15 | "Hello __NAME__!", "__NAME__", "World"); | ||
| 16 | ASSERT(result != NULL, "result not NULL"); | ||
| 17 | ASSERT(strcmp(result, "Hello World!") == 0, "single substitution works"); | ||
| 18 | free(result); | ||
| 19 | } | ||
| 20 | |||
| 21 | printf("\n--- template_replace no match ---\n"); | ||
| 22 | { | ||
| 23 | char *result = tollgate_core_portal_template_replace( | ||
| 24 | "Hello World!", "__NAME__", "Test"); | ||
| 25 | ASSERT(result != NULL, "result not NULL"); | ||
| 26 | ASSERT(strcmp(result, "Hello World!") == 0, "no match returns original"); | ||
| 27 | free(result); | ||
| 28 | } | ||
| 29 | |||
| 30 | printf("\n--- template_replace multiple occurrences ---\n"); | ||
| 31 | { | ||
| 32 | char *result = tollgate_core_portal_template_replace( | ||
| 33 | "__IP__:2121 and __IP__:80", "__IP__", "10.0.0.1"); | ||
| 34 | ASSERT(result != NULL, "result not NULL"); | ||
| 35 | ASSERT(strcmp(result, "10.0.0.1:2121 and 10.0.0.1:80") == 0, | ||
| 36 | "multiple occurrences replaced"); | ||
| 37 | free(result); | ||
| 38 | } | ||
| 39 | |||
| 40 | printf("\n--- template_replace key longer than value ---\n"); | ||
| 41 | { | ||
| 42 | char *result = tollgate_core_portal_template_replace( | ||
| 43 | "A __LONGKEY__ B", "__LONGKEY__", "X"); | ||
| 44 | ASSERT(result != NULL, "result not NULL"); | ||
| 45 | ASSERT(strcmp(result, "A X B") == 0, "shrinks correctly"); | ||
| 46 | free(result); | ||
| 47 | } | ||
| 48 | |||
| 49 | printf("\n--- render multi-key substitution ---\n"); | ||
| 50 | { | ||
| 51 | tollgate_portal_sub_t subs[] = { | ||
| 52 | { "__AP_IP__", "10.0.0.1" }, | ||
| 53 | { "__PRICE__", "21" }, | ||
| 54 | { "__MINT_URL__", "https://test.mint" }, | ||
| 55 | }; | ||
| 56 | char *result = tollgate_core_portal_render( | ||
| 57 | "IP=__AP_IP__ price=__PRICE__ mint=__MINT_URL__", subs, 3); | ||
| 58 | ASSERT(result != NULL, "result not NULL"); | ||
| 59 | ASSERT(strcmp(result, "IP=10.0.0.1 price=21 mint=https://test.mint") == 0, | ||
| 60 | "multi-key render works"); | ||
| 61 | free(result); | ||
| 62 | } | ||
| 63 | |||
| 64 | printf("\n--- render with no matches ---\n"); | ||
| 65 | { | ||
| 66 | tollgate_portal_sub_t subs[] = { | ||
| 67 | { "__AP_IP__", "10.0.0.1" }, | ||
| 68 | }; | ||
| 69 | char *result = tollgate_core_portal_render("no placeholders", subs, 1); | ||
| 70 | ASSERT(result != NULL, "result not NULL"); | ||
| 71 | ASSERT(strcmp(result, "no placeholders") == 0, "no matches returns original"); | ||
| 72 | free(result); | ||
| 73 | } | ||
| 74 | |||
| 75 | printf("\n--- calc_usage time metric ---\n"); | ||
| 76 | { | ||
| 77 | tg_session_t session = {0}; | ||
| 78 | session.active = true; | ||
| 79 | session.allotment_ms = 60000; | ||
| 80 | session.start_time_ms = 10000; | ||
| 81 | |||
| 82 | int64_t remaining = 0, total = 0; | ||
| 83 | bool ok = tollgate_core_portal_calc_usage(&session, "milliseconds", 30000, &remaining, &total); | ||
| 84 | ASSERT(ok, "calc_usage returns true for active session"); | ||
| 85 | ASSERT_EQ_UINT64(40000, (unsigned long long)remaining, "remaining = 60000 - 20000"); | ||
| 86 | ASSERT_EQ_UINT64(60000, (unsigned long long)total, "total = allotment_ms"); | ||
| 87 | } | ||
| 88 | |||
| 89 | printf("\n--- calc_usage bytes metric ---\n"); | ||
| 90 | { | ||
| 91 | tg_session_t session = {0}; | ||
| 92 | session.active = true; | ||
| 93 | session.allotment_bytes = 1000000; | ||
| 94 | session.bytes_consumed = 300000; | ||
| 95 | |||
| 96 | int64_t remaining = 0, total = 0; | ||
| 97 | bool ok = tollgate_core_portal_calc_usage(&session, "bytes", 0, &remaining, &total); | ||
| 98 | ASSERT(ok, "calc_usage returns true for bytes"); | ||
| 99 | ASSERT_EQ_UINT64(700000, (unsigned long long)remaining, "remaining = 1000000 - 300000"); | ||
| 100 | ASSERT_EQ_UINT64(1000000, (unsigned long long)total, "total = allotment_bytes"); | ||
| 101 | } | ||
| 102 | |||
| 103 | printf("\n--- calc_usage expired time ---\n"); | ||
| 104 | { | ||
| 105 | tg_session_t session = {0}; | ||
| 106 | session.active = true; | ||
| 107 | session.allotment_ms = 60000; | ||
| 108 | session.start_time_ms = 0; | ||
| 109 | |||
| 110 | int64_t remaining = 0, total = 0; | ||
| 111 | tollgate_core_portal_calc_usage(&session, "milliseconds", 120000, &remaining, &total); | ||
| 112 | ASSERT_EQ_UINT64(0, (unsigned long long)remaining, "remaining clamped to 0 when expired"); | ||
| 113 | } | ||
| 114 | |||
| 115 | printf("\n--- calc_usage inactive session ---\n"); | ||
| 116 | { | ||
| 117 | tg_session_t session = {0}; | ||
| 118 | session.active = false; | ||
| 119 | |||
| 120 | int64_t remaining = 0, total = 0; | ||
| 121 | bool ok = tollgate_core_portal_calc_usage(&session, "milliseconds", 0, &remaining, &total); | ||
| 122 | ASSERT(!ok, "inactive session returns false"); | ||
| 123 | } | ||
| 124 | |||
| 125 | printf("\n--- format_usage ---\n"); | ||
| 126 | { | ||
| 127 | tg_session_t session = {0}; | ||
| 128 | session.active = true; | ||
| 129 | session.allotment_ms = 60000; | ||
| 130 | session.start_time_ms = 10000; | ||
| 131 | |||
| 132 | char buf[64]; | ||
| 133 | int len = tollgate_core_portal_format_usage(&session, "milliseconds", 30000, buf, sizeof(buf)); | ||
| 134 | ASSERT(len > 0, "format_usage returns positive length"); | ||
| 135 | ASSERT(strstr(buf, "/") != NULL, "contains separator"); | ||
| 136 | ASSERT(strstr(buf, "60000") != NULL, "contains total"); | ||
| 137 | } | ||
| 138 | |||
| 139 | printf("\n--- is_captive_uri ---\n"); | ||
| 140 | { | ||
| 141 | ASSERT(tollgate_core_portal_is_captive_uri("/generate_204"), "generate_204 is captive"); | ||
| 142 | ASSERT(tollgate_core_portal_is_captive_uri("/hotspot-detect.html"), "hotspot-detect is captive"); | ||
| 143 | ASSERT(tollgate_core_portal_is_captive_uri("/success.txt"), "success.txt is captive"); | ||
| 144 | ASSERT(tollgate_core_portal_is_captive_uri("/ncsi.txt"), "ncsi.txt is captive"); | ||
| 145 | ASSERT(tollgate_core_portal_is_captive_uri("/connecttest.txt"), "connecttest is captive"); | ||
| 146 | ASSERT(tollgate_core_portal_is_captive_uri("/wpad.dat"), "wpad.dat is captive"); | ||
| 147 | ASSERT(!tollgate_core_portal_is_captive_uri("/"), "root is not captive"); | ||
| 148 | ASSERT(!tollgate_core_portal_is_captive_uri("/setup"), "setup is not captive"); | ||
| 149 | ASSERT(!tollgate_core_portal_is_captive_uri(NULL), "NULL is not captive"); | ||
| 150 | } | ||
| 151 | |||
| 152 | TEST_SUMMARY(); | ||
| 153 | } | ||
diff --git a/tests/unit/test_stratum_client.c b/tests/unit/test_stratum_client.c new file mode 100644 index 0000000..302fcba --- /dev/null +++ b/tests/unit/test_stratum_client.c | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | #include "test_framework.h" | ||
| 2 | #include "../../components/tollgate_core/src/tollgate_core_stratum_client.h" | ||
| 3 | #include <cjson/cJSON.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include <stdio.h> | ||
| 6 | #include <stdlib.h> | ||
| 7 | |||
| 8 | int main(void) | ||
| 9 | { | ||
| 10 | printf("=== test_stratum_client ===\n"); | ||
| 11 | |||
| 12 | printf("\n--- hex_to_bytes ---\n"); | ||
| 13 | { | ||
| 14 | const char *hex = "0a1b2c3d"; | ||
| 15 | uint8_t out[4] = {0}; | ||
| 16 | tollgate_core_stratum_hex_to_bytes(hex, out, 4); | ||
| 17 | ASSERT_EQ_INT(0x0a, (int)out[0], "byte 0"); | ||
| 18 | ASSERT_EQ_INT(0x1b, (int)out[1], "byte 1"); | ||
| 19 | ASSERT_EQ_INT(0x2c, (int)out[2], "byte 2"); | ||
| 20 | ASSERT_EQ_INT(0x3d, (int)out[3], "byte 3"); | ||
| 21 | } | ||
| 22 | |||
| 23 | printf("\n--- hex_to_bytes zeros ---\n"); | ||
| 24 | { | ||
| 25 | const char *hex = "00000000"; | ||
| 26 | uint8_t out[4] = {0xff, 0xff, 0xff, 0xff}; | ||
| 27 | tollgate_core_stratum_hex_to_bytes(hex, out, 4); | ||
| 28 | ASSERT_EQ_INT(0, (int)out[0], "zero byte 0"); | ||
| 29 | ASSERT_EQ_INT(0, (int)out[1], "zero byte 1"); | ||
| 30 | } | ||
| 31 | |||
| 32 | printf("\n--- parse_notify valid ---\n"); | ||
| 33 | { | ||
| 34 | cJSON *params = cJSON_Parse("[\"123\",\"0000000000000000000000000000000000000000000000000000000000000000\"," | ||
| 35 | "\"\"" | ||
| 36 | ",\"\"" | ||
| 37 | ",\"\"" | ||
| 38 | ",\"20000000\"" | ||
| 39 | ",\"1705e3c4\"" | ||
| 40 | ",\"65a3b2c1\"]"); | ||
| 41 | tollgate_stratum_job_t job = {0}; | ||
| 42 | uint32_t nbits = 0; | ||
| 43 | bool ok = tollgate_core_stratum_parse_notify(params, &job, &nbits); | ||
| 44 | ASSERT(ok, "parse_notify returns true"); | ||
| 45 | ASSERT_EQ_INT(123, (int)job.job_id, "job_id parsed"); | ||
| 46 | ASSERT(job.valid, "job is valid"); | ||
| 47 | ASSERT_EQ_INT(0x20000000, (int)job.version, "version parsed"); | ||
| 48 | ASSERT_EQ_INT(0x1705e3c4, (int)job.nbits, "nbits parsed"); | ||
| 49 | ASSERT_EQ_INT(0x65a3b2c1, (int)job.ntime, "ntime parsed"); | ||
| 50 | ASSERT_EQ_INT(0x1705e3c4, (int)nbits, "out_nbits set"); | ||
| 51 | ASSERT_EQ_INT(32, job.target_len, "target_len is 32"); | ||
| 52 | cJSON_Delete(params); | ||
| 53 | } | ||
| 54 | |||
| 55 | printf("\n--- parse_notify too few params ---\n"); | ||
| 56 | { | ||
| 57 | cJSON *params = cJSON_Parse("[\"123\",\"abcd\"]"); | ||
| 58 | tollgate_stratum_job_t job = {0}; | ||
| 59 | bool ok = tollgate_core_stratum_parse_notify(params, &job, NULL); | ||
| 60 | ASSERT(!ok, "parse_notify returns false for insufficient params"); | ||
| 61 | cJSON_Delete(params); | ||
| 62 | } | ||
| 63 | |||
| 64 | printf("\n--- parse_notify NULL ---\n"); | ||
| 65 | { | ||
| 66 | tollgate_stratum_job_t job = {0}; | ||
| 67 | bool ok = tollgate_core_stratum_parse_notify(NULL, &job, NULL); | ||
| 68 | ASSERT(!ok, "parse_notify returns false for NULL"); | ||
| 69 | } | ||
| 70 | |||
| 71 | printf("\n--- parse_difficulty valid ---\n"); | ||
| 72 | { | ||
| 73 | cJSON *params = cJSON_Parse("[512]"); | ||
| 74 | uint64_t diff = 0; | ||
| 75 | bool ok = tollgate_core_stratum_parse_difficulty(params, &diff); | ||
| 76 | ASSERT(ok, "parse_difficulty returns true"); | ||
| 77 | ASSERT_EQ_UINT64(512, (unsigned long long)diff, "difficulty parsed"); | ||
| 78 | cJSON_Delete(params); | ||
| 79 | } | ||
| 80 | |||
| 81 | printf("\n--- parse_difficulty invalid ---\n"); | ||
| 82 | { | ||
| 83 | cJSON *params = cJSON_Parse("[]"); | ||
| 84 | uint64_t diff = 0; | ||
| 85 | bool ok = tollgate_core_stratum_parse_difficulty(params, &diff); | ||
| 86 | ASSERT(!ok, "parse_difficulty returns false for empty array"); | ||
| 87 | cJSON_Delete(params); | ||
| 88 | } | ||
| 89 | |||
| 90 | printf("\n--- build_subscribe ---\n"); | ||
| 91 | { | ||
| 92 | char buf[256]; | ||
| 93 | int len = tollgate_core_stratum_build_subscribe(buf, sizeof(buf), 1); | ||
| 94 | ASSERT(len > 0, "build_subscribe returns positive length"); | ||
| 95 | ASSERT(strstr(buf, "mining.subscribe") != NULL, "contains method"); | ||
| 96 | ASSERT(strstr(buf, "\"id\":1") != NULL, "contains id"); | ||
| 97 | ASSERT(strstr(buf, "TollGate/1.0") != NULL, "contains user agent"); | ||
| 98 | ASSERT(buf[len - 1] == '\n', "ends with newline"); | ||
| 99 | } | ||
| 100 | |||
| 101 | printf("\n--- build_authorize ---\n"); | ||
| 102 | { | ||
| 103 | char buf[512]; | ||
| 104 | int len = tollgate_core_stratum_build_authorize(buf, sizeof(buf), 2, "user1", "pass1"); | ||
| 105 | ASSERT(len > 0, "build_authorize returns positive length"); | ||
| 106 | ASSERT(strstr(buf, "mining.authorize") != NULL, "contains method"); | ||
| 107 | ASSERT(strstr(buf, "user1") != NULL, "contains user"); | ||
| 108 | ASSERT(strstr(buf, "pass1") != NULL, "contains pass"); | ||
| 109 | } | ||
| 110 | |||
| 111 | printf("\n--- build_submit ---\n"); | ||
| 112 | { | ||
| 113 | char buf[512]; | ||
| 114 | int len = tollgate_core_stratum_build_submit(buf, sizeof(buf), 3, "worker1", | ||
| 115 | 100, 0x65a3b2c1, 0x12345678, 0x20000000); | ||
| 116 | ASSERT(len > 0, "build_submit returns positive length"); | ||
| 117 | ASSERT(strstr(buf, "mining.submit") != NULL, "contains method"); | ||
| 118 | ASSERT(strstr(buf, "worker1") != NULL, "contains worker"); | ||
| 119 | ASSERT(strstr(buf, "100") != NULL, "contains job_id"); | ||
| 120 | ASSERT(strstr(buf, "65a3b2c1") != NULL, "contains ntime"); | ||
| 121 | ASSERT(strstr(buf, "12345678") != NULL, "contains nonce"); | ||
| 122 | } | ||
| 123 | |||
| 124 | TEST_SUMMARY(); | ||
| 125 | } | ||