Files
meshcore-analyzer/cmd/server/hop_context_bench_test.go
Kpa-clawbot 2beeb2b324 fix(#1199): 6 deferred quality items from PR #1198 r2 review (#1200)
Red commit: 75563ce (CI run: pending — pushed at branch open)

Follows up PR #1198 round-2 adversarial review (issue #1199). Six
robustness / perf-hot-path / maintenance items, one commit per logical
change. Stacked on top of `fix/issue-1197` (PR #1198) — base must move
to `master` after #1198 merges.

| # | Item | Commit(s) | Discipline |
|---|---|---|---|
| 1 | Brittle static-grep regex → go/parser AST walk in
`resolve_context_callsites_test.go` | 33d80b6 (RED) → 450236d (GREEN) |
red→green |
| 2 | `computeAnalyticsTopology` double-pass filter → materialize
`filteredTxs` once | 00005f6 | refactor |
| 3 | `BenchmarkBuildAggregateHopContextPubkeys` baseline + tiny smoke
test | b520048 | net-new bench/test |
| 4 | `hopResolverPerTx` CONCURRENCY doc — single-goroutine invariant |
155ff07 | doc-only |
| 5 | `schemaDegradationLogged` package-level `sync.Map` → PacketStore
field | 75563ce (RED) → 7dbf193 (GREEN) | red→green |
| 6 | `buildHopContextPubkeys` `out` slice cap hint (`make([]string, 0,
16)`) | 2040962 | refactor |

Items 2 & 6 are pure refactors — no test files modified for items 2 & 6
(per AGENTS.md exemption rule). Existing tests stay green and unaltered.

Item 4 is doc-only (CONCURRENCY: comment); no behavior change.

Item 3 adds a bench + a smoke assertion for the aggregate helper that
previously had no coverage. Local arm64 baseline: ~72ms/op, 130k allocs
at 5k txs.

Items 1 & 5 follow red→green: 33d80b6 demonstrates the regex blindspot
via a synthetic AST-detectable input the regex misses; 75563ce
demonstrates per-store log dedup leaks across instances. Both flips
visible in branch history.

Full `go test ./cmd/server/...` runs clean post-amend.

Fixes #1199

---------

Co-authored-by: openclaw-bot <bot@openclaw.local>
2026-05-15 16:21:14 +00:00

143 lines
4.6 KiB
Go

package main
import (
"encoding/json"
"fmt"
"testing"
)
// BenchmarkBuildHopContextPubkeys exercises the hot per-tx context builder
// at a realistic shape: ~50 nodes (mixed role), 6-hop path, sender + observer
// pubkey populated. Required by AGENTS.md hot-path benchmark rule (#1197 r1
// carmack #6).
func BenchmarkBuildHopContextPubkeys(b *testing.B) {
nodes := make([]nodeInfo, 0, 64)
for i := 0; i < 50; i++ {
nodes = append(nodes, nodeInfo{
PublicKey: fmt.Sprintf("%012x", i*0x101010101),
Role: "repeater",
Name: fmt.Sprintf("N%d", i),
ObservationCount: i * 3,
Lat: 37.0 + float64(i)*0.01,
Lon: -122.0 - float64(i)*0.01,
HasGPS: true,
})
}
pm := buildPrefixMap(nodes)
hops := []string{
nodes[1].PublicKey[:6], nodes[3].PublicKey[:6], nodes[5].PublicKey[:6],
nodes[7].PublicKey[:6], nodes[9].PublicKey[:6], nodes[11].PublicKey[:6],
}
pathJSON, _ := json.Marshal(hops)
decoded, _ := json.Marshal(map[string]interface{}{"pubKey": "cc4444444444"})
tx := &StoreTx{
PathJSON: string(pathJSON),
DecodedJSON: string(decoded),
ObserverID: "dd5555555555",
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = buildHopContextPubkeys(tx, pm)
}
}
// BenchmarkBuildAggregateHopContextPubkeys exercises the aggregate context
// builder at the hot scale called out by #1197 (subpath/topology bulk
// aggregations): ~5k txs sharing a node pool of ~50 prefixes. The aggregate
// builder unions per-tx contexts with its own dedupe map; this benchmark
// gives us a baseline so a future regression (e.g. accidental O(n²) dedupe)
// shows up immediately. No assertion threshold yet — see #1199 item 3.
func BenchmarkBuildAggregateHopContextPubkeys(b *testing.B) {
const numNodes = 50
const numTxs = 5000
nodes := make([]nodeInfo, 0, numNodes)
for i := 0; i < numNodes; i++ {
nodes = append(nodes, nodeInfo{
PublicKey: fmt.Sprintf("%012x", i*0x101010101),
Role: "repeater",
Name: fmt.Sprintf("N%d", i),
ObservationCount: i * 3,
Lat: 37.0 + float64(i)*0.01,
Lon: -122.0 - float64(i)*0.01,
HasGPS: true,
})
}
pm := buildPrefixMap(nodes)
txs := make([]*StoreTx, 0, numTxs)
for i := 0; i < numTxs; i++ {
hops := []string{
nodes[(i+1)%numNodes].PublicKey[:6],
nodes[(i+3)%numNodes].PublicKey[:6],
nodes[(i+5)%numNodes].PublicKey[:6],
nodes[(i+7)%numNodes].PublicKey[:6],
nodes[(i+9)%numNodes].PublicKey[:6],
nodes[(i+11)%numNodes].PublicKey[:6],
}
pathJSON, _ := json.Marshal(hops)
decoded, _ := json.Marshal(map[string]interface{}{
"pubKey": fmt.Sprintf("cc%010x", i),
})
txs = append(txs, &StoreTx{
PathJSON: string(pathJSON),
DecodedJSON: string(decoded),
ObserverID: fmt.Sprintf("dd%010x", i%32),
})
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = buildAggregateHopContextPubkeys(txs, pm)
}
}
// TestBuildAggregateHopContextPubkeysSmoke is a tiny correctness anchor for
// the aggregate helper: union over per-tx contexts, deduped. Lives next to
// the benchmark so the file ships an assertion (preflight gate). See #1199
// item 3.
func TestBuildAggregateHopContextPubkeysSmoke(t *testing.T) {
pm := buildPrefixMap([]nodeInfo{{PublicKey: "aabbccddeeff"}})
d1, _ := json.Marshal(map[string]interface{}{"pubKey": "1111111111"})
d2, _ := json.Marshal(map[string]interface{}{"pubKey": "2222222222"})
d3, _ := json.Marshal(map[string]interface{}{"pubKey": "1111111111"}) // dup
txs := []*StoreTx{
{DecodedJSON: string(d1)},
{DecodedJSON: string(d2)},
{DecodedJSON: string(d3)},
}
got := buildAggregateHopContextPubkeys(txs, pm)
if len(got) != 2 {
t.Fatalf("expected 2 deduped pubkeys, got %d (%v)", len(got), got)
}
// Content assertion — proves dedup actually keeps the right pubkeys
// (not just any 2). Without this the test would pass even if dedup
// returned, e.g., one pubkey twice or two unrelated pubkeys. See
// #1199 r1 review (adv #1).
wantSet := map[string]bool{"1111111111": true, "2222222222": true}
gotSet := map[string]bool{}
for _, pk := range got {
gotSet[pk] = true
}
for pk := range wantSet {
if !gotSet[pk] {
t.Fatalf("expected pubkey %q in deduped result, got %v", pk, got)
}
}
for pk := range gotSet {
if !wantSet[pk] {
t.Fatalf("unexpected pubkey %q in deduped result, got %v", pk, got)
}
}
if buildAggregateHopContextPubkeys(nil, pm) != nil {
t.Fatalf("nil tx slice must yield nil")
}
if buildAggregateHopContextPubkeys(txs, nil) != nil {
t.Fatalf("nil prefix map must yield nil")
}
}