internal/control/events_test.go

b347d6c8c464e3c965455795f4e22e0aaeed0652
gitbay/internal/control/events_test.go history · blame · raw

70 lines · 2268 bytes

 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}