package main import ( "bytes" "os" "path/filepath" "strings" "testing" ) // fixture is carlos logs output as it prints it: its own prefix, then the // app's JSON line. Two people in one call, a call before it, a problem // report in two parts, and a text line the summary must skip. const fixture = `2026-10-03 14:39:30 [app] calls.bds.oncarlos.com time=2026-10-03T14:39:30.000Z level=INFO msg="rastrillo: serving" 2026-10-03 14:40:00 [app] calls.bds.oncarlos.com {"time":"2026-10-03T14:40:00Z","level":"INFO","msg":"calls: quality","call":"oldcalloldcall22","peer":"zzzzzzzzzzzzzzzz","app":"web","seconds":30,"report":{"seconds":30}} 2026-10-03 14:41:00 [app] calls.bds.oncarlos.com {"time":"2026-10-03T14:41:00Z","level":"INFO","msg":"calls: quality","call":"callcallcallcall","peer":"aaaaaaaaaaaaaaaa","app":"mac","version":"0.4.9","os":"macos","osVersion":"26.0.1","final":false,"seconds":30,"report":{"seconds":30,"devices":{"input":"bluetooth","output":"built-in"},"peers":[{"peer":"bbbbbbbbbbbbbbbb","path":{"local":"srflx","remote":"relay","protocol":"udp"},"rtt":48,"in":{"audio":{"packets":1490,"lost":10,"samples":1440000,"concealed":14400},"video":{"packets":900,"lost":100,"freezes":2,"freezeSeconds":1.5}},"events":{"reconnecting":1,"reconnectingSeconds":4.2}}]}} 2026-10-03 14:41:05 [app] calls.bds.oncarlos.com {"time":"2026-10-03T14:41:05Z","level":"INFO","msg":"calls: quality","call":"callcallcallcall","peer":"bbbbbbbbbbbbbbbb","app":"web","version":"de04e2d","browser":"chrome","browserVersion":"141.0","os":"windows","osVersion":"10.0","seconds":30,"report":{"seconds":30,"peers":[{"peer":"aaaaaaaaaaaaaaaa","path":{"local":"relay","remote":"srflx","protocol":"tls"},"rtt":180,"in":{"audio":{"packets":1500,"lost":0}},"events":{"cantHearSeconds":3}}]}} 2026-10-03 14:41:30 [app] calls.bds.oncarlos.com {"time":"2026-10-03T14:41:30Z","level":"INFO","msg":"calls: quality","call":"callcallcallcall","peer":"aaaaaaaaaaaaaaaa","app":"mac","version":"0.4.9","os":"macos","osVersion":"26.0.1","final":true,"seconds":30,"report":{"seconds":30,"peers":[{"peer":"bbbbbbbbbbbbbbbb","path":{"local":"host","remote":"host","protocol":"udp"},"rtt":20}]}} 2026-10-03 14:41:20 [app] calls.bds.oncarlos.com {"time":"2026-10-03T14:41:20Z","level":"WARN","msg":"calls: problem report","ref":"K7Q2M9PD","call":"callcallcallcall","peer":"aaaaaaaaaaaaaaaa","app":"mac","version":"0.4.9","os":"macos","live":true,"note":"video froze","parts":2} 2026-10-03 14:41:20 [app] calls.bds.oncarlos.com {"time":"2026-10-03T14:41:20Z","level":"WARN","msg":"calls: problem report diagnostics","ref":"K7Q2M9PD","call":"callcallcallcall","peer":"aaaaaaaaaaaaaaaa","part":2,"of":2,"text":"second half\n"} 2026-10-03 14:41:20 [app] calls.bds.oncarlos.com {"time":"2026-10-03T14:41:20Z","level":"WARN","msg":"calls: problem report diagnostics","ref":"K7Q2M9PD","call":"callcallcallcall","peer":"aaaaaaaaaaaaaaaa","part":1,"of":2,"text":"first half, "} ` func runOn(t *testing.T, args ...string) string { t.Helper() path := filepath.Join(t.TempDir(), "logs") if err := os.WriteFile(path, []byte(fixture), 0o600); err != nil { t.Fatal(err) } f, err := os.Open(path) if err != nil { t.Fatal(err) } defer f.Close() var out bytes.Buffer if err := run(append([]string{"--zone", "Europe/Dublin"}, args...), f, &out); err != nil { t.Fatal(err) } return out.String() } func TestSummaryOfOneCall(t *testing.T) { out := runOn(t, "--at", "2026-10-03 15:41") t.Log("\n" + out) for _, want := range []string{ "Call callcallcallcall 2026-10-03 15:41:00 – 15:41:30 Europe/Dublin (30s), 2 people, 1 problem report(s)", "aaaaaa mac 0.4.9 macos 26.0.1 2 reports (input bluetooth, output built-in)", "bbbbbb web de04e2d chrome 141.0 on windows 10.0 1 reports", "aaaaaa ← bbbbbb worst loss 10.0% (video), worst RTT 48 ms, freezes 2 (1.5 s), audio concealed 1.00%, path host→host udp", "relay 50%", "bbbbbb ← aaaaaa worst loss 0.0%, worst RTT 180 ms, freezes 0 (0.0 s), path relay→srflx tls, relay 100%", `15:41:00 aaaaaa: "Reconnecting to bbbbbb…" (4.2 s)`, `15:41:05 bbbbbb: "aaaaaa can't hear you yet" (3.0 s)`, "15:41:30 aaaaaa left (final report)", `Problem K7Q2M9PD at 15:41:20 from aaaaaa (mac): "video froze"`, } { if !strings.Contains(out, want) { t.Errorf("missing %q", want) } } if strings.Contains(out, "oldcall") { t.Error("--at showed a call that had ended by then") } } func TestSummaryByCallTagAndAProblemReport(t *testing.T) { if out := runOn(t, "--call", "oldcalloldcall22"); !strings.Contains(out, "Call oldcalloldcall22") || strings.Contains(out, "callcallcallcall") { t.Fatalf("--call:\n%s", out) } out := runOn(t, "--problem", "k7q2m9pd") if !strings.Contains(out, "note: video froze") || !strings.Contains(out, "first half, second half") { t.Fatalf("--problem:\n%s", out) } }