carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package applog
2
3import (
4 "encoding/json"
5 "strings"
6 "testing"
7 "time"
8)
9
10// TestRecordWireShapeIsAdditive pins the wire contract: every field but ts
11// and msg is omitempty, and a record written by a future revision with keys
12// this one has never heard of still parses. Live chunks exist in production
13// buckets from the moment this ships — anything written before a change
14// must still parse (AGENTS.md wire-shape rule).
15func TestRecordWireShapeIsAdditive(t *testing.T) {
16 r := Record{
17 TS: time.Date(2026, 8, 10, 14, 3, 11, 482913000, time.UTC),
18 Msg: "hello",
19 }
20 b, err := json.Marshal(r)
21 if err != nil {
22 t.Fatal(err)
23 }
24 for _, absent := range []string{"box", "host", "stream", "level", "fields", "seq"} {
25 if strings.Contains(string(b), `"`+absent+`"`) {
26 t.Errorf("zero-valued %q should be omitted from the wire: %s", absent, b)
27 }
28 }
29
30 // A future record with unknown keys parses; known keys land.
31 future := `{"ts":"2026-08-10T14:03:11.482913Z","msg":"m","stream":"app",` +
32 `"seq":41822,"box":"b1","host":"h","level":"error",` +
33 `"fields":{"k":"v"},"shiny_new_thing":{"deep":true}}`
34 var got Record
35 if err := json.Unmarshal([]byte(future), &got); err != nil {
36 t.Fatalf("future record must parse: %v", err)
37 }
38 if got.Seq != 41822 || got.Stream != StreamApp || got.Fields["k"] != "v" {
39 t.Fatalf("known fields lost in additive parse: %+v", got)
40 }
41}
42
43// TestParseAppLine covers the JSON-line contract: a top-level JSON object
44// yields fields from its scalar values, msg from msg/message, level only
45// from a recognized value — and anything else is opaque text, untouched.
46func TestParseAppLine(t *testing.T) {
47 cases := []struct {
48 name, line string
49 wantMsg, wantLevel string
50 wantFields map[string]string
51 }{
52 {"plain text", "listening on :8080", "listening on :8080", "", nil},
53 {"non-object json", `[1,2,3]`, `[1,2,3]`, "", nil},
54 {
55 "structured",
56 `{"level":"ERROR","msg":"boom","request_id":"a1b2","n":7,"ok":true}`,
57 "boom", "error",
58 map[string]string{"request_id": "a1b2", "n": "7", "ok": "true"},
59 },
60 {
61 "message key and unknown level",
62 `{"level":"shouting","message":"hi"}`,
63 "hi", "",
64 // An unrecognized level is DATA, not a level — it must survive
65 // as a field rather than be guessed at or dropped.
66 map[string]string{"level": "shouting"},
67 },
68 {
69 "nested values are not flattened",
70 `{"msg":"m","deep":{"a":1}}`,
71 "m", "", nil,
72 },
73 {"empty line", "", "", "", nil},
74 }
75 for _, tc := range cases {
76 t.Run(tc.name, func(t *testing.T) {
77 msg, level, fields := ParseAppLine(tc.line)
78 if msg != tc.wantMsg || level != tc.wantLevel {
79 t.Fatalf("msg=%q level=%q, want %q/%q", msg, level, tc.wantMsg, tc.wantLevel)
80 }
81 if len(fields) != len(tc.wantFields) {
82 t.Fatalf("fields=%v, want %v", fields, tc.wantFields)
83 }
84 for k, v := range tc.wantFields {
85 if fields[k] != v {
86 t.Fatalf("fields[%q]=%q, want %q", k, fields[k], v)
87 }
88 }
89 })
90 }
91}
92
93// TestLineWriter: the tee's writer half splits on \n, caps line length with
94// an explicit truncation marker, and flushes a trailing partial on Close —
95// output bytes are never reordered or dropped silently.
96func TestLineWriter(t *testing.T) {
97 var got []string
98 w := NewLineWriter(16, func(line string) { got = append(got, line) })
99
100 // Split across writes; only complete lines emit.
101 w.Write([]byte("hel"))
102 w.Write([]byte("lo\nwor"))
103 if len(got) != 1 || got[0] != "hello" {
104 t.Fatalf("after partial writes got %q", got)
105 }
106 // An over-long line is truncated once, marked, and the tail discarded —
107 // not emitted as a phantom second line.
108 w.Write([]byte("ldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-tail\nnext\n"))
109 if len(got) != 3 {
110 t.Fatalf("got %q", got)
111 }
112 if !strings.HasSuffix(got[1], "…(truncated)") || len(got[1]) > 16+len("…(truncated)") {
113 t.Fatalf("long line not truncated with marker: %q", got[1])
114 }
115 if got[2] != "next" {
116 t.Fatalf("line after a truncated one corrupted: %q", got[2])
117 }
118 // Close flushes the partial.
119 w.Write([]byte("no newline"))
120 w.Close()
121 if got[len(got)-1] != "no newline" {
122 t.Fatalf("Close did not flush the partial: %q", got)
123 }
124 // Empty lines are dropped (a trailing \n on every Printf would
125 // otherwise ship a blank record each time).
126 got = nil
127 w2 := NewLineWriter(16, func(line string) { got = append(got, line) })
128 w2.Write([]byte("\n\n"))
129 w2.Close()
130 if len(got) != 0 {
131 t.Fatalf("blank lines shipped: %q", got)
132 }
133}
134