snapshot of 962fc3c82c774ab371e3fc4e84c55ef26e61268d Annotations about the code that implements koment.

schema/v1alpha/annotation_schema_test.go

1 package schema_test
2
3 import (
4 _ "embed"
5 "encoding/json"
6 "os"
7 "path/filepath"
8 "testing"
9
10 "github.com/google/jsonschema-go/jsonschema"
11 yaml "go.yaml.in/yaml/v3"
12 )
13
14 //go:embed annotation.schema.json
15 var annotationSchema []byte
16
17 const validRecord = `{
18 "apiVersion": "koment.dev/v1alpha",
19 "kind": "Annotation",
20 "metadata": {
21 "id": "01JQ8ZK3M4N5P6R7S8T9V0W1X2",
22 "created": "2026-08-03T09:15:00Z"
23 },
24 "spec": {
25 "target": {
26 "file": "internal/session/token.go"
27 },
28 "type": "invariant",
29 "body": "Keep the prior key through the rotation window.",
30 "anchor": {
31 "scope": "excerpt",
32 "excerpt": "if token.Expired(now) {"
33 },
34 "author": {
35 "name": "Fixture Author",
36 "kind": "human",
37 "source": "explicit"
38 }
39 },
40 "status": {
41 "lastSeenLine": 42
42 }
43 }`
44
45 func resolveAnnotationSchema(t *testing.T) *jsonschema.Resolved {
46 t.Helper()
47 var schema jsonschema.Schema
48 if err := json.Unmarshal(annotationSchema, &schema); err != nil {
49 t.Fatalf("decode schema: %v", err)
50 }
51 resolved, err := schema.Resolve(nil)
52 if err != nil {
53 t.Fatalf("resolve schema: %v", err)
54 }
55 return resolved
56 }
57
58 func decodeRecord(t *testing.T, record string) map[string]any {
59 t.Helper()
60 var decoded map[string]any
61 if err := json.Unmarshal([]byte(record), &decoded); err != nil {
62 t.Fatalf("decode record: %v", err)
63 }
64 return decoded
65 }
66
67 func specOf(record map[string]any) map[string]any {
68 spec, _ := record["spec"].(map[string]any)
69 return spec
70 }
71
72 func TestAnnotationSchemaAcceptsTheCurrentShape(t *testing.T) {
73 if err := resolveAnnotationSchema(t).Validate(decodeRecord(t, validRecord)); err != nil {
74 t.Fatalf("validate record: %v", err)
75 }
76 }
77
78 func TestAnnotationSchemaAcceptsAPersistedObservation(t *testing.T) {
79 record := decodeRecord(t, validRecord)
80 record["status"] = map[string]any{
81 "lastSeenLine": float64(42),
82 "resolution": "ok",
83 "resolvedAt": "2026-08-05T11:00:00Z",
84 "resolvedCommit": "0123456789abcdef0123456789abcdef01234567",
85 }
86 if err := resolveAnnotationSchema(t).Validate(record); err != nil {
87 t.Fatalf("validate observation: %v", err)
88 }
89 }
90
91 func TestAnnotationSchemaAcceptsAFileScopedRecordWithNoObservedLine(t *testing.T) {
92 record := decodeRecord(t, validRecord)
93 specOf(record)["anchor"] = map[string]any{"scope": "file"}
94 record["status"] = map[string]any{
95 "resolution": "ok",
96 "resolvedAt": "2026-08-05T11:00:00Z",
97 "resolvedCommit": "0123456789abcdef0123456789abcdef01234567",
98 }
99 if err := resolveAnnotationSchema(t).Validate(record); err != nil {
100 t.Fatalf("validate file-scoped record: %v", err)
101 }
102
103 delete(record, "status")
104 if err := resolveAnnotationSchema(t).Validate(record); err != nil {
105 t.Fatalf("validate file-scoped record with no status at all: %v", err)
106 }
107 }
108
109 func TestEveryCommittedAnnotationMatchesThePublishedSchema(t *testing.T) {
110 resolved := resolveAnnotationSchema(t)
111 patterns := []string{
112 filepath.Join("..", "..", ".koment", "annotations", "*.yaml"),
113 filepath.Join("..", "..", "workspace", ".koment", "annotations", "*.yaml"),
114 }
115 total := 0
116 for _, pattern := range patterns {
117 paths, err := filepath.Glob(pattern)
118 if err != nil {
119 t.Fatal(err)
120 }
121 for _, path := range paths {
122 total++
123 content, err := os.ReadFile(path)
124 if err != nil {
125 t.Fatal(err)
126 }
127 var yamlRecord any
128 if err := yaml.Unmarshal(content, &yamlRecord); err != nil {
129 t.Fatalf("decode %s: %v", path, err)
130 }
131 encoded, err := json.Marshal(yamlRecord)
132 if err != nil {
133 t.Fatalf("convert %s to JSON: %v", path, err)
134 }
135 var record map[string]any
136 if err := json.Unmarshal(encoded, &record); err != nil {
137 t.Fatalf("decode converted %s: %v", path, err)
138 }
139 if err := resolved.Validate(record); err != nil {
140 t.Errorf("%s: %v", path, err)
141 }
142 }
143 }
144 if total == 0 {
145 t.Fatal("no committed annotations were validated")
146 }
147 }
148
149 func TestAnnotationSchemaAcceptsInlineCommentAcknowledgement(t *testing.T) {
150 record := decodeRecord(t, validRecord)
151 spec := specOf(record)
152 spec["type"] = "why"
153 spec["policy"] = map[string]any{
154 "exception": "inline-comment",
155 "acknowledged": true,
156 }
157 if err := resolveAnnotationSchema(t).Validate(record); err != nil {
158 t.Fatalf("validate acknowledgement: %v", err)
159 }
160 }
161
162 func TestAnnotationSchemaRejectsUnsupportedRecords(t *testing.T) {
163 resolved := resolveAnnotationSchema(t)
164 for _, test := range []struct {
165 name string
166 mutate func(map[string]any)
167 }{
168 {"the retired version field", func(record map[string]any) { record["version"] = float64(1) }},
169 {"a later api version", func(record map[string]any) { record["apiVersion"] = "koment.dev/v1" }},
170 {"another resource kind", func(record map[string]any) { record["kind"] = "Rationale" }},
171 {"unknown field", func(record map[string]any) { record["legacy"] = true }},
172 {"unknown spec field", func(record map[string]any) { specOf(record)["confidence"] = "high" }},
173 {"a bare file outside target", func(record map[string]any) {
174 specOf(record)["file"] = "internal/session/token.go"
175 }},
176 {"a date instead of an instant", func(record map[string]any) {
177 record["metadata"] = map[string]any{"id": "01JQ8ZK3M4N5P6R7S8T9V0W1X2", "created": "2026-08-03"}
178 }},
179 {"absolute path", func(record map[string]any) {
180 specOf(record)["target"] = map[string]any{"file": "/etc/passwd"}
181 }},
182 {"noncanonical path", func(record map[string]any) {
183 specOf(record)["target"] = map[string]any{"file": "./main.go"}
184 }},
185 {"backslash path", func(record map[string]any) {
186 specOf(record)["target"] = map[string]any{"file": `internal\main.go`}
187 }},
188 {"drive-relative path", func(record map[string]any) {
189 specOf(record)["target"] = map[string]any{"file": "C:main.go"}
190 }},
191 {"an excerpt anchor with no observed line", func(record map[string]any) {
192 delete(record, "status")
193 }},
194 {"a line on a file anchor", func(record map[string]any) {
195 specOf(record)["anchor"] = map[string]any{"scope": "file"}
196 }},
197 {"a resolution with no time", func(record map[string]any) {
198 record["status"] = map[string]any{"lastSeenLine": float64(42), "resolution": "ok"}
199 }},
200 {"a retired resolution", func(record map[string]any) {
201 record["status"] = map[string]any{
202 "lastSeenLine": float64(42), "resolution": "moved", "resolvedAt": "2026-08-05T11:00:00Z",
203 }
204 }},
205 {"an abbreviated resolved commit", func(record map[string]any) {
206 record["status"] = map[string]any{
207 "lastSeenLine": float64(42), "resolution": "ok",
208 "resolvedAt": "2026-08-05T11:00:00Z", "resolvedCommit": "0123456",
209 }
210 }},
211 {"human migration source", func(record map[string]any) {
212 specOf(record)["author"] = map[string]any{
213 "name": "Test Human",
214 "kind": "human",
215 "source": "migration",
216 }
217 }},
218 {"unacknowledged exception", func(record map[string]any) {
219 specOf(record)["policy"] = map[string]any{
220 "exception": "inline-comment",
221 "acknowledged": false,
222 }
223 }},
224 {"non-why exception", func(record map[string]any) {
225 spec := specOf(record)
226 spec["type"] = "gotcha"
227 spec["policy"] = map[string]any{
228 "exception": "inline-comment",
229 "acknowledged": true,
230 }
231 }},
232 {"file-wide exception", func(record map[string]any) {
233 spec := specOf(record)
234 spec["type"] = "why"
235 spec["anchor"] = map[string]any{"scope": "file"}
236 spec["policy"] = map[string]any{
237 "exception": "inline-comment",
238 "acknowledged": true,
239 }
240 delete(record, "status")
241 }},
242 } {
243 t.Run(test.name, func(t *testing.T) {
244 record := decodeRecord(t, validRecord)
245 test.mutate(record)
246 if err := resolved.Validate(record); err == nil {
247 t.Fatal("invalid record was accepted")
248 }
249 })
250 }
251 }

Find an annotation

Search file paths, rationale, kinds, and authors.

moveEnter openEsc close