upleb.uk

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

summaryrefslogtreecommitdiff
path: root/tests/integration/test-market.mjs
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-19 13:14:48 +0530
committerYour Name <you@example.com>2026-05-19 13:14:48 +0530
commitfe6aa9663d4cdabdc6e71db6068f8cd9e3739ffe (patch)
tree8cadb07243c07a6b3fa9453b239c9ac5cb02b454 /tests/integration/test-market.mjs
parent77031f06a9a87320d011f501590985161d1eb305 (diff)
feat: WiFi beacon price discovery via Vendor IE (two-board verified)
Price discovery allows TollGate ESP32 boards to advertise their per-step price via WiFi Vendor-Specific Information Elements (OUI 0xC0FFEE) in beacon and probe response frames. Nearby boards passively scan and build a market view of competing TollGates without requiring internet access. Features: - beacon_price.c/h: 26-byte packed Vendor IE payload (price, step, metric, mint_hash, geohash, npub_hash), injected via esp_wifi_set_vendor_ie() - market.c/h: Passive WiFi scan receiver, vendor IE callback parsing, BSSID-correlated market entries, effective price ranking - GET /market API endpoint: JSON market snapshot with discovered entries - AP-only services: beacon + market + API start on WIFI_EVENT_AP_START, independent of STA connectivity - STA reconnect fix: 2s delay between retries creates scan windows; s_sta_connecting guard prevents double-connect - write-config-ap-only-a/b Makefile targets for STA-less testing - market_tick() in main loop, client price comparison logging Hardware verified: both boards discover each other via Vendor IE beacons. Board A sees TollGate-C0E9CA (RSSI=-30), Board B sees TollGate-B96D80 (RSSI=-25). test-market.mjs: 9/9, test-price-discovery.mjs: 7/7 per board. Unit tests: 45 new assertions across test_beacon_price (28) and test_market (17). All 15 test suites pass. ESP-IDF build clean for ESP32-S3.
Diffstat (limited to 'tests/integration/test-market.mjs')
-rw-r--r--tests/integration/test-market.mjs60
1 files changed, 60 insertions, 0 deletions
diff --git a/tests/integration/test-market.mjs b/tests/integration/test-market.mjs
new file mode 100644
index 0000000..20f062f
--- /dev/null
+++ b/tests/integration/test-market.mjs
@@ -0,0 +1,60 @@
1import { execSync } from 'child_process';
2
3const API_URL = `http://${process.env.TOLLGATE_IP || '10.192.45.1'}:2121`;
4
5function run(cmd) {
6 try { return execSync(cmd, { encoding: 'utf8', timeout: 15000 }); }
7 catch (e) { return e.stdout || null; }
8}
9
10function runJson(cmd) {
11 const out = run(cmd);
12 try { return out ? JSON.parse(out) : null; }
13 catch { return null; }
14}
15
16let passed = 0, failed = 0;
17function assert(cond, msg) {
18 if (cond) { console.log(` PASS: ${msg}`); passed++; }
19 else { console.log(` FAIL: ${msg}`); failed++; }
20}
21
22console.log('=== test-market (GET /market) ===\n');
23
24console.log('--- /market endpoint responds ---');
25{
26 const data = runJson(`curl -s --connect-timeout 5 ${API_URL}/market`);
27 assert(data !== null, '/market returns valid JSON');
28 assert(typeof data.count === 'number', `count is number (got ${data?.count})`);
29 assert(Array.isArray(data.entries), 'entries is array');
30}
31
32console.log('\n--- /market entry structure ---');
33{
34 const data = runJson(`curl -s --connect-timeout 5 ${API_URL}/market`);
35 if (data && data.entries && data.entries.length > 0) {
36 const e = data.entries[0];
37 assert(typeof e.bssid === 'string', `bssid is string (got ${e.bssid})`);
38 assert(typeof e.ssid === 'string', `ssid is string (got ${e.ssid})`);
39 assert(typeof e.rssi === 'number', `rssi is number (got ${e.rssi})`);
40 assert(typeof e.price_per_step === 'number', `price_per_step is number (got ${e.price_per_step})`);
41 assert(typeof e.step_size === 'number', `step_size is number (got ${e.step_size})`);
42 assert(typeof e.metric === 'string', `metric is string (got ${e.metric})`);
43 } else {
44 console.log(' SKIP: no entries found (scan may not have run yet)');
45 }
46}
47
48console.log('\n--- /market with no discovered TollGates ---');
49{
50 const data = runJson(`curl -s --connect-timeout 5 ${API_URL}/market`);
51 if (data && data.count === 0) {
52 assert(data.entries.length === 0, 'empty entries array when count=0');
53 console.log(' INFO: no nearby TollGates discovered yet (expected if only one board)');
54 } else if (data && data.count > 0) {
55 console.log(` INFO: ${data.count} nearby TollGate(s) discovered`);
56 }
57}
58
59console.log(`\n=== Results: ${passed} passed, ${failed} failed ===`);
60process.exit(failed > 0 ? 1 : 0);