93 lines
3.4 KiB
Go
93 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRunMergeComputesArrivalAndPersistenceGate(t *testing.T) {
|
|
dir := t.TempDir()
|
|
a := AgentSummary{RunID: "run1", Scenario: "p2p", Machine: "a", ReadyConnections: 1000,
|
|
ExpectedConnections: 1000,
|
|
PublishAttempted: 10, PublishAccepted: 10, ExpectedPeer: 10, ReceivedPeer: 9,
|
|
RealtimeLost: 1, HistoryChecked: 10, HistoryFound: 10}
|
|
b := AgentSummary{RunID: "run1", Scenario: "p2p", Machine: "b", ReadyConnections: 1000,
|
|
ExpectedConnections: 1000,
|
|
PublishAttempted: 10, PublishAccepted: 10, ExpectedPeer: 10, ReceivedPeer: 10,
|
|
HistoryChecked: 10, HistoryFound: 9, PersistenceLost: 1, OutOfOrder: 1,
|
|
OrderingViolations: []OrderingViolation{{ReceiverMachine: "b", ReceiverIndex: 7, PreviousSeq: 12, CurrentSeq: 11}}}
|
|
aPath, bPath, reportPath := filepath.Join(dir, "a.json"), filepath.Join(dir, "b.json"), filepath.Join(dir, "report.json")
|
|
writeSummaryForTest(t, aPath, a)
|
|
writeSummaryForTest(t, bPath, b)
|
|
if err := runMerge(aPath, bPath, reportPath); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var report CombinedReport
|
|
raw, err := os.ReadFile(reportPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = json.Unmarshal(raw, &report); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if report.ExpectedDeliveries != 20 || report.ReceivedDeliveries != 19 || report.ArrivalRate != 0.95 || report.LossRate != 0.05 {
|
|
t.Fatalf("unexpected delivery totals: %+v", report)
|
|
}
|
|
if report.Passed || report.PersistenceLost != 1 {
|
|
t.Fatalf("correctness gate did not fail: %+v", report)
|
|
}
|
|
if len(report.OrderingViolations) != 1 || report.OrderingViolations[0].ReceiverIndex != 7 {
|
|
t.Fatalf("ordering violations were not merged: %+v", report.OrderingViolations)
|
|
}
|
|
}
|
|
|
|
func TestMergedHistogramP95(t *testing.T) {
|
|
agents := []AgentSummary{
|
|
{AckLatency: HistogramSnapshot{Count: 10, MaxMS: 900, Buckets: map[string]int64{"200ms": 9, "1s": 1}}},
|
|
{AckLatency: HistogramSnapshot{Count: 10, MaxMS: 300, Buckets: map[string]int64{"200ms": 10}}},
|
|
}
|
|
if got := mergedHistogramP95(agents, func(summary AgentSummary) HistogramSnapshot { return summary.AckLatency }); got != 200 {
|
|
t.Fatalf("p95=%v", got)
|
|
}
|
|
}
|
|
|
|
func TestMergedAckP95UsesExactAcceptedTimestamps(t *testing.T) {
|
|
base := time.Date(2026, 9, 27, 8, 0, 0, 0, time.UTC)
|
|
agents := []AgentSummary{{
|
|
AckLatency: HistogramSnapshot{Count: 4, MaxMS: 900, Buckets: map[string]int64{"1s": 4}},
|
|
AcceptedLocal: []AcceptedMessage{
|
|
{SentAt: base, AckAt: base.Add(100 * time.Millisecond)},
|
|
{SentAt: base, AckAt: base.Add(200 * time.Millisecond)},
|
|
{SentAt: base, AckAt: base.Add(300 * time.Millisecond)},
|
|
{SentAt: base, AckAt: base.Add(400 * time.Millisecond)},
|
|
},
|
|
}}
|
|
if got := mergedAckP95(agents); got != 400 {
|
|
t.Fatalf("exact p95=%v want=400", got)
|
|
}
|
|
}
|
|
|
|
func TestMergedAckP95FallsBackWhenRawSamplesAreIncomplete(t *testing.T) {
|
|
agents := []AgentSummary{{
|
|
AckLatency: HistogramSnapshot{Count: 2, MaxMS: 900, Buckets: map[string]int64{"1s": 2}},
|
|
AcceptedLocal: []AcceptedMessage{{SentAt: time.Now(), AckAt: time.Now().Add(100 * time.Millisecond)}},
|
|
}}
|
|
if got := mergedAckP95(agents); got != 1000 {
|
|
t.Fatalf("fallback p95=%v want=1000", got)
|
|
}
|
|
}
|
|
|
|
func writeSummaryForTest(t *testing.T, path string, summary AgentSummary) {
|
|
t.Helper()
|
|
raw, err := json.Marshal(summary)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = os.WriteFile(path, raw, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|