nx_linkqual_test.nx source
↩ module page · 81 lines · 4287 B
1// nx_linkqual_test.nx -- 1:1 KAT for the real-time link-quality substrate
2// (nx_linkqual.nx). Deterministic: feed scripted sample events, assert
3// EXACT metric values (hand-computed from the RFC math), then assert each
4// product consumer's decision (game input-delay frames, video jitter
5// buffer, streaming bitrate, easy-for-anyone score/verdict).
6//
7// expect_exit: 0
8// license_tier: ORIGINAL
9
10import "nx_linkqual.nx"
11
12func main() -> i64 {
13 // ---- T1: RTT (RFC 6298) exact ----
14 let f: *LinkFlow = lq_flow_new()
15 lq_on_rtt(f, 100)
16 if lq_srtt_ms(f) != 100 { return 1 } // first sample seeds SRTT=R
17 if lq_rttvar_ms(f) != 50 { return 2 } // RTTVAR=R/2
18 lq_on_rtt(f, 120)
19 if lq_srtt_ms(f) != 102 { return 3 } // 100 + 20/8
20 if lq_rttvar_ms(f) != 42 { return 4 } // 50 + (20-50)/4
21
22 // ---- T2: jitter (RFC 3550 A.8) exact ----
23 let g: *LinkFlow = lq_flow_new()
24 lq_on_arrival(g, 0, 10) // first -> seed transit, jitter 0
25 lq_on_arrival(g, 10, 20) // constant transit -> D=0 -> jitter 0
26 if lq_jitter_ms(g) != 0 { return 5 }
27 lq_on_arrival(g, 20, 50) // transit 10->30, D=20 -> jitter 20/16=1
28 if lq_jitter_ms(g) != 1 { return 6 }
29
30 // ---- T3: loss fraction (RFC 3550 A.3) exact ----
31 let h: *LinkFlow = lq_flow_new()
32 lq_on_seq(h, 0); lq_on_seq(h, 1); lq_on_seq(h, 2); lq_on_seq(h, 3); lq_on_seq(h, 4)
33 lq_loss_tick(h)
34 if lq_loss_pct(h) != 0 { return 7 } // 5 expected, 5 received -> 0%
35 lq_on_seq(h, 7); lq_on_seq(h, 8); lq_on_seq(h, 9) // dropped 5,6
36 lq_loss_tick(h)
37 if lq_loss_pct(h) != 40 { return 8 } // 5 expected, 3 received -> 2/5 = 40%
38
39 // ---- T4: quantiles + max (HDR buckets) ----
40 let q: *LinkFlow = lq_flow_new()
41 lq_record_latency(q, 10); lq_record_latency(q, 10); lq_record_latency(q, 10)
42 lq_record_latency(q, 10); lq_record_latency(q, 100)
43 if q.max_latency_ms != 100 { return 9 }
44 if lq_quantile_ms(q, 50) != 16 { return 10 } // bucket_of(10)=3 -> edge 2^4
45 if lq_quantile_ms(q, 95) != 128 { return 11 } // outlier in bucket_of(100)=6 -> edge 2^7
46
47 // ---- T5: GOOD flow -> EXCELLENT + low delay/buffer + bitrate UP ----
48 let good: *LinkFlow = lq_flow_new()
49 lq_on_rtt(good, 20) // srtt 20
50 lq_record_latency(good, 20); lq_record_latency(good, 20); lq_record_latency(good, 20)
51 if lq_score(good) < 80 { return 12 }
52 if lq_verdict_band(lq_score(good)) != LQ_EXCELLENT { return 13 }
53 let ga: *GameAdvice = sys_mmap(LQ_GAME_ADVICE_BYTES) as *GameAdvice
54 lq_game_advise(good, 60, ga)
55 if ga.delay_frames > 2 { return 14 } // ~1 frame
56 if lq_jitter_buffer_ms(good) > 40 { return 15 }
57 if lq_bitrate_decision(good) != 1 { return 16 } // clean -> raise
58
59 // ---- T6: BAD flow -> POOR + clamped delay + big buffer + bitrate DOWN ----
60 let bad: *LinkFlow = lq_flow_new()
61 bad.srtt_x8 = 300 << LQ_SRTT_SH // srtt 300ms
62 bad.jitter_x16 = 30 << LQ_JIT_SH // jitter 30ms
63 bad.loss_frac_q16 = 6554 // 10% (rounds: (6554*100+32768)>>16)
64 lq_record_latency(bad, 600)
65 if lq_loss_pct(bad) != 10 { return 17 }
66 if lq_score(bad) != 0 { return 18 } // 100-40-30-40 -> clamped 0
67 if lq_verdict_band(lq_score(bad)) != LQ_POOR { return 19 }
68 lq_game_advise(bad, 60, ga)
69 if ga.delay_frames != 9 { return 20 } // (150+60)ms*60fps -> 13 -> clamp 9
70 if lq_jitter_buffer_ms(bad) != 190 { return 21 } // 20 + 30*4 + 10*5
71 if lq_bitrate_decision(bad) != (0 - 1) { return 22 } // loss>=5% -> lower
72
73 sys_write(1, "T1-T6 link-quality core+consumers OK (RTT/jitter/loss/quantile exact; game/video/stream decisions)\n", 99)
74
75 // ---- render the easy-for-anyone quality cards (one per product) ----
76 sys_write(1, "\n=== GOOD link ===\n", 19); lq_render(good, LQ_PROD_GAME); lq_render(good, LQ_PROD_VIDEO); lq_render(good, LQ_PROD_STREAM)
77 sys_write(1, "\n=== BAD link ===\n", 18); lq_render(bad, LQ_PROD_GAME); lq_render(bad, LQ_PROD_VIDEO); lq_render(bad, LQ_PROD_STREAM)
78
79 sys_write(1, "\nLINKQUAL KAT PASS (one sovereign metrics core -> games + video rooms + streaming, easy-for-anyone)\n", 99)
80 return 0
81}