e2e/writerate_test.go

3797906826d106b7e052e9d1a95958af851ec052
gitbay/e2e/writerate_test.go history · blame · raw

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