e2e/writerate_test.go

1ed9fb9399b21da8e6cf45be8389792aac82d5bc
gitbay/e2e/writerate_test.go history · blame · raw

80 lines · 3150 bytes

 1package e2e
 2
 3import (
 4	"os"
 5	"path/filepath"
 6	"strings"
 7	"testing"
 8)
 9
10// Mutating commands are bounded per account in the dispatcher, so the
11// budget is the same one whichever surface spends it. Reads are not
12// charged (#148).
13func TestWriteRateLimit(t *testing.T) {
14	t.Parallel()
15	inst := startInstanceWith(t, "[limits]\nwrite_rate = 4\n")
16	aliceKey := inst.newKey(t, "alice")
17	bobKey := inst.newKey(t, "bob")
18	inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub")
19	inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
20
21	// repo create plus three issues is the whole budget.
22	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
23		t.Fatalf("repo create: %s", errOut)
24	}
25	for i := 0; i < 3; i++ {
26		if _, errOut, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/app", "--title", "t"); code != 0 {
27			t.Fatalf("issue %d within the budget was refused: %s", i+1, errOut)
28		}
29	}
30	_, errOut, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/app", "--title", "over")
31	if code != 4 {
32		t.Fatalf("write past the budget exited %d, want 4:\n%s", code, errOut)
33	}
34	if !strings.Contains(errOut, "too many writes") || !strings.Contains(errOut, "try again in") {
35		t.Errorf("refusal does not say what happened or when to retry: %s", errOut)
36	}
37
38	// Reads are not charged, so a throttled account can still look.
39	if out, _, code := inst.ssh(t, aliceKey, "", "issue", "list", "alice/app"); code != 0 {
40		t.Fatalf("a read was refused while throttled: %s", out)
41	}
42
43	// The budget is per account, not per instance.
44	if _, errOut, code := inst.ssh(t, bobKey, "", "repo", "create", "bob/app"); code != 0 {
45		t.Fatalf("bob was charged for alice's writes: %s", errOut)
46	}
47}
48
49// The runner protocol is exempt: a build streams its log in many small
50// writes, and throttling those would throttle CI itself.
51func TestWriteRateLimitSparesTheRunner(t *testing.T) {
52	t.Parallel()
53	inst := startInstanceWith(t, "[limits]\nwrite_rate = 2\n")
54	inst.runner = buildRunner(t)
55	aliceKey := inst.newKey(t, "alice")
56	inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub")
57	runnerKey := inst.newKey(t, "ci")
58	inst.admin(t, "admin", "user", "create", "ci", "--key", runnerKey+".pub", "--admin")
59
60	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
61		t.Fatalf("repo create: %s", errOut)
62	}
63	env := inst.gitEnv(aliceKey)
64	work := t.TempDir()
65	mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
66	dir := filepath.Join(work, "w")
67	os.MkdirAll(filepath.Join(dir, ".gitbay"), 0o755)
68	os.WriteFile(filepath.Join(dir, ".gitbay", "ci.yml"),
69		[]byte("jobs:\n  smoke:\n    steps:\n      - echo ok\n"), 0o644)
70	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
71	mustGit(t, dir, env, "add", ".")
72	mustGit(t, dir, env, "commit", "-q", "-m", "base")
73	mustGit(t, dir, env, "push", "-q", "origin", "main")
74
75	inst.runnerOnce(t, runnerKey)
76	out, _, _ := inst.ssh(t, aliceKey, "", "build", "list", "alice/app")
77	if !strings.Contains(out, "success") {
78		t.Fatalf("the build did not run under a tight write budget:\n%s", out)
79	}
80}