internal/control/events_test.go
70 lines · 2268 bytes
2 symbols in this file
1package control
2
3import (
4 "os"
5 "path/filepath"
6 "regexp"
7 "slices"
8 "strings"
9 "testing"
10)
11
12// recordEventKind pulls the kind out of a RecordEvent call. The kind is
13// either a literal or a literal prefix concatenated with a variable, and
14// the second shape is why this reads source rather than trusting a list.
15var recordEventKind = regexp.MustCompile(`RecordEvent\([^,]+,\s*[^,]+,\s*"([a-z._]+)"`)
16
17// TestEventKindsAreRecorded keeps the published list and the code
18// together: an event added without documenting it, or documented without
19// being emitted, fails here. Webhook subscribers filter on these strings,
20// so a name that exists in only one of the two places is a subscription
21// that silently never fires (#112).
22func TestEventKindsAreRecorded(t *testing.T) {
23 emitted := map[string]bool{}
24 roots := []string{".", filepath.Join("..", "hookd")}
25 for _, root := range roots {
26 entries, err := os.ReadDir(root)
27 if err != nil {
28 t.Fatal(err)
29 }
30 for _, e := range entries {
31 if !strings.HasSuffix(e.Name(), ".go") || strings.HasSuffix(e.Name(), "_test.go") {
32 continue
33 }
34 src, err := os.ReadFile(filepath.Join(root, e.Name()))
35 if err != nil {
36 t.Fatal(err)
37 }
38 for _, m := range recordEventKind.FindAllStringSubmatch(string(src), -1) {
39 emitted[m[1]] = true
40 }
41 }
42 }
43 // The kinds built from a variable suffix, which the pattern above
44 // sees only as their prefix. Each is spelled out so the list stays
45 // exhaustive rather than approximate.
46 for _, k := range []string{
47 "build.success", "build.failure", // "build."+args[1]
48 "issue.closed", "issue.open", // "issue."+state
49 "repo.archived", "repo.unarchived", // "repo."+verb+"d"
50 "issue.commented", "mr.commented", // thread.event
51 "issue.milestoned", "mr.milestoned", // noun+".milestoned"
52 } {
53 emitted[k] = true
54 }
55 // Prefixes the pattern caught from those concatenations.
56 for _, partial := range []string{"build.", "issue.", "repo."} {
57 delete(emitted, partial)
58 }
59
60 for _, k := range EventKinds {
61 if !emitted[k] {
62 t.Errorf("EventKinds lists %q but nothing records it", k)
63 }
64 }
65 for k := range emitted {
66 if !slices.Contains(EventKinds, k) {
67 t.Errorf("%q is recorded but missing from EventKinds; add it, and to the API wiki page", k)
68 }
69 }
70}