e2e: build binaries once, run the tests in parallel !454
142 files changed, +311 −79
Layout: unified · split
Makefile +2 −3
| @@ -26,9 +26,8 @@ RUNNER_BIN := dist/gitbay-runner-linux-amd64 | |||
| 26 | help: | 26 | help: |
| 27 | @sed -n 's/^# //p' $(MAKEFILE_LIST) | 27 | @sed -n 's/^# //p' $(MAKEFILE_LIST) |
| 28 | 28 | ||
| 29 | # The e2e suite runs 400-700s against go's 600s per-package default, so a | 29 | # -timeout 30m is a ceiling for a real hang, not a working figure: the |
| 30 | # loaded machine turns a passing tree into a goroutine dump that reads as | 30 | # suite runs in a couple of minutes since the e2e tests went parallel. |
| 31 | # an unrelated failure. A real hang still fails, just later. | ||
| 32 | test: | 31 | test: |
| 33 | go test ./... -count=1 -timeout 30m | 32 | go test ./... -count=1 -timeout 30m |
| 34 | 33 | ||
e2e/aboutbackfill_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // The about text parked by migration 0058 becomes a file in the owner's | 11 | // The about text parked by migration 0058 becomes a file in the owner's |
| 12 | // .gitbay repository. Running it twice writes nothing the second time. | 12 | // .gitbay repository. Running it twice writes nothing the second time. |
| 13 | func TestMigrateProfileAbout(t *testing.T) { | 13 | func TestMigrateProfileAbout(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | inst.admin(t, "admin", "user", "create", "alice", | 17 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/accounts_test.go +3
| @@ -49,6 +49,7 @@ func browserPost(t *testing.T, c *http.Client, u string, form url.Values) (int, | |||
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | func TestWebAccounts(t *testing.T) { | 51 | func TestWebAccounts(t *testing.T) { |
| 52 | t.Parallel() | ||
| 52 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 53 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 53 | 54 | ||
| 54 | aliceKey := inst.newKey(t, "alice") | 55 | aliceKey := inst.newKey(t, "alice") |
| @@ -246,6 +247,7 @@ func TestWebAccounts(t *testing.T) { | |||
| 246 | // TestViewOnlyHasNoLoginOnTheWire is the M8 negative: in view_only mode the | 247 | // TestViewOnlyHasNoLoginOnTheWire is the M8 negative: in view_only mode the |
| 247 | // login route does not exist and web login over ssh is refused. | 248 | // login route does not exist and web login over ssh is refused. |
| 248 | func TestViewOnlyHasNoLoginOnTheWire(t *testing.T) { | 249 | func TestViewOnlyHasNoLoginOnTheWire(t *testing.T) { |
| 250 | t.Parallel() | ||
| 249 | inst := startInstance(t) // default: view_only | 251 | inst := startInstance(t) // default: view_only |
| 250 | aliceKey := inst.newKey(t, "alice") | 252 | aliceKey := inst.newKey(t, "alice") |
| 251 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 253 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -263,6 +265,7 @@ func TestViewOnlyHasNoLoginOnTheWire(t *testing.T) { | |||
| 263 | // and its hostname: the login page prints a command to paste into a terminal, | 265 | // and its hostname: the login page prints a command to paste into a terminal, |
| 264 | // so it must name the host even when the operator has set a display title. | 266 | // so it must name the host even when the operator has set a display title. |
| 265 | func TestTitleIsNotAHostname(t *testing.T) { | 267 | func TestTitleIsNotAHostname(t *testing.T) { |
| 268 | t.Parallel() | ||
| 266 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\ntitle = \"GitBay\"\n") | 269 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\ntitle = \"GitBay\"\n") |
| 267 | 270 | ||
| 268 | status, body := inst.get(t, "/login") | 271 | status, body := inst.get(t, "/login") |
e2e/accountweb_test.go +1
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | // browser session. Public keys are the only credential-shaped input the web | 13 | // browser session. Public keys are the only credential-shaped input the web |
| 14 | // accepts; secrets and token minting stay on SSH. | 14 | // accepts; secrets and token minting stay on SSH. |
| 15 | func TestAccountSettingsWeb(t *testing.T) { | 15 | func TestAccountSettingsWeb(t *testing.T) { |
| 16 | t.Parallel() | ||
| 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 17 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 17 | aliceKey := inst.newKey(t, "alice") | 18 | aliceKey := inst.newKey(t, "alice") |
| 18 | inst.admin(t, "admin", "user", "create", "alice", | 19 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/acme_test.go +1
| @@ -18,6 +18,7 @@ import ( | |||
| 18 | // name, which a test cannot have; what matters here is that the plumbing is | 18 | // name, which a test cannot have; what matters here is that the plumbing is |
| 19 | // correct and failure to issue does not kill the daemon. | 19 | // correct and failure to issue does not kill the daemon. |
| 20 | func TestACMEServe(t *testing.T) { | 20 | func TestACMEServe(t *testing.T) { |
| 21 | t.Parallel() | ||
| 21 | inst := startInstanceWith(t, "") // helper for binary + keys; killed below | 22 | inst := startInstanceWith(t, "") // helper for binary + keys; killed below |
| 22 | inst.proc.Process.Kill() | 23 | inst.proc.Process.Kill() |
| 23 | inst.proc.Wait() | 24 | inst.proc.Wait() |
e2e/activity_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | ) | 11 | ) |
| 12 | 12 | ||
| 13 | func TestActivityGraph(t *testing.T) { | 13 | func TestActivityGraph(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
e2e/adminusers_test.go +7
| @@ -17,6 +17,7 @@ type adminUserRow struct { | |||
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | func TestAdminUserListAndShow(t *testing.T) { | 19 | func TestAdminUserListAndShow(t *testing.T) { |
| 20 | t.Parallel() | ||
| 20 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 21 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 21 | adminKey := inst.newKey(t, "root") | 22 | adminKey := inst.newKey(t, "root") |
| 22 | aliceKey := inst.newKey(t, "alice") | 23 | aliceKey := inst.newKey(t, "alice") |
| @@ -171,6 +172,7 @@ func TestAdminUserListAndShow(t *testing.T) { | |||
| 171 | } | 172 | } |
| 172 | 173 | ||
| 173 | func TestAdminPromoteDemote(t *testing.T) { | 174 | func TestAdminPromoteDemote(t *testing.T) { |
| 175 | t.Parallel() | ||
| 174 | inst := startInstance(t) | 176 | inst := startInstance(t) |
| 175 | rootKey := inst.newKey(t, "root") | 177 | rootKey := inst.newKey(t, "root") |
| 176 | aliceKey := inst.newKey(t, "alice") | 178 | aliceKey := inst.newKey(t, "alice") |
| @@ -226,6 +228,7 @@ func TestAdminPromoteDemote(t *testing.T) { | |||
| 226 | } | 228 | } |
| 227 | 229 | ||
| 228 | func TestAdminRepoModeration(t *testing.T) { | 230 | func TestAdminRepoModeration(t *testing.T) { |
| 231 | t.Parallel() | ||
| 229 | inst := startInstance(t) | 232 | inst := startInstance(t) |
| 230 | rootKey := inst.newKey(t, "root") | 233 | rootKey := inst.newKey(t, "root") |
| 231 | aliceKey := inst.newKey(t, "alice") | 234 | aliceKey := inst.newKey(t, "alice") |
| @@ -337,6 +340,7 @@ func TestAdminRepoModeration(t *testing.T) { | |||
| 337 | // commands work in an admin's SSH session and audit rows say which path | 340 | // commands work in an admin's SSH session and audit rows say which path |
| 338 | // ran them. | 341 | // ran them. |
| 339 | func TestAdminHostAndSSHAreOneSurface(t *testing.T) { | 342 | func TestAdminHostAndSSHAreOneSurface(t *testing.T) { |
| 343 | t.Parallel() | ||
| 340 | inst := startInstance(t) | 344 | inst := startInstance(t) |
| 341 | rootKey := inst.newKey(t, "root") | 345 | rootKey := inst.newKey(t, "root") |
| 342 | aliceKey := inst.newKey(t, "alice") | 346 | aliceKey := inst.newKey(t, "alice") |
| @@ -402,6 +406,7 @@ func TestAdminHostAndSSHAreOneSurface(t *testing.T) { | |||
| 402 | } | 406 | } |
| 403 | 407 | ||
| 404 | func TestAuditFilters(t *testing.T) { | 408 | func TestAuditFilters(t *testing.T) { |
| 409 | t.Parallel() | ||
| 405 | inst := startInstance(t) | 410 | inst := startInstance(t) |
| 406 | rootKey := inst.newKey(t, "root") | 411 | rootKey := inst.newKey(t, "root") |
| 407 | aliceKey := inst.newKey(t, "alice") | 412 | aliceKey := inst.newKey(t, "alice") |
| @@ -454,6 +459,7 @@ func TestAuditFilters(t *testing.T) { | |||
| 454 | } | 459 | } |
| 455 | 460 | ||
| 456 | func TestAdminQueuesDashboard(t *testing.T) { | 461 | func TestAdminQueuesDashboard(t *testing.T) { |
| 462 | t.Parallel() | ||
| 457 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n[webhooks]\nallow_local = true\n") | 463 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n[webhooks]\nallow_local = true\n") |
| 458 | rootKey := inst.newKey(t, "root") | 464 | rootKey := inst.newKey(t, "root") |
| 459 | aliceKey := inst.newKey(t, "alice") | 465 | aliceKey := inst.newKey(t, "alice") |
| @@ -568,6 +574,7 @@ func TestAdminQueuesDashboard(t *testing.T) { | |||
| 568 | } | 574 | } |
| 569 | 575 | ||
| 570 | func TestAdminConfigShow(t *testing.T) { | 576 | func TestAdminConfigShow(t *testing.T) { |
| 577 | t.Parallel() | ||
| 571 | inst := startInstanceWith(t, "[mail]\nsmtp_host = \"127.0.0.1:1\"\nfrom = \"forge@example.test\"\nsmtp_pass = \"hunter2\"\n") | 578 | inst := startInstanceWith(t, "[mail]\nsmtp_host = \"127.0.0.1:1\"\nfrom = \"forge@example.test\"\nsmtp_pass = \"hunter2\"\n") |
| 572 | out := inst.admin(t, "admin", "config", "show") | 579 | out := inst.admin(t, "admin", "config", "show") |
| 573 | for _, want := range []string{"[server]", "site_url", "ssh_auth_rate = 10", "pull_interval_minutes = 15", "[mail]", `smtp_pass = "<redacted>"`} { | 580 | for _, want := range []string{"[server]", "site_url", "ssh_auth_rate = 10", "pull_interval_minutes = 15", "[mail]", `smtp_pass = "<redacted>"`} { |
e2e/adminusersweb_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // web can reach now that nothing is held back from it (#234). Demote | 10 | // web can reach now that nothing is held back from it (#234). Demote |
| 11 | // and disable carry the typed-name check. | 11 | // and disable carry the typed-name check. |
| 12 | func TestAdminUsersWeb(t *testing.T) { | 12 | func TestAdminUsersWeb(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 14 | rootKey := inst.newKey(t, "root") | 15 | rootKey := inst.newKey(t, "root") |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
e2e/api_test.go +3
| @@ -40,6 +40,7 @@ func (i *instance) apiCall(t *testing.T, token string, argv []string, stdin stri | |||
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | func TestJSONAPI(t *testing.T) { | 42 | func TestJSONAPI(t *testing.T) { |
| 43 | t.Parallel() | ||
| 43 | inst := startInstanceWith(t, "[api]\nenabled = true\n") | 44 | inst := startInstanceWith(t, "[api]\nenabled = true\n") |
| 44 | aliceKey := inst.newKey(t, "alice") | 45 | aliceKey := inst.newKey(t, "alice") |
| 45 | inst.admin(t, "admin", "user", "create", "alice", | 46 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -202,6 +203,7 @@ func TestJSONAPI(t *testing.T) { | |||
| 202 | // metered separately from reads, and one caller cannot spend another's | 203 | // metered separately from reads, and one caller cannot spend another's |
| 203 | // budget. | 204 | // budget. |
| 204 | func TestAPIRateLimit(t *testing.T) { | 205 | func TestAPIRateLimit(t *testing.T) { |
| 206 | t.Parallel() | ||
| 205 | // 6/minute sustained, so the read burst is 6 and the write burst 0.6 — | 207 | // 6/minute sustained, so the read burst is 6 and the write burst 0.6 — |
| 206 | // the first write is allowed and the second is not. | 208 | // the first write is allowed and the second is not. |
| 207 | inst := startInstanceWith(t, "[api]\nenabled = true\n[limits]\napi_rate = 6\n") | 209 | inst := startInstanceWith(t, "[api]\nenabled = true\n[limits]\napi_rate = 6\n") |
| @@ -309,6 +311,7 @@ func (i *instance) apiGet(t *testing.T, token string, argv []string, ifNoneMatch | |||
| 309 | // with an ETag, 304 on revalidation, writes refused, and one caller's ETag | 311 | // with an ETag, 304 on revalidation, writes refused, and one caller's ETag |
| 310 | // never matching another's. | 312 | // never matching another's. |
| 311 | func TestAPIReadGET(t *testing.T) { | 313 | func TestAPIReadGET(t *testing.T) { |
| 314 | t.Parallel() | ||
| 312 | inst := startInstanceWith(t, "[api]\nenabled = true\n") | 315 | inst := startInstanceWith(t, "[api]\nenabled = true\n") |
| 313 | aliceKey := inst.newKey(t, "alice") | 316 | aliceKey := inst.newKey(t, "alice") |
| 314 | bobKey := inst.newKey(t, "bob") | 317 | bobKey := inst.newKey(t, "bob") |
e2e/apiread_test.go +1
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | // before: no command returned file contents, and the web's raw route | 14 | // before: no command returned file contents, and the web's raw route |
| 15 | // authenticates by session cookie, not bearer token. | 15 | // authenticates by session cookie, not bearer token. |
| 16 | func TestRepoTreeAndCat(t *testing.T) { | 16 | func TestRepoTreeAndCat(t *testing.T) { |
| 17 | t.Parallel() | ||
| 17 | inst := startInstance(t) | 18 | inst := startInstance(t) |
| 18 | aliceKey := inst.newKey(t, "alice") | 19 | aliceKey := inst.newKey(t, "alice") |
| 19 | bobKey := inst.newKey(t, "bob") | 20 | bobKey := inst.newKey(t, "bob") |
e2e/approvals_test.go +2
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | ) | 10 | ) |
| 11 | 11 | ||
| 12 | func TestMergeRequirements(t *testing.T) { | 12 | func TestMergeRequirements(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
| @@ -147,6 +148,7 @@ func TestMergeRequirements(t *testing.T) { | |||
| 147 | // merges. When it is on, it gates independently of require_approvals — | 148 | // merges. When it is on, it gates independently of require_approvals — |
| 148 | // the coupling that left owners unenforced under default settings (#99). | 149 | // the coupling that left owners unenforced under default settings (#99). |
| 149 | func TestCodeownersToggle(t *testing.T) { | 150 | func TestCodeownersToggle(t *testing.T) { |
| 151 | t.Parallel() | ||
| 150 | inst := startInstance(t) | 152 | inst := startInstance(t) |
| 151 | aliceKey := inst.newKey(t, "alice") | 153 | aliceKey := inst.newKey(t, "alice") |
| 152 | carolKey := inst.newKey(t, "carol") | 154 | carolKey := inst.newKey(t, "carol") |
e2e/archive_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestArchiveAndTopics(t *testing.T) { | 10 | func TestArchiveAndTopics(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/audit_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestAuditAndHardening(t *testing.T) { | 11 | func TestAuditAndHardening(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstanceWith(t, "[limits]\nssh_auth_rate = 3\nmax_pack_bytes = 2000\n") | 13 | inst := startInstanceWith(t, "[limits]\nssh_auth_rate = 3\nmax_pack_bytes = 2000\n") |
| 13 | adminKey := inst.newKey(t, "root") | 14 | adminKey := inst.newKey(t, "root") |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
e2e/autolink_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestWebAutolinks(t *testing.T) { | 10 | func TestWebAutolinks(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/backup_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | ) | 12 | ) |
| 13 | 13 | ||
| 14 | func TestAdminBackup(t *testing.T) { | 14 | func TestAdminBackup(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", | 18 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/badge_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // says "unknown" before any build exists, and 404s for a private repo so | 9 | // says "unknown" before any build exists, and 404s for a private repo so |
| 10 | // it cannot be used to probe for one. | 10 | // it cannot be used to probe for one. |
| 11 | func TestBuildBadge(t *testing.T) { | 11 | func TestBuildBadge(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/bin_test.go added +67
| @@ -0,0 +1,67 @@ | |||
| 1 | package e2e | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "os" | ||
| 5 | "os/exec" | ||
| 6 | "path/filepath" | ||
| 7 | "sync" | ||
| 8 | "testing" | ||
| 9 | ) | ||
| 10 | |||
| 11 | // The suite starts an instance per test, and each one needs gitbayd. Built | ||
| 12 | // per test, that is 200-odd links of a byte-identical 35MB binary: go's | ||
| 13 | // build cache covers the compile but not the final link, so it cost about | ||
| 14 | // 0.8s every time, a quarter of the whole run. | ||
| 15 | // | ||
| 16 | // Built once per process instead, under a directory TestMain owns. The | ||
| 17 | // binaries outlive any single test, so t.TempDir is the wrong home for | ||
| 18 | // them — it is removed when the test that asked for it ends. | ||
| 19 | var ( | ||
| 20 | gitbaydBin = &builtBin{name: "gitbayd", pkg: "gitbay.org/gitbay/cmd/gitbayd"} | ||
| 21 | gitbayBin = &builtBin{name: "gitbay", pkg: "gitbay.org/gitbay/cmd/gitbay"} | ||
| 22 | runnerBin = &builtBin{name: "gitbay-runner", pkg: "gitbay.org/gitbay/cmd/gitbay-runner"} | ||
| 23 | ) | ||
| 24 | |||
| 25 | // binDir is where the built binaries live, set by TestMain. | ||
| 26 | var binDir string | ||
| 27 | |||
| 28 | type builtBin struct { | ||
| 29 | name string | ||
| 30 | pkg string | ||
| 31 | |||
| 32 | once sync.Once | ||
| 33 | path string | ||
| 34 | out []byte | ||
| 35 | err error | ||
| 36 | } | ||
| 37 | |||
| 38 | // get builds the binary on first use and returns the same path thereafter. | ||
| 39 | // Lazily, so `-run TestOneThing` does not link the two binaries it has no | ||
| 40 | // use for. | ||
| 41 | func (b *builtBin) get(t *testing.T) string { | ||
| 42 | t.Helper() | ||
| 43 | b.once.Do(func() { | ||
| 44 | b.path = filepath.Join(binDir, b.name) | ||
| 45 | cmd := exec.Command("go", "build", "-o", b.path, b.pkg) | ||
| 46 | cmd.Dir = ".." | ||
| 47 | b.out, b.err = cmd.CombinedOutput() | ||
| 48 | }) | ||
| 49 | if b.err != nil { | ||
| 50 | t.Fatalf("build %s: %v\n%s", b.name, b.err, b.out) | ||
| 51 | } | ||
| 52 | return b.path | ||
| 53 | } | ||
| 54 | |||
| 55 | func buildGitbayd(t *testing.T) string { return gitbaydBin.get(t) } | ||
| 56 | func buildGitbayCLI(t *testing.T) string { return gitbayBin.get(t) } | ||
| 57 | func buildRunner(t *testing.T) string { return runnerBin.get(t) } | ||
| 58 | |||
| 59 | // makeBinDir is called by TestMain. Returned rather than deferred because | ||
| 60 | // TestMain ends in os.Exit, which runs no deferred functions. | ||
| 61 | func makeBinDir() (dir string, cleanup func(), err error) { | ||
| 62 | dir, err = os.MkdirTemp("", "e2e-bin") | ||
| 63 | if err != nil { | ||
| 64 | return "", func() {}, err | ||
| 65 | } | ||
| 66 | return dir, func() { os.RemoveAll(dir) }, nil | ||
| 67 | } | ||
e2e/blame_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestBlameView(t *testing.T) { | 11 | func TestBlameView(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | inst.admin(t, "admin", "user", "create", "alice", | 15 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/blobrender_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // Markdown and org files render on the blob page, with the source one | 10 | // Markdown and org files render on the blob page, with the source one |
| 11 | // click away; everything else is unchanged. | 11 | // click away; everything else is unchanged. |
| 12 | func TestBlobRendersMarkup(t *testing.T) { | 12 | func TestBlobRendersMarkup(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/bookmarks_test.go +2
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // are something you do to someone else's repository, and the count is a | 12 | // are something you do to someone else's repository, and the count is a |
| 13 | // signal of what people found worth returning to (#146). | 13 | // signal of what people found worth returning to (#146). |
| 14 | func TestBookmarks(t *testing.T) { | 14 | func TestBookmarks(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | bobKey := inst.newKey(t, "bob") | 18 | bobKey := inst.newKey(t, "bob") |
| @@ -89,6 +90,7 @@ func TestBookmarks(t *testing.T) { | |||
| 89 | // A repository bookmarked while public and since made private drops out | 90 | // A repository bookmarked while public and since made private drops out |
| 90 | // of the listing rather than leaking its existence. | 91 | // of the listing rather than leaking its existence. |
| 91 | func TestBookmarkOfRepoGonePrivate(t *testing.T) { | 92 | func TestBookmarkOfRepoGonePrivate(t *testing.T) { |
| 93 | t.Parallel() | ||
| 92 | inst := startInstance(t) | 94 | inst := startInstance(t) |
| 93 | aliceKey := inst.newKey(t, "alice") | 95 | aliceKey := inst.newKey(t, "alice") |
| 94 | bobKey := inst.newKey(t, "bob") | 96 | bobKey := inst.newKey(t, "bob") |
e2e/build_cancel_test.go +2
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | // Cancelling a duplicate of a commit that already passed puts that | 14 | // Cancelling a duplicate of a commit that already passed puts that |
| 15 | // result back on the commit. | 15 | // result back on the commit. |
| 16 | func TestBuildCancel(t *testing.T) { | 16 | func TestBuildCancel(t *testing.T) { |
| 17 | t.Parallel() | ||
| 17 | inst := startInstance(t) | 18 | inst := startInstance(t) |
| 18 | inst.runner = buildRunner(t) | 19 | inst.runner = buildRunner(t) |
| 19 | aliceKey := inst.newKey(t, "alice") | 20 | aliceKey := inst.newKey(t, "alice") |
| @@ -91,6 +92,7 @@ func TestBuildCancel(t *testing.T) { | |||
| 91 | // server closes the log session, the runner kills the step, and its late | 92 | // server closes the log session, the runner kills the step, and its late |
| 92 | // report lands on a row that already says cancelled. | 93 | // report lands on a row that already says cancelled. |
| 93 | func TestBuildCancelRunning(t *testing.T) { | 94 | func TestBuildCancelRunning(t *testing.T) { |
| 95 | t.Parallel() | ||
| 94 | inst := startInstance(t) | 96 | inst := startInstance(t) |
| 95 | inst.runner = buildRunner(t) | 97 | inst.runner = buildRunner(t) |
| 96 | aliceKey := inst.newKey(t, "alice") | 98 | aliceKey := inst.newKey(t, "alice") |
e2e/buildcancelweb_test.go +1
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | // real, so a stale or repeated post against a build that is no longer | 14 | // real, so a stale or repeated post against a build that is no longer |
| 15 | // cancellable shows the refusal rather than a broken page. | 15 | // cancellable shows the refusal rather than a broken page. |
| 16 | func TestBuildCancelWeb(t *testing.T) { | 16 | func TestBuildCancelWeb(t *testing.T) { |
| 17 | t.Parallel() | ||
| 17 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 18 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 18 | aliceKey := inst.newKey(t, "alice") | 19 | aliceKey := inst.newKey(t, "alice") |
| 19 | inst.admin(t, "admin", "user", "create", "alice", | 20 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/buildorphan_test.go +1
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | // looking like a real failure; it is cancelled when a runner claims it, and | 13 | // looking like a real failure; it is cancelled when a runner claims it, and |
| 14 | // the runner gets the real build behind it instead, in the same poll. | 14 | // the runner gets the real build behind it instead, in the same poll. |
| 15 | func TestBuildOrphanedByForcePushCancelledAtClaim(t *testing.T) { | 15 | func TestBuildOrphanedByForcePushCancelledAtClaim(t *testing.T) { |
| 16 | t.Parallel() | ||
| 16 | inst := startInstance(t) | 17 | inst := startInstance(t) |
| 17 | inst.runner = buildRunner(t) | 18 | inst.runner = buildRunner(t) |
| 18 | aliceKey := inst.newKey(t, "alice") | 19 | aliceKey := inst.newKey(t, "alice") |
e2e/ci_dedupe_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // A fast-forward lands the exact commit that was already built on its | 10 | // A fast-forward lands the exact commit that was already built on its |
| 11 | // branch; that commit is not built again. A commit whose build failed is. | 11 | // branch; that commit is not built again. A commit whose build failed is. |
| 12 | func TestFastForwardMergeSkipsBuiltCommit(t *testing.T) { | 12 | func TestFastForwardMergeSkipsBuiltCommit(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | inst.runner = buildRunner(t) | 15 | inst.runner = buildRunner(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
e2e/ci_merge_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // an MR into a repository with a CI config queued nothing, while pushing | 12 | // an MR into a repository with a CI config queued nothing, while pushing |
| 13 | // the identical commit ran the whole config. | 13 | // the identical commit ran the whole config. |
| 14 | func TestMergeQueuesBuildsAndRecordsPush(t *testing.T) { | 14 | func TestMergeQueuesBuildsAndRecordsPush(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", | 18 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", |
e2e/ci_nojobs_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // the setting off. Nothing was ever going to report, so the gate has | 11 | // the setting off. Nothing was ever going to report, so the gate has |
| 12 | // nothing to wait for. | 12 | // nothing to wait for. |
| 13 | func TestRequireChecksWithoutCIConfigMerges(t *testing.T) { | 13 | func TestRequireChecksWithoutCIConfigMerges(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", | 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", |
e2e/ci_skipped_test.go +1
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | // filtered job now records a "skipped" status instead, which the gate reads | 13 | // filtered job now records a "skipped" status instead, which the gate reads |
| 14 | // as green (#172). | 14 | // as green (#172). |
| 15 | func TestSkippedStatusSatisfiesRequireChecks(t *testing.T) { | 15 | func TestSkippedStatusSatisfiesRequireChecks(t *testing.T) { |
| 16 | t.Parallel() | ||
| 16 | inst := startInstance(t) | 17 | inst := startInstance(t) |
| 17 | aliceKey := inst.newKey(t, "alice") | 18 | aliceKey := inst.newKey(t, "alice") |
| 18 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", | 19 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", |
e2e/ci_test.go +3 −11
| @@ -11,17 +11,6 @@ import ( | |||
| 11 | "time" | 11 | "time" |
| 12 | ) | 12 | ) |
| 13 | 13 | ||
| 14 | func buildRunner(t *testing.T) string { | ||
| 15 | t.Helper() | ||
| 16 | bin := filepath.Join(t.TempDir(), "gitbay-runner") | ||
| 17 | cmd := exec.Command("go", "build", "-o", bin, "gitbay.org/gitbay/cmd/gitbay-runner") | ||
| 18 | cmd.Dir = ".." | ||
| 19 | if out, err := cmd.CombinedOutput(); err != nil { | ||
| 20 | t.Fatalf("build gitbay-runner: %v\n%s", err, out) | ||
| 21 | } | ||
| 22 | return bin | ||
| 23 | } | ||
| 24 | |||
| 25 | // runnerOnce processes at most one pending build with the given key. | 14 | // runnerOnce processes at most one pending build with the given key. |
| 26 | func (i *instance) runnerOnce(t *testing.T, key string, extra ...string) string { | 15 | func (i *instance) runnerOnce(t *testing.T, key string, extra ...string) string { |
| 27 | t.Helper() | 16 | t.Helper() |
| @@ -50,6 +39,7 @@ func (i *instance) runnerOnce(t *testing.T, key string, extra ...string) string | |||
| 50 | // A failed build mails the repo owner with the log tail; green builds | 39 | // A failed build mails the repo owner with the log tail; green builds |
| 51 | // stay silent. | 40 | // stay silent. |
| 52 | func TestBuildFailureMail(t *testing.T) { | 41 | func TestBuildFailureMail(t *testing.T) { |
| 42 | t.Parallel() | ||
| 53 | smtp := startFakeSMTP(t) | 43 | smtp := startFakeSMTP(t) |
| 54 | inst := startInstanceWith(t, fmt.Sprintf( | 44 | inst := startInstanceWith(t, fmt.Sprintf( |
| 55 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 45 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
| @@ -91,6 +81,7 @@ func TestBuildFailureMail(t *testing.T) { | |||
| 91 | } | 81 | } |
| 92 | 82 | ||
| 93 | func TestCI(t *testing.T) { | 83 | func TestCI(t *testing.T) { |
| 84 | t.Parallel() | ||
| 94 | inst := startInstance(t) | 85 | inst := startInstance(t) |
| 95 | inst.runner = buildRunner(t) | 86 | inst.runner = buildRunner(t) |
| 96 | aliceKey := inst.newKey(t, "alice") | 87 | aliceKey := inst.newKey(t, "alice") |
| @@ -318,6 +309,7 @@ func (i *instance) runnerJobs(t *testing.T, key, repo string, jobs int) string { | |||
| 318 | // transaction that selects and updates, so several workers claiming | 309 | // transaction that selects and updates, so several workers claiming |
| 319 | // together is safe; the runner simply never used more than one (#115). | 310 | // together is safe; the runner simply never used more than one (#115). |
| 320 | func TestRunnerConcurrentJobs(t *testing.T) { | 311 | func TestRunnerConcurrentJobs(t *testing.T) { |
| 312 | t.Parallel() | ||
| 321 | inst := startInstance(t) | 313 | inst := startInstance(t) |
| 322 | inst.runner = buildRunner(t) | 314 | inst.runner = buildRunner(t) |
| 323 | aliceKey := inst.newKey(t, "alice") | 315 | aliceKey := inst.newKey(t, "alice") |
e2e/cipaths_test.go +2
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // A doc-only push queues nothing; a push touching the named path queues | 11 | // A doc-only push queues nothing; a push touching the named path queues |
| 12 | // the job, same as before path filters existed. | 12 | // the job, same as before path filters existed. |
| 13 | func TestCIPaths(t *testing.T) { | 13 | func TestCIPaths(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -68,6 +69,7 @@ func TestCIPaths(t *testing.T) { | |||
| 68 | // that first push is always a new branch. Without a merge-base fallback, | 69 | // that first push is always a new branch. Without a merge-base fallback, |
| 69 | // a docs-only branch queues the full suite anyway (#171). | 70 | // a docs-only branch queues the full suite anyway (#171). |
| 70 | func TestCIPathsNewBranch(t *testing.T) { | 71 | func TestCIPathsNewBranch(t *testing.T) { |
| 72 | t.Parallel() | ||
| 71 | inst := startInstance(t) | 73 | inst := startInstance(t) |
| 72 | aliceKey := inst.newKey(t, "alice") | 74 | aliceKey := inst.newKey(t, "alice") |
| 73 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 75 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/cli_test.go +1 −11
| @@ -10,17 +10,6 @@ import ( | |||
| 10 | "testing" | 10 | "testing" |
| 11 | ) | 11 | ) |
| 12 | 12 | ||
| 13 | func buildGitbayCLI(t *testing.T) string { | ||
| 14 | t.Helper() | ||
| 15 | bin := filepath.Join(t.TempDir(), "gitbay") | ||
| 16 | cmd := exec.Command("go", "build", "-o", bin, "gitbay.org/gitbay/cmd/gitbay") | ||
| 17 | cmd.Dir = ".." | ||
| 18 | if out, err := cmd.CombinedOutput(); err != nil { | ||
| 19 | t.Fatalf("build gitbay: %v\n%s", err, out) | ||
| 20 | } | ||
| 21 | return bin | ||
| 22 | } | ||
| 23 | |||
| 24 | // cli runs the forge binary with an isolated config home. | 13 | // cli runs the forge binary with an isolated config home. |
| 25 | type cli struct { | 14 | type cli struct { |
| 26 | bin string | 15 | bin string |
| @@ -66,6 +55,7 @@ func (c *cli) must(t *testing.T, dir, stdin string, args ...string) string { | |||
| 66 | } | 55 | } |
| 67 | 56 | ||
| 68 | func TestCLI(t *testing.T) { | 57 | func TestCLI(t *testing.T) { |
| 58 | t.Parallel() | ||
| 69 | inst := startInstance(t) | 59 | inst := startInstance(t) |
| 70 | aliceKey := inst.newKey(t, "alice") | 60 | aliceKey := inst.newKey(t, "alice") |
| 71 | inst.admin(t, "admin", "user", "create", "alice", | 61 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/commentmigrate_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestMigrateCommitRefComments(t *testing.T) { | 11 | func TestMigrateCommitRefComments(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/commitrefs_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestCommitMessageIssueActions(t *testing.T) { | 10 | func TestCommitMessageIssueActions(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | inst.admin(t, "admin", "user", "create", "alice", | 14 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/compare_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // The compare view shows what a branch adds on top of another from their | 10 | // The compare view shows what a branch adds on top of another from their |
| 11 | // merge base, and repo diff is the same range over ssh (#118). | 11 | // merge base, and repo diff is the same range over ssh (#118). |
| 12 | func TestCompareView(t *testing.T) { | 12 | func TestCompareView(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/dashboard_test.go +4
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestDashboard(t *testing.T) { | 11 | func TestDashboard(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | bobKey := inst.newKey(t, "bob") | 15 | bobKey := inst.newKey(t, "bob") |
| @@ -136,6 +137,7 @@ func TestDashboard(t *testing.T) { | |||
| 136 | // dashboard — review queue, assigned/open work, pins, and activity — in | 137 | // dashboard — review queue, assigned/open work, pins, and activity — in |
| 137 | // one read. Builds remain for clients that already consume them. | 138 | // one read. Builds remain for clients that already consume them. |
| 138 | func TestDashboardCommand(t *testing.T) { | 139 | func TestDashboardCommand(t *testing.T) { |
| 140 | t.Parallel() | ||
| 139 | inst := startInstance(t) | 141 | inst := startInstance(t) |
| 140 | aliceKey := inst.newKey(t, "alice") | 142 | aliceKey := inst.newKey(t, "alice") |
| 141 | bobKey := inst.newKey(t, "bob") | 143 | bobKey := inst.newKey(t, "bob") |
| @@ -286,6 +288,7 @@ func TestDashboardCommand(t *testing.T) { | |||
| 286 | // TestDashboardQueues covers the parts of the dashboard that answer "what | 288 | // TestDashboardQueues covers the parts of the dashboard that answer "what |
| 287 | // needs me": the review queue, assigned issues, and the activity feed. | 289 | // needs me": the review queue, assigned issues, and the activity feed. |
| 288 | func TestDashboardQueues(t *testing.T) { | 290 | func TestDashboardQueues(t *testing.T) { |
| 291 | t.Parallel() | ||
| 289 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 292 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 290 | aliceKey := inst.newKey(t, "alice") | 293 | aliceKey := inst.newKey(t, "alice") |
| 291 | bobKey := inst.newKey(t, "bob") | 294 | bobKey := inst.newKey(t, "bob") |
| @@ -361,6 +364,7 @@ func TestDashboardQueues(t *testing.T) { | |||
| 361 | // folded line's state is the worse of the two, which the feed no longer | 364 | // folded line's state is the worse of the two, which the feed no longer |
| 362 | // draws; TestFeedLinesFoldsBuildRun covers that rule. | 365 | // draws; TestFeedLinesFoldsBuildRun covers that rule. |
| 363 | func TestDashboardFeedFoldsBuildRun(t *testing.T) { | 366 | func TestDashboardFeedFoldsBuildRun(t *testing.T) { |
| 367 | t.Parallel() | ||
| 364 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 368 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 365 | inst.runner = buildRunner(t) | 369 | inst.runner = buildRunner(t) |
| 366 | aliceKey := inst.newKey(t, "alice") | 370 | aliceKey := inst.newKey(t, "alice") |
e2e/dashboardbuild_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // visible without reading the journal. It is admin-only: the exact build a | 9 | // visible without reading the journal. It is admin-only: the exact build a |
| 10 | // host runs narrows down which known issues apply to it. | 10 | // host runs narrows down which known issues apply to it. |
| 11 | func TestDashboardReportsTheServerBuild(t *testing.T) { | 11 | func TestDashboardReportsTheServerBuild(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | 14 | ||
| 14 | adminKey := inst.newKey(t, "root") | 15 | adminKey := inst.newKey(t, "root") |
e2e/defaultbranch_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // A first push of a branch other than main moves the unborn HEAD to it, | 11 | // A first push of a branch other than main moves the unborn HEAD to it, |
| 12 | // and repo settings default-branch moves it later (#189). | 12 | // and repo settings default-branch moves it later (#189). |
| 13 | func TestDefaultBranch(t *testing.T) { | 13 | func TestDefaultBranch(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
e2e/deploykey_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestDeployKeys(t *testing.T) { | 11 | func TestDeployKeys(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | bobKey := inst.newKey(t, "bob") | 15 | bobKey := inst.newKey(t, "bob") |
e2e/deps_test.go +1
| @@ -20,6 +20,7 @@ type depsStatus struct { | |||
| 20 | // can turn it on: the check tells a public registry what the repository | 20 | // can turn it on: the check tells a public registry what the repository |
| 21 | // depends on. | 21 | // depends on. |
| 22 | func TestDepsEnableDisable(t *testing.T) { | 22 | func TestDepsEnableDisable(t *testing.T) { |
| 23 | t.Parallel() | ||
| 23 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 24 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 24 | aliceKey := inst.newKey(t, "alice") | 25 | aliceKey := inst.newKey(t, "alice") |
| 25 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", | 26 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", |
e2e/description_test.go +1
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | func TestRepoDescriptions(t *testing.T) { | 8 | func TestRepoDescriptions(t *testing.T) { |
| 9 | t.Parallel() | ||
| 9 | inst := startInstance(t) | 10 | inst := startInstance(t) |
| 10 | aliceKey := inst.newKey(t, "alice") | 11 | aliceKey := inst.newKey(t, "alice") |
| 11 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 12 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/design_test.go +6
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | ) | 12 | ) |
| 13 | 13 | ||
| 14 | func TestReadmeRelativeLinks(t *testing.T) { | 14 | func TestReadmeRelativeLinks(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 18 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -177,6 +178,7 @@ func TestReadmeRelativeLinks(t *testing.T) { | |||
| 177 | 178 | ||
| 178 | // TestLandingRoutes checks the landing page's copy and the two routes. | 179 | // TestLandingRoutes checks the landing page's copy and the two routes. |
| 179 | func TestLandingRoutes(t *testing.T) { | 180 | func TestLandingRoutes(t *testing.T) { |
| 181 | t.Parallel() | ||
| 180 | smtp := startFakeSMTP(t) | 182 | smtp := startFakeSMTP(t) |
| 181 | inst := startInstanceWith(t, fmt.Sprintf( | 183 | inst := startInstanceWith(t, fmt.Sprintf( |
| 182 | "[web]\nmode = \"accounts\"\n[registration]\nmode = \"open\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 184 | "[web]\nmode = \"accounts\"\n[registration]\nmode = \"open\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
| @@ -204,6 +206,7 @@ func TestLandingRoutes(t *testing.T) { | |||
| 204 | } | 206 | } |
| 205 | 207 | ||
| 206 | func TestWebInteractions(t *testing.T) { | 208 | func TestWebInteractions(t *testing.T) { |
| 209 | t.Parallel() | ||
| 207 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 210 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 208 | aliceKey := inst.newKey(t, "alice") | 211 | aliceKey := inst.newKey(t, "alice") |
| 209 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", "--email", "alice@example.test", "--verified") | 212 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", "--email", "alice@example.test", "--verified") |
| @@ -271,6 +274,7 @@ func TestWebInteractions(t *testing.T) { | |||
| 271 | } | 274 | } |
| 272 | 275 | ||
| 273 | func TestCommitParentLinks(t *testing.T) { | 276 | func TestCommitParentLinks(t *testing.T) { |
| 277 | t.Parallel() | ||
| 274 | inst := startInstance(t) | 278 | inst := startInstance(t) |
| 275 | aliceKey := inst.newKey(t, "alice") | 279 | aliceKey := inst.newKey(t, "alice") |
| 276 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 280 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -305,6 +309,7 @@ func TestCommitParentLinks(t *testing.T) { | |||
| 305 | // verified here displays the account's name rather than whatever git | 309 | // verified here displays the account's name rather than whatever git |
| 306 | // config carried, and that an unknown address keeps its own name. | 310 | // config carried, and that an unknown address keeps its own name. |
| 307 | func TestAuthorNamesResolve(t *testing.T) { | 311 | func TestAuthorNamesResolve(t *testing.T) { |
| 312 | t.Parallel() | ||
| 308 | inst := startInstance(t) | 313 | inst := startInstance(t) |
| 309 | aliceKey := inst.newKey(t, "alice") | 314 | aliceKey := inst.newKey(t, "alice") |
| 310 | inst.admin(t, "admin", "user", "create", "alice", | 315 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -365,6 +370,7 @@ func TestAuthorNamesResolve(t *testing.T) { | |||
| 365 | // TestTreeSearchCodeAndClone: the overview links "Search code", not | 370 | // TestTreeSearchCodeAndClone: the overview links "Search code", not |
| 366 | // "Find file", and shows two labelled clone blocks after the file table. | 371 | // "Find file", and shows two labelled clone blocks after the file table. |
| 367 | func TestTreeSearchCodeAndClone(t *testing.T) { | 372 | func TestTreeSearchCodeAndClone(t *testing.T) { |
| 373 | t.Parallel() | ||
| 368 | inst := startInstance(t) | 374 | inst := startInstance(t) |
| 369 | key := inst.newKey(t, "alice") | 375 | key := inst.newKey(t, "alice") |
| 370 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") | 376 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") |
e2e/diffcomment_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | ) | 10 | ) |
| 11 | 11 | ||
| 12 | func TestDiffComments(t *testing.T) { | 12 | func TestDiffComments(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/diffweb_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // line-number gutters, syntax highlighting, and binary files declared | 11 | // line-number gutters, syntax highlighting, and binary files declared |
| 12 | // rather than dumped. | 12 | // rather than dumped. |
| 13 | func TestDiffRendering(t *testing.T) { | 13 | func TestDiffRendering(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/disabled_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // listener checked the flag and disabling deleted sessions but not tokens | 10 | // listener checked the flag and disabling deleted sessions but not tokens |
| 11 | // (#95). | 11 | // (#95). |
| 12 | func TestDisabledAccountAPI(t *testing.T) { | 12 | func TestDisabledAccountAPI(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[api]\nenabled = true\n") | 14 | inst := startInstanceWith(t, "[api]\nenabled = true\n") |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", | 16 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/edit_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | ) | 10 | ) |
| 11 | 11 | ||
| 12 | func TestIssueMREditing(t *testing.T) { | 12 | func TestIssueMREditing(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/effectiveaccess_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // outsider gets one answer about an org: it exists and has members; | 9 | // outsider gets one answer about an org: it exists and has members; |
| 10 | // its teams are not theirs to see (#200). | 10 | // its teams are not theirs to see (#200). |
| 11 | func TestEffectiveAccessAndOutsiders(t *testing.T) { | 11 | func TestEffectiveAccessAndOutsiders(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | keys := map[string]string{} | 14 | keys := map[string]string{} |
| 14 | for _, u := range []string{"alice", "bob", "carol", "dave", "eve"} { | 15 | for _, u := range []string{"alice", "bob", "carol", "dave", "eve"} { |
e2e/emaillogin_test.go +6
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // A person with no SSH key can still get into the web UI: they ask for a | 11 | // A person with no SSH key can still get into the web UI: they ask for a |
| 12 | // link by username or verified address and it arrives by mail (#155). | 12 | // link by username or verified address and it arrives by mail (#155). |
| 13 | func TestEmailLogin(t *testing.T) { | 13 | func TestEmailLogin(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | smtp := startFakeSMTP(t) | 15 | smtp := startFakeSMTP(t) |
| 15 | inst := startInstanceWith(t, fmt.Sprintf( | 16 | inst := startInstanceWith(t, fmt.Sprintf( |
| 16 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 17 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
| @@ -71,6 +72,7 @@ func TestEmailLogin(t *testing.T) { | |||
| 71 | // A verified secondary address stands in for an unverified primary: | 72 | // A verified secondary address stands in for an unverified primary: |
| 72 | // resolution by username must not stop at the primary (#158). | 73 | // resolution by username must not stop at the primary (#158). |
| 73 | func TestEmailLoginResolvesVerifiedSecondary(t *testing.T) { | 74 | func TestEmailLoginResolvesVerifiedSecondary(t *testing.T) { |
| 75 | t.Parallel() | ||
| 74 | smtp := startFakeSMTP(t) | 76 | smtp := startFakeSMTP(t) |
| 75 | inst := startInstanceWith(t, fmt.Sprintf( | 77 | inst := startInstanceWith(t, fmt.Sprintf( |
| 76 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 78 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
| @@ -108,6 +110,7 @@ func TestEmailLoginResolvesVerifiedSecondary(t *testing.T) { | |||
| 108 | // The response must not say whether an account exists. A different status, | 110 | // The response must not say whether an account exists. A different status, |
| 109 | // body, or destination answers "is this person here?" to anyone who asks. | 111 | // body, or destination answers "is this person here?" to anyone who asks. |
| 110 | func TestEmailLoginDoesNotEnumerate(t *testing.T) { | 112 | func TestEmailLoginDoesNotEnumerate(t *testing.T) { |
| 113 | t.Parallel() | ||
| 111 | smtp := startFakeSMTP(t) | 114 | smtp := startFakeSMTP(t) |
| 112 | inst := startInstanceWith(t, fmt.Sprintf( | 115 | inst := startInstanceWith(t, fmt.Sprintf( |
| 113 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 116 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
| @@ -175,6 +178,7 @@ func TestEmailLoginDoesNotEnumerate(t *testing.T) { | |||
| 175 | // An anonymous endpoint that sends mail needs a durable per-account bound, | 178 | // An anonymous endpoint that sends mail needs a durable per-account bound, |
| 176 | // the same one email verification has (#136). | 179 | // the same one email verification has (#136). |
| 177 | func TestEmailLoginThrottled(t *testing.T) { | 180 | func TestEmailLoginThrottled(t *testing.T) { |
| 181 | t.Parallel() | ||
| 178 | smtp := startFakeSMTP(t) | 182 | smtp := startFakeSMTP(t) |
| 179 | inst := startInstanceWith(t, fmt.Sprintf( | 183 | inst := startInstanceWith(t, fmt.Sprintf( |
| 180 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 184 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
| @@ -220,6 +224,7 @@ func TestEmailLoginThrottled(t *testing.T) { | |||
| 220 | // itself a link. It must not get a session out of it: read access to the | 224 | // itself a link. It must not get a session out of it: read access to the |
| 221 | // private repos it is a member of is what suspension takes away. | 225 | // private repos it is a member of is what suspension takes away. |
| 222 | func TestEmailLoginRefusesDisabledAccount(t *testing.T) { | 226 | func TestEmailLoginRefusesDisabledAccount(t *testing.T) { |
| 227 | t.Parallel() | ||
| 223 | smtp := startFakeSMTP(t) | 228 | smtp := startFakeSMTP(t) |
| 224 | inst := startInstanceWith(t, fmt.Sprintf( | 229 | inst := startInstanceWith(t, fmt.Sprintf( |
| 225 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 230 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
| @@ -256,6 +261,7 @@ func TestEmailLoginRefusesDisabledAccount(t *testing.T) { | |||
| 256 | // login tokens, and login() refuses a disabled account after consuming one, | 261 | // login tokens, and login() refuses a disabled account after consuming one, |
| 257 | // so neither the window nor a token that somehow survives it opens a session. | 262 | // so neither the window nor a token that somehow survives it opens a session. |
| 258 | func TestEmailLoginRefusesLinkMintedBeforeSuspension(t *testing.T) { | 263 | func TestEmailLoginRefusesLinkMintedBeforeSuspension(t *testing.T) { |
| 264 | t.Parallel() | ||
| 259 | smtp := startFakeSMTP(t) | 265 | smtp := startFakeSMTP(t) |
| 260 | inst := startInstanceWith(t, fmt.Sprintf( | 266 | inst := startInstanceWith(t, fmt.Sprintf( |
| 261 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 267 | "[web]\nmode = \"accounts\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
e2e/emailremove_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // store holds: the primary stays until another is primary, and the last | 11 | // store holds: the primary stays until another is primary, and the last |
| 12 | // verified address stays (#181). | 12 | // verified address stays (#181). |
| 13 | func TestEmailRemoveAndPrimary(t *testing.T) { | 13 | func TestEmailRemoveAndPrimary(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | smtp := startFakeSMTP(t) | 15 | smtp := startFakeSMTP(t) |
| 15 | inst := startInstanceWith(t, fmt.Sprintf( | 16 | inst := startInstanceWith(t, fmt.Sprintf( |
| 16 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 17 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
e2e/emailthrottle_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // rate-limited; this path was not, so an authenticated account could | 10 | // rate-limited; this path was not, so an authenticated account could |
| 11 | // enqueue mail without bound (#136). | 11 | // enqueue mail without bound (#136). |
| 12 | func TestEmailAddThrottled(t *testing.T) { | 12 | func TestEmailAddThrottled(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | smtp := startFakeSMTP(t) | 14 | smtp := startFakeSMTP(t) |
| 14 | inst := startInstanceWith(t, fmt.Sprintf( | 15 | inst := startInstanceWith(t, fmt.Sprintf( |
| 15 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 16 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
e2e/facts_test.go +2
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // TestRepoFacts covers the repository summary: counts, license, languages, | 12 | // TestRepoFacts covers the repository summary: counts, license, languages, |
| 13 | // and contributors resolved to accounts where the email is verified. | 13 | // and contributors resolved to accounts where the email is verified. |
| 14 | func TestRepoFacts(t *testing.T) { | 14 | func TestRepoFacts(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", | 18 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -102,6 +103,7 @@ WITH REGARD TO THIS SOFTWARE. | |||
| 102 | // account has verified here. Addresses with neither stay distinct, even | 103 | // account has verified here. Addresses with neither stay distinct, even |
| 103 | // when they carry the same name. | 104 | // when they carry the same name. |
| 104 | func TestContributorIdentity(t *testing.T) { | 105 | func TestContributorIdentity(t *testing.T) { |
| 106 | t.Parallel() | ||
| 105 | smtp := startFakeSMTP(t) | 107 | smtp := startFakeSMTP(t) |
| 106 | inst := startInstanceWith(t, fmt.Sprintf( | 108 | inst := startInstanceWith(t, fmt.Sprintf( |
| 107 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 109 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
e2e/feeds_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // Atom feeds for releases, commits and an owner's public activity, read | 11 | // Atom feeds for releases, commits and an owner's public activity, read |
| 12 | // with no session; private repositories stay out of them (#192). | 12 | // with no session; private repositories stay out of them (#192). |
| 13 | func TestAtomFeeds(t *testing.T) { | 13 | func TestAtomFeeds(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/filenav_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // A file page lists its directory beside the file, marks the file, and | 10 | // A file page lists its directory beside the file, marks the file, and |
| 11 | // links up (desktop layout spec). | 11 | // links up (desktop layout spec). |
| 12 | func TestFileNavigator(t *testing.T) { | 12 | func TestFileNavigator(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 14 | key := inst.newKey(t, "alice") | 15 | key := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") | 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") |
e2e/forkweb_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // file in the fork, open the merge request against the parent, without a | 12 | // file in the fork, open the merge request against the parent, without a |
| 13 | // terminal at any step (#174). | 13 | // terminal at any step (#174). |
| 14 | func TestForkWeb(t *testing.T) { | 14 | func TestForkWeb(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | bobKey := inst.newKey(t, "bob") | 18 | bobKey := inst.newKey(t, "bob") |
e2e/formatpickerweb_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // request create forms (#160). Neither form offered --format before; a | 12 | // request create forms (#160). Neither form offered --format before; a |
| 13 | // browser session could only ever write markdown. | 13 | // browser session could only ever write markdown. |
| 14 | func TestIssueMRWebFormat(t *testing.T) { | 14 | func TestIssueMRWebFormat(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", | 18 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/gates_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // unmet gate at once, and mr review says when a verdict is advisory | 11 | // unmet gate at once, and mr review says when a verdict is advisory |
| 12 | // (#199). | 12 | // (#199). |
| 13 | func TestMergeGatesVisible(t *testing.T) { | 13 | func TestMergeGatesVisible(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
e2e/ghimport_test.go +3
| @@ -72,6 +72,7 @@ func fakeGitHub(t *testing.T) *httptest.Server { | |||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | func TestGitHubIssueImport(t *testing.T) { | 74 | func TestGitHubIssueImport(t *testing.T) { |
| 75 | t.Parallel() | ||
| 75 | // allow_local lets --api-base reach the loopback fake; a default | 76 | // allow_local lets --api-base reach the loopback fake; a default |
| 76 | // instance refuses it (see the SSRF check at the end). | 77 | // instance refuses it (see the SSRF check at the end). |
| 77 | inst := startInstanceWith(t, "[webhooks]\nallow_local = true\n") | 78 | inst := startInstanceWith(t, "[webhooks]\nallow_local = true\n") |
| @@ -143,6 +144,7 @@ func TestGitHubIssueImport(t *testing.T) { | |||
| 143 | } | 144 | } |
| 144 | 145 | ||
| 145 | func TestGitHubImportSSRFGuard(t *testing.T) { | 146 | func TestGitHubImportSSRFGuard(t *testing.T) { |
| 147 | t.Parallel() | ||
| 146 | inst := startInstance(t) // allow_local off: default posture | 148 | inst := startInstance(t) // allow_local off: default posture |
| 147 | aliceKey := inst.newKey(t, "alice") | 149 | aliceKey := inst.newKey(t, "alice") |
| 148 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 150 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -219,6 +221,7 @@ func fakeForgejo(t *testing.T) *httptest.Server { | |||
| 219 | } | 221 | } |
| 220 | 222 | ||
| 221 | func TestForgejoIssueImport(t *testing.T) { | 223 | func TestForgejoIssueImport(t *testing.T) { |
| 224 | t.Parallel() | ||
| 222 | inst := startInstanceWith(t, "[webhooks]\nallow_local = true\n") | 225 | inst := startInstanceWith(t, "[webhooks]\nallow_local = true\n") |
| 223 | aliceKey := inst.newKey(t, "alice") | 226 | aliceKey := inst.newKey(t, "alice") |
| 224 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 227 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/git_test.go +1
| @@ -55,6 +55,7 @@ func mustGit(t *testing.T, dir string, env []string, args ...string) string { | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | func TestGitOverSSH(t *testing.T) { | 57 | func TestGitOverSSH(t *testing.T) { |
| 58 | t.Parallel() | ||
| 58 | inst := startInstance(t) | 59 | inst := startInstance(t) |
| 59 | 60 | ||
| 60 | aliceKey := inst.newKey(t, "alice") | 61 | aliceKey := inst.newKey(t, "alice") |
e2e/goimport_test.go +1
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | func TestGoImportVanity(t *testing.T) { | 8 | func TestGoImportVanity(t *testing.T) { |
| 9 | t.Parallel() | ||
| 9 | inst := startInstanceWith(t, "[go_import]\n\"127.0.0.1/tool\" = \"alice/tool\"\n") | 10 | inst := startInstanceWith(t, "[go_import]\n\"127.0.0.1/tool\" = \"alice/tool\"\n") |
| 10 | aliceKey := inst.newKey(t, "alice") | 11 | aliceKey := inst.newKey(t, "alice") |
| 11 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 12 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/http_test.go +2
| @@ -64,6 +64,7 @@ func (i *instance) httpURL(repo string) string { | |||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | func TestHTTPTransport(t *testing.T) { | 66 | func TestHTTPTransport(t *testing.T) { |
| 67 | t.Parallel() | ||
| 67 | inst := startInstance(t) | 68 | inst := startInstance(t) |
| 68 | aliceKey := setupPublicRepo(t, inst, "alice/pub") | 69 | aliceKey := setupPublicRepo(t, inst, "alice/pub") |
| 69 | 70 | ||
| @@ -127,6 +128,7 @@ func TestHTTPTransport(t *testing.T) { | |||
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | func TestGitDaemon(t *testing.T) { | 130 | func TestGitDaemon(t *testing.T) { |
| 131 | t.Parallel() | ||
| 130 | inst := startInstance(t) | 132 | inst := startInstance(t) |
| 131 | aliceKey := setupPublicRepo(t, inst, "alice/pub") | 133 | aliceKey := setupPublicRepo(t, inst, "alice/pub") |
| 132 | gitURL := func(repo string) string { | 134 | gitURL := func(repo string) string { |
e2e/import_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestRepoImport(t *testing.T) { | 11 | func TestRepoImport(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | inst.admin(t, "admin", "user", "create", "alice", | 15 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/inbox_test.go +1
| @@ -41,6 +41,7 @@ func notices(t *testing.T, inst *instance, key string, args ...string) []struct | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | func TestNotificationInbox(t *testing.T) { | 43 | func TestNotificationInbox(t *testing.T) { |
| 44 | t.Parallel() | ||
| 44 | inst := startInstance(t) | 45 | inst := startInstance(t) |
| 45 | 46 | ||
| 46 | aliceKey := inst.newKey(t, "alice") | 47 | aliceKey := inst.newKey(t, "alice") |
e2e/isolation_podman_test.go +5
| @@ -46,6 +46,7 @@ func havePodman(t *testing.T) bool { | |||
| 46 | // the runner refuses to start rather than running a build on the host. | 46 | // the runner refuses to start rather than running a build on the host. |
| 47 | // This one needs no podman, so it runs everywhere. | 47 | // This one needs no podman, so it runs everywhere. |
| 48 | func TestRunnerRefusesToStartWithoutPodman(t *testing.T) { | 48 | func TestRunnerRefusesToStartWithoutPodman(t *testing.T) { |
| 49 | t.Parallel() | ||
| 49 | bin := buildRunner(t) | 50 | bin := buildRunner(t) |
| 50 | cmd := exec.Command(bin, "-once", "-remote", "git@127.0.0.1", | 51 | cmd := exec.Command(bin, "-once", "-remote", "git@127.0.0.1", |
| 51 | "-isolation", "podman", "-image", "localhost/whatever:1", "-workdir", t.TempDir()) | 52 | "-isolation", "podman", "-image", "localhost/whatever:1", "-workdir", t.TempDir()) |
| @@ -66,6 +67,7 @@ func TestRunnerRefusesToStartWithoutPodman(t *testing.T) { | |||
| 66 | 67 | ||
| 67 | // An unknown mode is refused rather than guessed at. | 68 | // An unknown mode is refused rather than guessed at. |
| 68 | func TestRunnerRefusesUnknownIsolation(t *testing.T) { | 69 | func TestRunnerRefusesUnknownIsolation(t *testing.T) { |
| 70 | t.Parallel() | ||
| 69 | bin := buildRunner(t) | 71 | bin := buildRunner(t) |
| 70 | cmd := exec.Command(bin, "-once", "-remote", "git@127.0.0.1", | 72 | cmd := exec.Command(bin, "-once", "-remote", "git@127.0.0.1", |
| 71 | "-isolation", "chroot", "-workdir", t.TempDir()) | 73 | "-isolation", "chroot", "-workdir", t.TempDir()) |
| @@ -81,6 +83,7 @@ func TestRunnerRefusesUnknownIsolation(t *testing.T) { | |||
| 81 | // With podman, a step runs in a container: it cannot read the runner's | 83 | // With podman, a step runs in a container: it cannot read the runner's |
| 82 | // SSH key, and it does not see the runner's home. | 84 | // SSH key, and it does not see the runner's home. |
| 83 | func TestPodmanStepCannotReachTheRunnersKey(t *testing.T) { | 85 | func TestPodmanStepCannotReachTheRunnersKey(t *testing.T) { |
| 86 | t.Parallel() | ||
| 84 | if !havePodman(t) { | 87 | if !havePodman(t) { |
| 85 | t.Skip("no podman") | 88 | t.Skip("no podman") |
| 86 | } | 89 | } |
| @@ -131,6 +134,7 @@ func TestPodmanStepCannotReachTheRunnersKey(t *testing.T) { | |||
| 131 | // An image this runner does not have fails the build and says an | 134 | // An image this runner does not have fails the build and says an |
| 132 | // operator must provision it, rather than pulling it. | 135 | // operator must provision it, rather than pulling it. |
| 133 | func TestPodmanMissingImageFailsTheBuild(t *testing.T) { | 136 | func TestPodmanMissingImageFailsTheBuild(t *testing.T) { |
| 137 | t.Parallel() | ||
| 134 | if !havePodman(t) { | 138 | if !havePodman(t) { |
| 135 | t.Skip("no podman") | 139 | t.Skip("no podman") |
| 136 | } | 140 | } |
| @@ -192,6 +196,7 @@ func runnerPodmanOnce(t *testing.T, inst *instance, key string) { | |||
| 192 | // guessing one: with --pull=never an image the host does not have fails | 196 | // guessing one: with --pull=never an image the host does not have fails |
| 193 | // every job that names none. | 197 | // every job that names none. |
| 194 | func TestRunnerRefusesPodmanWithoutAnImage(t *testing.T) { | 198 | func TestRunnerRefusesPodmanWithoutAnImage(t *testing.T) { |
| 199 | t.Parallel() | ||
| 195 | bin := buildRunner(t) | 200 | bin := buildRunner(t) |
| 196 | cmd := exec.Command(bin, "-once", "-remote", "git@127.0.0.1", | 201 | cmd := exec.Command(bin, "-once", "-remote", "git@127.0.0.1", |
| 197 | "-isolation", "podman", "-workdir", t.TempDir()) | 202 | "-isolation", "podman", "-workdir", t.TempDir()) |
e2e/isolation_test.go +1
| @@ -19,6 +19,7 @@ import ( | |||
| 19 | // of surfaces is the thing under test, so adding a route without adding | 19 | // of surfaces is the thing under test, so adding a route without adding |
| 20 | // it here is the omission that shows up. | 20 | // it here is the omission that shows up. |
| 21 | func TestPrivateRepoIsInvisible(t *testing.T) { | 21 | func TestPrivateRepoIsInvisible(t *testing.T) { |
| 22 | t.Parallel() | ||
| 22 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 23 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 23 | ownerKey := inst.newKey(t, "owner") | 24 | ownerKey := inst.newKey(t, "owner") |
| 24 | strangerKey := inst.newKey(t, "stranger") | 25 | strangerKey := inst.newKey(t, "stranger") |
e2e/issue_test.go +1
| @@ -24,6 +24,7 @@ func golden(t *testing.T, raw string) string { | |||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | func TestIssueLifecycleOverBareSSH(t *testing.T) { | 26 | func TestIssueLifecycleOverBareSSH(t *testing.T) { |
| 27 | t.Parallel() | ||
| 27 | inst := startInstance(t) | 28 | inst := startInstance(t) |
| 28 | 29 | ||
| 29 | aliceKey := inst.newKey(t, "alice") | 30 | aliceKey := inst.newKey(t, "alice") |
e2e/issuesearch_test.go +1
| @@ -29,6 +29,7 @@ func issueNumbers(t *testing.T, inst *instance, key string, args ...string) []in | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | func TestIssueSearch(t *testing.T) { | 31 | func TestIssueSearch(t *testing.T) { |
| 32 | t.Parallel() | ||
| 32 | inst := startInstance(t) | 33 | inst := startInstance(t) |
| 33 | aliceKey := inst.newKey(t, "alice") | 34 | aliceKey := inst.newKey(t, "alice") |
| 34 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 35 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/issueweb_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // the browser. Each action runs the issue command the CLI runs, so the | 10 | // the browser. Each action runs the issue command the CLI runs, so the |
| 11 | // CLI is the check that they took effect. | 11 | // CLI is the check that they took effect. |
| 12 | func TestIssueWebTriage(t *testing.T) { | 12 | func TestIssueWebTriage(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/label_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | // Labels get colours: set from the CLI, listed with their use, painted | 8 | // Labels get colours: set from the CLI, listed with their use, painted |
| 9 | // on the web, and removed from every issue at once. | 9 | // on the web, and removed from every issue at once. |
| 10 | func TestLabelColors(t *testing.T) { | 10 | func TestLabelColors(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/labelweb_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // The label set itself is managed from the browser: create, recolour and | 9 | // The label set itself is managed from the browser: create, recolour and |
| 10 | // remove, each through the label command the CLI runs (#163). | 10 | // remove, each through the label command the CLI runs (#163). |
| 11 | func TestLabelsWeb(t *testing.T) { | 11 | func TestLabelsWeb(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | bobKey := inst.newKey(t, "bob") | 15 | bobKey := inst.newKey(t, "bob") |
e2e/lfs_test.go +1
| @@ -34,6 +34,7 @@ func waitForPort(t *testing.T, port int) { | |||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | func TestLFS(t *testing.T) { | 36 | func TestLFS(t *testing.T) { |
| 37 | t.Parallel() | ||
| 37 | if _, err := exec.LookPath("git-lfs"); err != nil { | 38 | if _, err := exec.LookPath("git-lfs"); err != nil { |
| 38 | t.Skip("git-lfs client not installed") | 39 | t.Skip("git-lfs client not installed") |
| 39 | } | 40 | } |
e2e/listfilters_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // issue list and mr list narrow by label, assignee, author and | 10 | // issue list and mr list narrow by label, assignee, author and |
| 11 | // milestone, and the web lists take the same names as query parameters. | 11 | // milestone, and the web lists take the same names as query parameters. |
| 12 | func TestListFilters(t *testing.T) { | 12 | func TestListFilters(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/mailpref_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // mail; on brings it back. The account page carries the same switch | 12 | // mail; on brings it back. The account page carries the same switch |
| 13 | // (#194). | 13 | // (#194). |
| 14 | func TestMailPreference(t *testing.T) { | 14 | func TestMailPreference(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | smtp := startFakeSMTP(t) | 16 | smtp := startFakeSMTP(t) |
| 16 | inst := startInstanceWith(t, fmt.Sprintf( | 17 | inst := startInstanceWith(t, fmt.Sprintf( |
| 17 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n[web]\nmode = \"accounts\"\n", smtp.addr)) | 18 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n[web]\nmode = \"accounts\"\n", smtp.addr)) |
e2e/main_test.go +8 −28
| @@ -1,39 +1,19 @@ | |||
| 1 | package e2e | 1 | package e2e |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "flag" | ||
| 5 | "fmt" | 4 | "fmt" |
| 6 | "os" | 5 | "os" |
| 7 | "testing" | 6 | "testing" |
| 8 | "time" | ||
| 9 | ) | 7 | ) |
| 10 | 8 | ||
| 11 | // This suite drives real git, ssh, sshd and gpg, and takes six to fifteen | ||
| 12 | // minutes depending on the machine — past `go test`'s ten-minute default. | ||
| 13 | // Exceeding it panics with the name of whichever test happened to be | ||
| 14 | // running, which is never the one at fault and reads like a hang (#143). | ||
| 15 | // | ||
| 16 | // make test passes -timeout 30m and .gitbay/ci.yml passes -timeout 20m. | ||
| 17 | // A bare `go test ./...` gets the default, so say so up front rather than | ||
| 18 | // eleven minutes later. | ||
| 19 | const minTimeout = 15 * time.Minute | ||
| 20 | |||
| 21 | func TestMain(m *testing.M) { | 9 | func TestMain(m *testing.M) { |
| 22 | flag.Parse() | 10 | dir, cleanup, err := makeBinDir() |
| 23 | // Only for a whole-package run: `-run TestOneThing -timeout 2m` is a | 11 | if err != nil { |
| 24 | // reasonable thing to type and none of this applies to it. | 12 | fmt.Fprintf(os.Stderr, "e2e: %v\n", err) |
| 25 | if run := flag.Lookup("test.run"); run == nil || run.Value.String() == "" { | 13 | os.Exit(1) |
| 26 | if f := flag.Lookup("test.timeout"); f != nil { | ||
| 27 | d, err := time.ParseDuration(f.Value.String()) | ||
| 28 | if err == nil && d > 0 && d < minTimeout { | ||
| 29 | fmt.Fprintf(os.Stderr, | ||
| 30 | "e2e: -timeout is %s; this suite needs about %s.\n"+ | ||
| 31 | "Run `make test` (which passes -timeout 30m), or pass -timeout yourself.\n"+ | ||
| 32 | "Without this check the run panics part way through and blames whichever\n"+ | ||
| 33 | "test was executing at the deadline.\n", d, minTimeout) | ||
| 34 | os.Exit(1) | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | 14 | } |
| 38 | os.Exit(m.Run()) | 15 | binDir = dir |
| 16 | code := m.Run() | ||
| 17 | cleanup() | ||
| 18 | os.Exit(code) | ||
| 39 | } | 19 | } |
e2e/maint_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestAdminGCAndStats(t *testing.T) { | 11 | func TestAdminGCAndStats(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/mentions_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // mute holds, and someone who cannot read the repository is not reached | 10 | // mute holds, and someone who cannot read the repository is not reached |
| 11 | // (#202). | 11 | // (#202). |
| 12 | func TestMentionsNotify(t *testing.T) { | 12 | func TestMentionsNotify(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | keys := map[string]string{} | 15 | keys := map[string]string{} |
| 15 | for _, u := range []string{"alice", "bob", "carol", "eve"} { | 16 | for _, u := range []string{"alice", "bob", "carol", "eve"} { |
e2e/merge_strategies_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestSquashAndRebaseMerges(t *testing.T) { | 10 | func TestSquashAndRebaseMerges(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/mergerecord_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // or a merge moved the ref and then failed to record itself. Either way | 12 | // or a merge moved the ref and then failed to record itself. Either way |
| 13 | // refusing left the merge request open for good (#108). | 13 | // refusing left the merge request open for good (#108). |
| 14 | func TestMergeRecordedWhenTargetContainsHead(t *testing.T) { | 14 | func TestMergeRecordedWhenTargetContainsHead(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 18 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/migrate_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestAccountMigration(t *testing.T) { | 10 | func TestAccountMigration(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | src := startInstance(t) | 12 | src := startInstance(t) |
| 12 | dst := startInstance(t) | 13 | dst := startInstance(t) |
| 13 | key := src.newKey(t, "alice") // one identity, both instances | 14 | key := src.newKey(t, "alice") // one identity, both instances |
e2e/migratemr_test.go +1
| @@ -17,6 +17,7 @@ import ( | |||
| 17 | // diff resolves through it and an empty head_sha is invisible — the first | 17 | // diff resolves through it and an empty head_sha is invisible — the first |
| 18 | // version of this test made that mistake and passed without the fix. | 18 | // version of this test made that mistake and passed without the fix. |
| 19 | func TestMigratedMRHasADiff(t *testing.T) { | 19 | func TestMigratedMRHasADiff(t *testing.T) { |
| 20 | t.Parallel() | ||
| 20 | src := startInstance(t) | 21 | src := startInstance(t) |
| 21 | dst := startInstance(t) | 22 | dst := startInstance(t) |
| 22 | key := src.newKey(t, "alice") | 23 | key := src.newKey(t, "alice") |
e2e/milestone_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestMilestonesAndTemplates(t *testing.T) { | 11 | func TestMilestonesAndTemplates(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | bobKey := inst.newKey(t, "bob") | 15 | bobKey := inst.newKey(t, "bob") |
e2e/mirror_test.go +1
| @@ -186,6 +186,7 @@ func TestMirrors(t *testing.T) { | |||
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | func TestMirrorSSRFGuard(t *testing.T) { | 188 | func TestMirrorSSRFGuard(t *testing.T) { |
| 189 | t.Parallel() | ||
| 189 | inst := startInstance(t) // default posture: allow_local off | 190 | inst := startInstance(t) // default posture: allow_local off |
| 190 | aliceKey := inst.newKey(t, "alice") | 191 | aliceKey := inst.newKey(t, "alice") |
| 191 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 192 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/mr_test.go +1
| @@ -46,6 +46,7 @@ func (i *instance) mrShow(t *testing.T, key, repo, n string) mrShow { | |||
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | func TestMergeRequests(t *testing.T) { | 48 | func TestMergeRequests(t *testing.T) { |
| 49 | t.Parallel() | ||
| 49 | inst := startInstance(t) | 50 | inst := startInstance(t) |
| 50 | 51 | ||
| 51 | aliceKey := inst.newKey(t, "alice") | 52 | aliceKey := inst.newKey(t, "alice") |
e2e/mrbuilds_test.go +1
| @@ -16,6 +16,7 @@ import ( | |||
| 16 | // merge request unbuildable and, under require-checks, unmergeable (#98). | 16 | // merge request unbuildable and, under require-checks, unmergeable (#98). |
| 17 | // A head from another repository runs without the target's secrets. | 17 | // A head from another repository runs without the target's secrets. |
| 18 | func TestForkMRHeadIsBuilt(t *testing.T) { | 18 | func TestForkMRHeadIsBuilt(t *testing.T) { |
| 19 | t.Parallel() | ||
| 19 | inst := startInstance(t) | 20 | inst := startInstance(t) |
| 20 | inst.runner = buildRunner(t) | 21 | inst.runner = buildRunner(t) |
| 21 | aliceKey := inst.newKey(t, "alice") | 22 | aliceKey := inst.newKey(t, "alice") |
e2e/mrdraft_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // TestMRDraft covers the first stage of #111: a merge request opened to | 11 | // TestMRDraft covers the first stage of #111: a merge request opened to |
| 12 | // show work rather than to ask for a merge. | 12 | // show work rather than to ask for a merge. |
| 13 | func TestMRDraft(t *testing.T) { | 13 | func TestMRDraft(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
e2e/mrforkweb_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // the source picker offers the branches of a fork they can push to, and | 12 | // the source picker offers the branches of a fork they can push to, and |
| 13 | // the merge request opens against the parent (#168). | 13 | // the merge request opens against the parent (#168). |
| 14 | func TestMRFromForkWeb(t *testing.T) { | 14 | func TestMRFromForkWeb(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | bobKey := inst.newKey(t, "bob") | 18 | bobKey := inst.newKey(t, "bob") |
e2e/mrrebase_test.go +2
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | // server is never asked to vouch for a commit it did not receive already | 15 | // server is never asked to vouch for a commit it did not receive already |
| 16 | // signed (#175). | 16 | // signed (#175). |
| 17 | func TestCLIMRRebase(t *testing.T) { | 17 | func TestCLIMRRebase(t *testing.T) { |
| 18 | t.Parallel() | ||
| 18 | inst := startInstance(t) | 19 | inst := startInstance(t) |
| 19 | aliceKey := inst.newKey(t, "alice") | 20 | aliceKey := inst.newKey(t, "alice") |
| 20 | inst.admin(t, "admin", "user", "create", "alice", | 21 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -84,6 +85,7 @@ func TestCLIMRRebase(t *testing.T) { | |||
| 84 | 85 | ||
| 85 | // The guards: a dirty tree, and a source in a fork this clone cannot push. | 86 | // The guards: a dirty tree, and a source in a fork this clone cannot push. |
| 86 | func TestCLIMRRebaseRefusals(t *testing.T) { | 87 | func TestCLIMRRebaseRefusals(t *testing.T) { |
| 88 | t.Parallel() | ||
| 87 | inst := startInstance(t) | 89 | inst := startInstance(t) |
| 88 | aliceKey := inst.newKey(t, "alice") | 90 | aliceKey := inst.newKey(t, "alice") |
| 89 | bobKey := inst.newKey(t, "bob") | 91 | bobKey := inst.newKey(t, "bob") |
e2e/mrretarget_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // SSH and from the browser. Retargeting changes which diff a review was | 12 | // SSH and from the browser. Retargeting changes which diff a review was |
| 13 | // of, so the existing approvals have to go stale with it. | 13 | // of, so the existing approvals have to go stale with it. |
| 14 | func TestMRRetarget(t *testing.T) { | 14 | func TestMRRetarget(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | bobKey := inst.newKey(t, "bob") | 18 | bobKey := inst.newKey(t, "bob") |
e2e/mrweb_test.go +7
| @@ -37,6 +37,7 @@ func (i *instance) login(t *testing.T, key string) *http.Client { | |||
| 37 | // browser. Every action runs the same control command the CLI runs, so the | 37 | // browser. Every action runs the same control command the CLI runs, so the |
| 38 | // test also proves the merge gates apply to web merges. | 38 | // test also proves the merge gates apply to web merges. |
| 39 | func TestMRWebReviewLoop(t *testing.T) { | 39 | func TestMRWebReviewLoop(t *testing.T) { |
| 40 | t.Parallel() | ||
| 40 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 41 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 41 | aliceKey := inst.newKey(t, "alice") | 42 | aliceKey := inst.newKey(t, "alice") |
| 42 | bobKey := inst.newKey(t, "bob") | 43 | bobKey := inst.newKey(t, "bob") |
| @@ -182,6 +183,7 @@ func TestMRWebReviewLoop(t *testing.T) { | |||
| 182 | // TestMRWebCreate opens a merge request from the browser and checks the | 183 | // TestMRWebCreate opens a merge request from the browser and checks the |
| 183 | // form survives a refusal with the draft intact. | 184 | // form survives a refusal with the draft intact. |
| 184 | func TestMRWebCreate(t *testing.T) { | 185 | func TestMRWebCreate(t *testing.T) { |
| 186 | t.Parallel() | ||
| 185 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 187 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 186 | aliceKey := inst.newKey(t, "alice") | 188 | aliceKey := inst.newKey(t, "alice") |
| 187 | inst.admin(t, "admin", "user", "create", "alice", | 189 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -241,6 +243,7 @@ func TestMRWebCreate(t *testing.T) { | |||
| 241 | // TestMRListRows checks that the merge request list shows each row's | 243 | // TestMRListRows checks that the merge request list shows each row's |
| 242 | // combined check state and comment count (#230). | 244 | // combined check state and comment count (#230). |
| 243 | func TestMRListRows(t *testing.T) { | 245 | func TestMRListRows(t *testing.T) { |
| 246 | t.Parallel() | ||
| 244 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 247 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 245 | aliceKey := inst.newKey(t, "alice") | 248 | aliceKey := inst.newKey(t, "alice") |
| 246 | inst.admin(t, "admin", "user", "create", "alice", | 249 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -292,6 +295,7 @@ func TestMRListRows(t *testing.T) { | |||
| 292 | // proves the page dispatched mr diff-comment rather than writing its own | 295 | // proves the page dispatched mr diff-comment rather than writing its own |
| 293 | // rows. | 296 | // rows. |
| 294 | func TestMRWebDiffThreads(t *testing.T) { | 297 | func TestMRWebDiffThreads(t *testing.T) { |
| 298 | t.Parallel() | ||
| 295 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 299 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 296 | aliceKey := inst.newKey(t, "alice") | 300 | aliceKey := inst.newKey(t, "alice") |
| 297 | inst.admin(t, "admin", "user", "create", "alice", | 301 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -406,6 +410,7 @@ func (i *instance) mrThreads(t *testing.T, key, repo, n string) []mrThread { | |||
| 406 | // TestMRDiffEmptyExplained: a merge request whose head was fast-forwarded | 410 | // TestMRDiffEmptyExplained: a merge request whose head was fast-forwarded |
| 407 | // into the target outside the request shows why its diff is empty. | 411 | // into the target outside the request shows why its diff is empty. |
| 408 | func TestMRDiffEmptyExplained(t *testing.T) { | 412 | func TestMRDiffEmptyExplained(t *testing.T) { |
| 413 | t.Parallel() | ||
| 409 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 414 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 410 | key := inst.newKey(t, "alice") | 415 | key := inst.newKey(t, "alice") |
| 411 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub", "--email", "alice@example.test", "--verified") | 416 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub", "--email", "alice@example.test", "--verified") |
| @@ -442,6 +447,7 @@ func TestMRDiffEmptyExplained(t *testing.T) { | |||
| 442 | // web form, and checks both pages say so; clearing it over ssh removes | 447 | // web form, and checks both pages say so; clearing it over ssh removes |
| 443 | // both lines again (#223). | 448 | // both lines again (#223). |
| 444 | func TestMRSupersedes(t *testing.T) { | 449 | func TestMRSupersedes(t *testing.T) { |
| 450 | t.Parallel() | ||
| 445 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 451 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 446 | aliceKey := inst.newKey(t, "alice") | 452 | aliceKey := inst.newKey(t, "alice") |
| 447 | inst.admin(t, "admin", "user", "create", "alice", | 453 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -507,6 +513,7 @@ func TestMRSupersedes(t *testing.T) { | |||
| 507 | // list by it (#231). The CLI is the check that the page dispatched | 513 | // list by it (#231). The CLI is the check that the page dispatched |
| 508 | // mr label rather than writing its own rows. | 514 | // mr label rather than writing its own rows. |
| 509 | func TestMRWebLabels(t *testing.T) { | 515 | func TestMRWebLabels(t *testing.T) { |
| 516 | t.Parallel() | ||
| 510 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 517 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 511 | aliceKey := inst.newKey(t, "alice") | 518 | aliceKey := inst.newKey(t, "alice") |
| 512 | bobKey := inst.newKey(t, "bob") | 519 | bobKey := inst.newKey(t, "bob") |
e2e/notify_test.go +1
| @@ -39,6 +39,7 @@ func (f *fakeSMTP) waitFor(t *testing.T, recipient, substr string) string { | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | func TestActivityNotifications(t *testing.T) { | 41 | func TestActivityNotifications(t *testing.T) { |
| 42 | t.Parallel() | ||
| 42 | smtp := startFakeSMTP(t) | 43 | smtp := startFakeSMTP(t) |
| 43 | inst := startInstanceWith(t, fmt.Sprintf( | 44 | inst := startInstanceWith(t, fmt.Sprintf( |
| 44 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 45 | "[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
e2e/org_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestOrganizations(t *testing.T) { | 10 | func TestOrganizations(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/orgbody_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // without a format is markdown, which is what everything written before the | 10 | // without a format is markdown, which is what everything written before the |
| 11 | // format existed carries. | 11 | // format existed carries. |
| 12 | func TestOrgBodies(t *testing.T) { | 12 | func TestOrgBodies(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", | 16 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/orglabels_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // commit in one repository closes an issue in another; the org pages | 11 | // commit in one repository closes an issue in another; the org pages |
| 12 | // answer members and outsiders as their access allows. | 12 | // answer members and outsiders as their access allows. |
| 13 | func TestOrgLabelsMilestonesAndCrossRepoCloses(t *testing.T) { | 13 | func TestOrgLabelsMilestonesAndCrossRepoCloses(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | carolKey := inst.newKey(t, "carol") | 17 | carolKey := inst.newKey(t, "carol") |
e2e/orgremove_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // teams (#196). Before the fix, team_members rows survived removal, so a | 11 | // teams (#196). Before the fix, team_members rows survived removal, so a |
| 12 | // former member kept pushing. | 12 | // former member kept pushing. |
| 13 | func TestOrgMemberRemovalEndsTeamAccess(t *testing.T) { | 13 | func TestOrgMemberRemovalEndsTeamAccess(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
e2e/orgweb_test.go +2
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // membership and teams, admin-gated, dispatched through the same commands | 12 | // membership and teams, admin-gated, dispatched through the same commands |
| 13 | // the CLI uses. | 13 | // the CLI uses. |
| 14 | func TestOrgManagementWeb(t *testing.T) { | 14 | func TestOrgManagementWeb(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | bobKey := inst.newKey(t, "bob") | 18 | bobKey := inst.newKey(t, "bob") |
| @@ -157,6 +158,7 @@ func orgMembers(t *testing.T, inst *instance, key string) []string { | |||
| 157 | // rename from the org's. Delete stays on the CLI, where a typed | 158 | // rename from the org's. Delete stays on the CLI, where a typed |
| 158 | // confirmation is the norm (#167). | 159 | // confirmation is the norm (#167). |
| 159 | func TestOrgLifecycleWeb(t *testing.T) { | 160 | func TestOrgLifecycleWeb(t *testing.T) { |
| 161 | t.Parallel() | ||
| 160 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 162 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 161 | aliceKey := inst.newKey(t, "alice") | 163 | aliceKey := inst.newKey(t, "alice") |
| 162 | bobKey := inst.newKey(t, "bob") | 164 | bobKey := inst.newKey(t, "bob") |
e2e/pagination_test.go +1
| @@ -28,6 +28,7 @@ func decodePage[T any](t *testing.T, out string) ([]T, string) { | |||
| 28 | // Cursor pagination on the list commands: opaque cursors, stable pages, | 28 | // Cursor pagination on the list commands: opaque cursors, stable pages, |
| 29 | // and the bare-array shape untouched when the flags are absent. | 29 | // and the bare-array shape untouched when the flags are absent. |
| 30 | func TestCursorPagination(t *testing.T) { | 30 | func TestCursorPagination(t *testing.T) { |
| 31 | t.Parallel() | ||
| 31 | inst := startInstance(t) | 32 | inst := startInstance(t) |
| 32 | aliceKey := inst.newKey(t, "alice") | 33 | aliceKey := inst.newKey(t, "alice") |
| 33 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 34 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/pendingreview_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // review and submits it as a unit, instead of every comment landing in | 12 | // review and submits it as a unit, instead of every comment landing in |
| 13 | // the author's inbox the moment it is typed. | 13 | // the author's inbox the moment it is typed. |
| 14 | func TestPendingReviewBatch(t *testing.T) { | 14 | func TestPendingReviewBatch(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | authorKey := inst.newKey(t, "author") | 17 | authorKey := inst.newKey(t, "author") |
| 17 | reviewerKey := inst.newKey(t, "reviewer") | 18 | reviewerKey := inst.newKey(t, "reviewer") |
e2e/previewweb_test.go +1
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | // create, their edit and comment boxes, release create and edit, the | 13 | // create, their edit and comment boxes, release create and edit, the |
| 14 | // profile about text, and the file editor on a path the forge renders. | 14 | // profile about text, and the file editor on a path the forge renders. |
| 15 | func TestMarkupPreviewWeb(t *testing.T) { | 15 | func TestMarkupPreviewWeb(t *testing.T) { |
| 16 | t.Parallel() | ||
| 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 17 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 17 | aliceKey := inst.newKey(t, "alice") | 18 | aliceKey := inst.newKey(t, "alice") |
| 18 | inst.admin(t, "admin", "user", "create", "alice", | 19 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/profile_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestOwnerProfiles(t *testing.T) { | 10 | func TestOwnerProfiles(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/profileabout_test.go +4
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | // The about text is a file in <owner>/.gitbay, read on every surface with | 8 | // The about text is a file in <owner>/.gitbay, read on every surface with |
| 9 | // the reader's own access. | 9 | // the reader's own access. |
| 10 | func TestProfileAboutFromRepo(t *testing.T) { | 10 | func TestProfileAboutFromRepo(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | inst.admin(t, "admin", "user", "create", "alice", | 14 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -61,6 +62,7 @@ func TestProfileAboutFromRepo(t *testing.T) { | |||
| 61 | // The extension picks the format, .md wins the resolution order, and a | 62 | // The extension picks the format, .md wins the resolution order, and a |
| 62 | // private .gitbay keeps the about to the people who can read it. | 63 | // private .gitbay keeps the about to the people who can read it. |
| 63 | func TestProfileAboutFormatAndPrivacy(t *testing.T) { | 64 | func TestProfileAboutFormatAndPrivacy(t *testing.T) { |
| 65 | t.Parallel() | ||
| 64 | inst := startInstance(t) | 66 | inst := startInstance(t) |
| 65 | aliceKey := inst.newKey(t, "alice") | 67 | aliceKey := inst.newKey(t, "alice") |
| 66 | inst.admin(t, "admin", "user", "create", "alice", | 68 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -104,6 +106,7 @@ func TestProfileAboutFormatAndPrivacy(t *testing.T) { | |||
| 104 | // A dot-repo is infrastructure: it stays out of explore and off the | 106 | // A dot-repo is infrastructure: it stays out of explore and off the |
| 105 | // profile's repository list, and stays in the owner's own inventory. | 107 | // profile's repository list, and stays in the owner's own inventory. |
| 106 | func TestDotReposHiddenFromListings(t *testing.T) { | 108 | func TestDotReposHiddenFromListings(t *testing.T) { |
| 109 | t.Parallel() | ||
| 107 | inst := startInstance(t) | 110 | inst := startInstance(t) |
| 108 | aliceKey := inst.newKey(t, "alice") | 111 | aliceKey := inst.newKey(t, "alice") |
| 109 | inst.admin(t, "admin", "user", "create", "alice", | 112 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -140,6 +143,7 @@ func TestDotReposHiddenFromListings(t *testing.T) { | |||
| 140 | 143 | ||
| 141 | // The about is not settable through profile set any more: it is a file. | 144 | // The about is not settable through profile set any more: it is a file. |
| 142 | func TestProfileSetHasNoAbout(t *testing.T) { | 145 | func TestProfileSetHasNoAbout(t *testing.T) { |
| 146 | t.Parallel() | ||
| 143 | inst := startInstance(t) | 147 | inst := startInstance(t) |
| 144 | aliceKey := inst.newKey(t, "alice") | 148 | aliceKey := inst.newKey(t, "alice") |
| 145 | inst.admin(t, "admin", "user", "create", "alice", | 149 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/profileweb_test.go +2
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // emptying a field actually clears it rather than being skipped. The about | 11 | // emptying a field actually clears it rather than being skipped. The about |
| 12 | // text is not on this form — it is a file, covered below. | 12 | // text is not on this form — it is a file, covered below. |
| 13 | func TestProfileSettingsWeb(t *testing.T) { | 13 | func TestProfileSettingsWeb(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | inst.admin(t, "admin", "user", "create", "alice", | 17 | inst.admin(t, "admin", "user", "create", "alice", |
| @@ -98,6 +99,7 @@ func TestProfileSettingsWeb(t *testing.T) { | |||
| 98 | // The settings page does not edit the about text; it creates the | 99 | // The settings page does not edit the about text; it creates the |
| 99 | // repository that holds it and points at the file editor. | 100 | // repository that holds it and points at the file editor. |
| 100 | func TestProfileAboutRepoFromWeb(t *testing.T) { | 101 | func TestProfileAboutRepoFromWeb(t *testing.T) { |
| 102 | t.Parallel() | ||
| 101 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 103 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 102 | aliceKey := inst.newKey(t, "alice") | 104 | aliceKey := inst.newKey(t, "alice") |
| 103 | inst.admin(t, "admin", "user", "create", "alice", | 105 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/rangediff_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // nothing said what had changed between the two heads. A plain diff of | 12 | // nothing said what had changed between the two heads. A plain diff of |
| 13 | // the heads cannot answer that — it shows the whole branch again. | 13 | // the heads cannot answer that — it shows the whole branch again. |
| 14 | func TestMRRangeDiff(t *testing.T) { | 14 | func TestMRRangeDiff(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | key := inst.newKey(t, "alice") | 17 | key := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") | 18 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") |
e2e/readonly_test.go +1
| @@ -26,6 +26,7 @@ import ( | |||
| 26 | // Every ReadOnly command needs an entry in readArgs; a new one without | 26 | // Every ReadOnly command needs an entry in readArgs; a new one without |
| 27 | // arguments here fails the test rather than going untested. | 27 | // arguments here fails the test rather than going untested. |
| 28 | func TestReadOnlyCommandsWriteNothing(t *testing.T) { | 28 | func TestReadOnlyCommandsWriteNothing(t *testing.T) { |
| 29 | t.Parallel() | ||
| 29 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n[webhooks]\nallow_local = true\n") | 30 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n[webhooks]\nallow_local = true\n") |
| 30 | aliceKey := inst.newKey(t, "alice") | 31 | aliceKey := inst.newKey(t, "alice") |
| 31 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", | 32 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub", |
e2e/reap_test.go +4
| @@ -88,6 +88,7 @@ func TestStaleBuildReapedWithoutRunner(t *testing.T) { | |||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | func TestAdminRunners(t *testing.T) { | 90 | func TestAdminRunners(t *testing.T) { |
| 91 | t.Parallel() | ||
| 91 | inst := startInstance(t) | 92 | inst := startInstance(t) |
| 92 | rootKey := inst.newKey(t, "root") | 93 | rootKey := inst.newKey(t, "root") |
| 93 | aliceKey := inst.newKey(t, "alice") | 94 | aliceKey := inst.newKey(t, "alice") |
| @@ -152,6 +153,7 @@ func TestAdminRunners(t *testing.T) { | |||
| 152 | 153 | ||
| 153 | // /healthz is unauthenticated, cache-free, and says which build serves. | 154 | // /healthz is unauthenticated, cache-free, and says which build serves. |
| 154 | func TestHealthz(t *testing.T) { | 155 | func TestHealthz(t *testing.T) { |
| 156 | t.Parallel() | ||
| 155 | inst := startInstance(t) | 157 | inst := startInstance(t) |
| 156 | status, body := inst.get(t, "/healthz") | 158 | status, body := inst.get(t, "/healthz") |
| 157 | if status != 200 || !strings.Contains(body, `"ok":true`) || !strings.Contains(body, `"commit":"`) { | 159 | if status != 200 || !strings.Contains(body, `"ok":true`) || !strings.Contains(body, `"commit":"`) { |
| @@ -166,6 +168,7 @@ func TestHealthz(t *testing.T) { | |||
| 166 | // gc --lfs removes objects no pointer names, keeps referenced ones, and | 168 | // gc --lfs removes objects no pointer names, keeps referenced ones, and |
| 167 | // leaves anything young enough to be an upload ahead of its push. | 169 | // leaves anything young enough to be an upload ahead of its push. |
| 168 | func TestGCLFSOrphans(t *testing.T) { | 170 | func TestGCLFSOrphans(t *testing.T) { |
| 171 | t.Parallel() | ||
| 169 | inst := startInstance(t) | 172 | inst := startInstance(t) |
| 170 | aliceKey := inst.newKey(t, "alice") | 173 | aliceKey := inst.newKey(t, "alice") |
| 171 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 174 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -216,6 +219,7 @@ func TestGCLFSOrphans(t *testing.T) { | |||
| 216 | // backup --verify reads an archive back and says whether a restore would | 219 | // backup --verify reads an archive back and says whether a restore would |
| 217 | // have what the database expects. | 220 | // have what the database expects. |
| 218 | func TestBackupVerify(t *testing.T) { | 221 | func TestBackupVerify(t *testing.T) { |
| 222 | t.Parallel() | ||
| 219 | inst := startInstance(t) | 223 | inst := startInstance(t) |
| 220 | aliceKey := inst.newKey(t, "alice") | 224 | aliceKey := inst.newKey(t, "alice") |
| 221 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 225 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/registration_test.go +2
| @@ -111,6 +111,7 @@ func extractCode(t *testing.T, mail string) string { | |||
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | func TestOpenRegistration(t *testing.T) { | 113 | func TestOpenRegistration(t *testing.T) { |
| 114 | t.Parallel() | ||
| 114 | smtp := startFakeSMTP(t) | 115 | smtp := startFakeSMTP(t) |
| 115 | inst := startInstanceWith(t, fmt.Sprintf( | 116 | inst := startInstanceWith(t, fmt.Sprintf( |
| 116 | "[registration]\nmode = \"open\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 117 | "[registration]\nmode = \"open\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
| @@ -195,6 +196,7 @@ func TestOpenRegistration(t *testing.T) { | |||
| 195 | } | 196 | } |
| 196 | 197 | ||
| 197 | func TestInviteRegistration(t *testing.T) { | 198 | func TestInviteRegistration(t *testing.T) { |
| 199 | t.Parallel() | ||
| 198 | smtp := startFakeSMTP(t) | 200 | smtp := startFakeSMTP(t) |
| 199 | inst := startInstanceWith(t, fmt.Sprintf( | 201 | inst := startInstanceWith(t, fmt.Sprintf( |
| 200 | "[registration]\nmode = \"invite\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 202 | "[registration]\nmode = \"invite\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
e2e/release_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | ) | 10 | ) |
| 11 | 11 | ||
| 12 | func TestReleases(t *testing.T) { | 12 | func TestReleases(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/releaseweb_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // TestReleaseAndBuildWeb creates and edits a release and triggers a build | 11 | // TestReleaseAndBuildWeb creates and edits a release and triggers a build |
| 12 | // from the browser, each through the command the CLI runs. | 12 | // from the browser, each through the command the CLI runs. |
| 13 | func TestReleaseAndBuildWeb(t *testing.T) { | 13 | func TestReleaseAndBuildWeb(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 15 | inst.runner = buildRunner(t) | 16 | inst.runner = buildRunner(t) |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
e2e/reporename_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // repo rename moves the directory and the row together; what hangs off | 10 | // repo rename moves the directory and the row together; what hangs off |
| 11 | // the repository by id (issues here) follows it (#190). | 11 | // the repository by id (issues here) follows it (#190). |
| 12 | func TestRepoRename(t *testing.T) { | 12 | func TestRepoRename(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/reposhowstate_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // the caller can read it, what the repository was forked from — so a | 9 | // the caller can read it, what the repository was forked from — so a |
| 10 | // client draws the real state without a second read per screen (#178). | 10 | // client draws the real state without a second read per screen (#178). |
| 11 | func TestRepoShowCarriesViewerState(t *testing.T) { | 11 | func TestRepoShowCarriesViewerState(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstance(t) | 13 | inst := startInstance(t) |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | bobKey := inst.newKey(t, "bob") | 15 | bobKey := inst.newKey(t, "bob") |
e2e/requiremr_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // not exist yet can still be created, and unprotected branches are | 12 | // not exist yet can still be created, and unprotected branches are |
| 13 | // unaffected (#197). | 13 | // unaffected (#197). |
| 14 | func TestRequireMR(t *testing.T) { | 14 | func TestRequireMR(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstance(t) | 16 | inst := startInstance(t) |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", | 18 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/reviewcarry_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // A rebase that leaves the merge request's diff unchanged keeps its | 10 | // A rebase that leaves the merge request's diff unchanged keeps its |
| 11 | // fresh approvals; a push that changes the diff stales them (#198). | 11 | // fresh approvals; a push that changes the diff stales them (#198). |
| 12 | func TestApprovalsSurviveSameDiffRebase(t *testing.T) { | 12 | func TestApprovalsSurviveSameDiffRebase(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/reviewloop_test.go +1
| @@ -20,6 +20,7 @@ import ( | |||
| 20 | // exercised the loop end to end at all — every feature had its own test | 20 | // exercised the loop end to end at all — every feature had its own test |
| 21 | // and none of them met. | 21 | // and none of them met. |
| 22 | func TestTwoAccountReviewLoop(t *testing.T) { | 22 | func TestTwoAccountReviewLoop(t *testing.T) { |
| 23 | t.Parallel() | ||
| 23 | inst := startInstance(t) | 24 | inst := startInstance(t) |
| 24 | authorKey := inst.newKey(t, "author") | 25 | authorKey := inst.newKey(t, "author") |
| 25 | reviewerKey := inst.newKey(t, "reviewer") | 26 | reviewerKey := inst.newKey(t, "reviewer") |
e2e/reviewrequest_test.go +1
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | // and --remove takes them out outright. A separate, private repository | 13 | // and --remove takes them out outright. A separate, private repository |
| 14 | // checks that requesting someone who cannot read it is refused. | 14 | // checks that requesting someone who cannot read it is refused. |
| 15 | func TestMRReviewRequest(t *testing.T) { | 15 | func TestMRReviewRequest(t *testing.T) { |
| 16 | t.Parallel() | ||
| 16 | inst := startInstance(t) | 17 | inst := startInstance(t) |
| 17 | aliceKey := inst.newKey(t, "alice") | 18 | aliceKey := inst.newKey(t, "alice") |
| 18 | bobKey := inst.newKey(t, "bob") | 19 | bobKey := inst.newKey(t, "bob") |
e2e/reviewstanding_test.go +1
| @@ -20,6 +20,7 @@ import ( | |||
| 20 | // Reviewing stays open to everyone: an outside opinion on a public change | 20 | // Reviewing stays open to everyone: an outside opinion on a public change |
| 21 | // is worth having. It just does not decide the gate. | 21 | // is worth having. It just does not decide the gate. |
| 22 | func TestReviewsCountOnlyFromWriters(t *testing.T) { | 22 | func TestReviewsCountOnlyFromWriters(t *testing.T) { |
| 23 | t.Parallel() | ||
| 23 | inst := startInstance(t) | 24 | inst := startInstance(t) |
| 24 | ownerKey := inst.newKey(t, "owner") | 25 | ownerKey := inst.newKey(t, "owner") |
| 25 | writerKey := inst.newKey(t, "writer") | 26 | writerKey := inst.newKey(t, "writer") |
e2e/robustness_test.go +2
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | // tree, cat, grep, blame and the web blob page. Nothing in the suite | 15 | // tree, cat, grep, blame and the web blob page. Nothing in the suite |
| 16 | // covered a non-ASCII path before (#129). | 16 | // covered a non-ASCII path before (#129). |
| 17 | func TestNonASCIIPaths(t *testing.T) { | 17 | func TestNonASCIIPaths(t *testing.T) { |
| 18 | t.Parallel() | ||
| 18 | inst := startInstance(t) | 19 | inst := startInstance(t) |
| 19 | aliceKey := inst.newKey(t, "alice") | 20 | aliceKey := inst.newKey(t, "alice") |
| 20 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 21 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -62,6 +63,7 @@ func TestNonASCIIPaths(t *testing.T) { | |||
| 62 | // land: the receive hooks, the post-receive work and the store take | 63 | // land: the receive hooks, the post-receive work and the store take |
| 63 | // them concurrently without losing one (#129). | 64 | // them concurrently without losing one (#129). |
| 64 | func TestConcurrentPushes(t *testing.T) { | 65 | func TestConcurrentPushes(t *testing.T) { |
| 66 | t.Parallel() | ||
| 65 | inst := startInstance(t) | 67 | inst := startInstance(t) |
| 66 | aliceKey := inst.newKey(t, "alice") | 68 | aliceKey := inst.newKey(t, "alice") |
| 67 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 69 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/runner_scope_test.go +2
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | // that should only build one project ends up executing every repository's | 13 | // that should only build one project ends up executing every repository's |
| 14 | // steps — including those of a repository it has nothing to do with. | 14 | // steps — including those of a repository it has nothing to do with. |
| 15 | func TestRunnerNextScopedToRepos(t *testing.T) { | 15 | func TestRunnerNextScopedToRepos(t *testing.T) { |
| 16 | t.Parallel() | ||
| 16 | inst := startInstance(t) | 17 | inst := startInstance(t) |
| 17 | aliceKey := inst.newKey(t, "alice") | 18 | aliceKey := inst.newKey(t, "alice") |
| 18 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 19 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
| @@ -65,6 +66,7 @@ func TestRunnerNextScopedToRepos(t *testing.T) { | |||
| 65 | // same account's full key nor the runner key reaches the wrong side, so a | 66 | // same account's full key nor the runner key reaches the wrong side, so a |
| 66 | // key stolen from a build step cannot administer the instance (#92). | 67 | // key stolen from a build step cannot administer the instance (#92). |
| 67 | func TestRunnerScopedKey(t *testing.T) { | 68 | func TestRunnerScopedKey(t *testing.T) { |
| 69 | t.Parallel() | ||
| 68 | inst := startInstance(t) | 70 | inst := startInstance(t) |
| 69 | aliceKey := inst.newKey(t, "alice") | 71 | aliceKey := inst.newKey(t, "alice") |
| 70 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 72 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/runnerattach_test.go +1
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | // wrote. The runner builds their push and leaves a fork's merge request | 14 | // wrote. The runner builds their push and leaves a fork's merge request |
| 15 | // head alone until started with -untrusted. | 15 | // head alone until started with -untrusted. |
| 16 | func TestAttachedRunnerBuildsOwnRepo(t *testing.T) { | 16 | func TestAttachedRunnerBuildsOwnRepo(t *testing.T) { |
| 17 | t.Parallel() | ||
| 17 | inst := startInstance(t) | 18 | inst := startInstance(t) |
| 18 | inst.runner = buildRunner(t) | 19 | inst.runner = buildRunner(t) |
| 19 | aliceKey := inst.newKey(t, "alice") | 20 | aliceKey := inst.newKey(t, "alice") |
e2e/runnerstop_test.go +3
| @@ -79,6 +79,7 @@ func (i *instance) buildStatus(t *testing.T, key string) string { | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | func TestRunnerDrainsOnSIGTERM(t *testing.T) { | 81 | func TestRunnerDrainsOnSIGTERM(t *testing.T) { |
| 82 | t.Parallel() | ||
| 82 | inst, key := stopFixture(t) | 83 | inst, key := stopFixture(t) |
| 83 | cmd := exec.Command(inst.runner, inst.runnerArgs(t, key)...) | 84 | cmd := exec.Command(inst.runner, inst.runnerArgs(t, key)...) |
| 84 | cmd.Env = append(os.Environ(), "XDG_CONFIG_HOME="+t.TempDir(), "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null") | 85 | cmd.Env = append(os.Environ(), "XDG_CONFIG_HOME="+t.TempDir(), "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null") |
| @@ -137,6 +138,7 @@ func dropInValue(conf, key string) string { | |||
| 137 | // The unit must let the drain happen: the stop signal reaches the runner | 138 | // The unit must let the drain happen: the stop signal reaches the runner |
| 138 | // alone, and the stop timeout outlasts a build plus the report retries. | 139 | // alone, and the stop timeout outlasts a build plus the report retries. |
| 139 | func TestRunnerDropInLetsTheDrainHappen(t *testing.T) { | 140 | func TestRunnerDropInLetsTheDrainHappen(t *testing.T) { |
| 141 | t.Parallel() | ||
| 140 | conf := runnerDropIn(t) | 142 | conf := runnerDropIn(t) |
| 141 | if mode := dropInValue(conf, "KillMode"); mode != "mixed" { | 143 | if mode := dropInValue(conf, "KillMode"); mode != "mixed" { |
| 142 | t.Fatalf("KillMode=%q, want mixed: control-group signals the step and the log session with the runner", mode) | 144 | t.Fatalf("KillMode=%q, want mixed: control-group signals the step and the log session with the runner", mode) |
| @@ -173,6 +175,7 @@ func haveUserSystemd(t *testing.T) bool { | |||
| 173 | // KillMode the build in flight is reported a success; under systemd's | 175 | // KillMode the build in flight is reported a success; under systemd's |
| 174 | // default it is not, which is the failure that shipped once. | 176 | // default it is not, which is the failure that shipped once. |
| 175 | func TestRunnerDrainUnderSystemd(t *testing.T) { | 177 | func TestRunnerDrainUnderSystemd(t *testing.T) { |
| 178 | t.Parallel() | ||
| 176 | if !haveUserSystemd(t) { | 179 | if !haveUserSystemd(t) { |
| 177 | t.Skip("no systemd user manager") | 180 | t.Skip("no systemd user manager") |
| 178 | } | 181 | } |
e2e/runnerweb_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // The settings page attaches and detaches runners through the same | 10 | // The settings page attaches and detaches runners through the same |
| 11 | // commands the CLI uses, and lists what is attached. | 11 | // commands the CLI uses, and lists what is attached. |
| 12 | func TestRunnerSettingsWeb(t *testing.T) { | 12 | func TestRunnerSettingsWeb(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", | 16 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/search_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestSearch(t *testing.T) { | 10 | func TestSearch(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/searchweb_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // TestGlobalSearchAndNotificationsWeb covers the two web surfaces #118 | 9 | // TestGlobalSearchAndNotificationsWeb covers the two web surfaces #118 |
| 10 | // still lacked: /search across the instance, and the notification inbox. | 10 | // still lacked: /search across the instance, and the notification inbox. |
| 11 | func TestGlobalSearchAndNotificationsWeb(t *testing.T) { | 11 | func TestGlobalSearchAndNotificationsWeb(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | bobKey := inst.newKey(t, "bob") | 15 | bobKey := inst.newKey(t, "bob") |
e2e/security_test.go +1
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | ) | 7 | ) |
| 8 | 8 | ||
| 9 | func TestSecurityHeaders(t *testing.T) { | 9 | func TestSecurityHeaders(t *testing.T) { |
| 10 | t.Parallel() | ||
| 10 | inst := startInstance(t) | 11 | inst := startInstance(t) |
| 11 | aliceKey := inst.newKey(t, "alice") | 12 | aliceKey := inst.newKey(t, "alice") |
| 12 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 13 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/settingsweb_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // TestRepoSettingsWeb drives the settings page: each control runs the | 9 | // TestRepoSettingsWeb drives the settings page: each control runs the |
| 10 | // command the CLI runs, so repo show and settings show are the check. | 10 | // command the CLI runs, so repo show and settings show are the check. |
| 11 | func TestRepoSettingsWeb(t *testing.T) { | 11 | func TestRepoSettingsWeb(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 13 | aliceKey := inst.newKey(t, "alice") | 14 | aliceKey := inst.newKey(t, "alice") |
| 14 | bobKey := inst.newKey(t, "bob") | 15 | bobKey := inst.newKey(t, "bob") |
e2e/shutdown_test.go +2
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | // kill: no listener closed, no request or push allowed to finish. The | 15 | // kill: no listener closed, no request or push allowed to finish. The |
| 16 | // daemon now stops its listeners, drains, and exits 0 (#105). | 16 | // daemon now stops its listeners, drains, and exits 0 (#105). |
| 17 | func TestServeStopsOnSIGTERM(t *testing.T) { | 17 | func TestServeStopsOnSIGTERM(t *testing.T) { |
| 18 | t.Parallel() | ||
| 18 | inst := startInstance(t) | 19 | inst := startInstance(t) |
| 19 | if resp, err := http.Get(inst.base() + "/healthz"); err != nil || resp.StatusCode != 200 { | 20 | if resp, err := http.Get(inst.base() + "/healthz"); err != nil || resp.StatusCode != 200 { |
| 20 | t.Fatalf("healthz before shutdown: %v", err) | 21 | t.Fatalf("healthz before shutdown: %v", err) |
| @@ -41,6 +42,7 @@ func TestServeStopsOnSIGTERM(t *testing.T) { | |||
| 41 | // idle connection is closed at once rather than holding the drain for its | 42 | // idle connection is closed at once rather than holding the drain for its |
| 42 | // full 30 s; only a session mid-command is waited for (#141). | 43 | // full 30 s; only a session mid-command is waited for (#141). |
| 43 | func TestShutdownClosesIdleConnections(t *testing.T) { | 44 | func TestShutdownClosesIdleConnections(t *testing.T) { |
| 45 | t.Parallel() | ||
| 44 | inst := startInstance(t) | 46 | inst := startInstance(t) |
| 45 | aliceKey := inst.newKey(t, "alice") | 47 | aliceKey := inst.newKey(t, "alice") |
| 46 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 48 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/sig_test.go +1
| @@ -153,6 +153,7 @@ func (i *instance) repoLog(t *testing.T, key, repo string) map[string]logEntry { | |||
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | func TestSignatureVerification(t *testing.T) { | 155 | func TestSignatureVerification(t *testing.T) { |
| 156 | t.Parallel() | ||
| 156 | inst := startInstance(t) | 157 | inst := startInstance(t) |
| 157 | 158 | ||
| 158 | aliceKey := inst.newKey(t, "alice") | 159 | aliceKey := inst.newKey(t, "alice") |
e2e/signupnotice_test.go +2
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // becomes active. An open-mode signup counts at verification, not when | 11 | // becomes active. An open-mode signup counts at verification, not when |
| 12 | // the row is created, so an unverified attempt is silent (#234). | 12 | // the row is created, so an unverified attempt is silent (#234). |
| 13 | func TestSignupNotifiesAdmins(t *testing.T) { | 13 | func TestSignupNotifiesAdmins(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | smtp := startFakeSMTP(t) | 15 | smtp := startFakeSMTP(t) |
| 15 | inst := startInstanceWith(t, fmt.Sprintf( | 16 | inst := startInstanceWith(t, fmt.Sprintf( |
| 16 | "[registration]\nmode = \"open\"\nnotify_admin = true\n"+ | 17 | "[registration]\nmode = \"open\"\nnotify_admin = true\n"+ |
| @@ -45,6 +46,7 @@ func TestSignupNotifiesAdmins(t *testing.T) { | |||
| 45 | // With notify_admin off, the default, the same signup mails no one but | 46 | // With notify_admin off, the default, the same signup mails no one but |
| 46 | // the person registering. | 47 | // the person registering. |
| 47 | func TestSignupNoticeOffByDefault(t *testing.T) { | 48 | func TestSignupNoticeOffByDefault(t *testing.T) { |
| 49 | t.Parallel() | ||
| 48 | smtp := startFakeSMTP(t) | 50 | smtp := startFakeSMTP(t) |
| 49 | inst := startInstanceWith(t, fmt.Sprintf( | 51 | inst := startInstanceWith(t, fmt.Sprintf( |
| 50 | "[registration]\nmode = \"open\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) | 52 | "[registration]\nmode = \"open\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", smtp.addr)) |
e2e/snippet_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // Snippets over SSH: create from stdin, read back, list by visibility, | 10 | // Snippets over SSH: create from stdin, read back, list by visibility, |
| 11 | // edit files and metadata, and the not-found rule for private ones. | 11 | // edit files and metadata, and the not-found rule for private ones. |
| 12 | func TestSnippets(t *testing.T) { | 12 | func TestSnippets(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[limits]\nmax_snippets_per_user = 3\n") | 14 | inst := startInstanceWith(t, "[limits]\nmax_snippets_per_user = 3\n") |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/snippetweb_test.go +1
| @@ -24,6 +24,7 @@ func snippetIDFrom(t *testing.T, out string) string { | |||
| 24 | // Snippet pages: the owner's list, one snippet with highlighted files, the | 24 | // Snippet pages: the owner's list, one snippet with highlighted files, the |
| 25 | // raw route, the owner-page link, and 404 for what the viewer may not see. | 25 | // raw route, the owner-page link, and 404 for what the viewer may not see. |
| 26 | func TestSnippetsWeb(t *testing.T) { | 26 | func TestSnippetsWeb(t *testing.T) { |
| 27 | t.Parallel() | ||
| 27 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 28 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 28 | aliceKey := inst.newKey(t, "alice") | 29 | aliceKey := inst.newKey(t, "alice") |
| 29 | bobKey := inst.newKey(t, "bob") | 30 | bobKey := inst.newKey(t, "bob") |
e2e/ssh_test.go +34 −26
| @@ -4,11 +4,13 @@ package e2e | |||
| 4 | import ( | 4 | import ( |
| 5 | "encoding/json" | 5 | "encoding/json" |
| 6 | "fmt" | 6 | "fmt" |
| 7 | "math/rand/v2" | ||
| 7 | "net" | 8 | "net" |
| 8 | "os" | 9 | "os" |
| 9 | "os/exec" | 10 | "os/exec" |
| 10 | "path/filepath" | 11 | "path/filepath" |
| 11 | "strings" | 12 | "strings" |
| 13 | "sync/atomic" | ||
| 12 | "testing" | 14 | "testing" |
| 13 | ) | 15 | ) |
| 14 | 16 | ||
| @@ -24,40 +26,44 @@ type instance struct { | |||
| 24 | sshDir string // per-user client keys live here | 26 | sshDir string // per-user client keys live here |
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | func buildGitbayd(t *testing.T) string { | 29 | // nextPort hands out candidate ports. Seeded randomly so two test processes |
| 28 | t.Helper() | 30 | // on one machine — `go test ./...` runs packages concurrently — start in |
| 29 | bin := filepath.Join(t.TempDir(), "gitbayd") | 31 | // different places. |
| 30 | cmd := exec.Command("go", "build", "-o", bin, "gitbay.org/gitbay/cmd/gitbayd") | 32 | var nextPort = func() *atomic.Int32 { |
| 31 | cmd.Dir = ".." | 33 | var n atomic.Int32 |
| 32 | if out, err := cmd.CombinedOutput(); err != nil { | 34 | n.Store(int32(20000 + rand.IntN(20000))) |
| 33 | t.Fatalf("build gitbayd: %v\n%s", err, out) | 35 | return &n |
| 34 | } | 36 | }() |
| 35 | return bin | ||
| 36 | } | ||
| 37 | 37 | ||
| 38 | // freePorts reserves n distinct ports. A port is chosen by binding :0 and | 38 | // freePorts reserves n distinct ports, counting up rather than asking the |
| 39 | // reading back what the kernel assigned, so every listener has to stay open | 39 | // kernel for :0. |
| 40 | // until all of them are picked — closing one before picking the next lets | ||
| 41 | // the kernel hand out the same port again, and the instance that asked for | ||
| 42 | // three then fails to bind its second listener. | ||
| 43 | // | 40 | // |
| 44 | // Still a narrowing rather than a guarantee: another process can take a port | 41 | // :0 cannot be made safe once tests run in parallel. A port is picked by |
| 45 | // between the close here and the bind in gitbayd. Distinctness within one | 42 | // binding, reading the number back and closing, and between that close and |
| 46 | // instance is the part that is ours. | 43 | // the bind inside gitbayd the kernel is free to hand the same port to |
| 44 | // another instance picking at that moment. The loser does not fail | ||
| 45 | // cleanly: waitForPort only asks whether something is listening, so a test | ||
| 46 | // whose port was taken talks to a different test's server and reports | ||
| 47 | // whatever that one says. | ||
| 48 | // | ||
| 49 | // A counter cannot collide within a process, whatever the interleaving. | ||
| 50 | // Each candidate is still bind-tested, which skips ports other programs | ||
| 51 | // hold. An outside process taking one in the close-to-bind window remains | ||
| 52 | // possible, as it was before; that race is not ours to close. | ||
| 47 | func freePorts(t *testing.T, n int) []int { | 53 | func freePorts(t *testing.T, n int) []int { |
| 48 | t.Helper() | 54 | t.Helper() |
| 49 | lns := make([]net.Listener, 0, n) | ||
| 50 | ports := make([]int, 0, n) | 55 | ports := make([]int, 0, n) |
| 51 | for i := 0; i < n; i++ { | 56 | for len(ports) < n { |
| 52 | ln, err := net.Listen("tcp", "127.0.0.1:0") | 57 | p := int(nextPort.Add(1)) |
| 58 | if p > 60000 { | ||
| 59 | t.Fatal("ran out of ports") | ||
| 60 | } | ||
| 61 | ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", p)) | ||
| 53 | if err != nil { | 62 | if err != nil { |
| 54 | t.Fatal(err) | 63 | continue // somebody else has it |
| 55 | } | 64 | } |
| 56 | lns = append(lns, ln) | ||
| 57 | ports = append(ports, ln.Addr().(*net.TCPAddr).Port) | ||
| 58 | } | ||
| 59 | for _, ln := range lns { | ||
| 60 | ln.Close() | 65 | ln.Close() |
| 66 | ports = append(ports, p) | ||
| 61 | } | 67 | } |
| 62 | return ports | 68 | return ports |
| 63 | } | 69 | } |
| @@ -184,6 +190,7 @@ func (i *instance) ssh(t *testing.T, key string, stdin string, args ...string) ( | |||
| 184 | } | 190 | } |
| 185 | 191 | ||
| 186 | func TestControlPlaneOverBareSSH(t *testing.T) { | 192 | func TestControlPlaneOverBareSSH(t *testing.T) { |
| 193 | t.Parallel() | ||
| 187 | inst := startInstance(t) | 194 | inst := startInstance(t) |
| 188 | 195 | ||
| 189 | aliceKey := inst.newKey(t, "alice") | 196 | aliceKey := inst.newKey(t, "alice") |
| @@ -278,6 +285,7 @@ func TestControlPlaneOverBareSSH(t *testing.T) { | |||
| 278 | // a row and then fails to bind its second listener, which surfaces as an | 285 | // a row and then fails to bind its second listener, which surfaces as an |
| 279 | // unrelated test timing out on "gitbayd did not start listening". | 286 | // unrelated test timing out on "gitbayd did not start listening". |
| 280 | func TestFreePortsAreDistinct(t *testing.T) { | 287 | func TestFreePortsAreDistinct(t *testing.T) { |
| 288 | t.Parallel() | ||
| 281 | for round := 0; round < 50; round++ { | 289 | for round := 0; round < 50; round++ { |
| 282 | seen := map[int]bool{} | 290 | seen := map[int]bool{} |
| 283 | for _, p := range freePorts(t, 8) { | 291 | for _, p := range freePorts(t, 8) { |
e2e/stack_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // it onto the merged target with its reviews intact; a squash under a | 12 | // it onto the merged target with its reviews intact; a squash under a |
| 13 | // stack is refused. | 13 | // stack is refused. |
| 14 | func TestStackedMergeRequests(t *testing.T) { | 14 | func TestStackedMergeRequests(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | bobKey := inst.newKey(t, "bob") | 18 | bobKey := inst.newKey(t, "bob") |
e2e/status_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestCommitStatuses(t *testing.T) { | 10 | func TestCommitStatuses(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/system_test.go +1
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | // TestSystemSSHMode runs the M1/M2 scenarios against a real host sshd using | 15 | // TestSystemSSHMode runs the M1/M2 scenarios against a real host sshd using |
| 16 | // AuthorizedKeysCommand + forced command instead of the embedded listener. | 16 | // AuthorizedKeysCommand + forced command instead of the embedded listener. |
| 17 | func TestSystemSSHMode(t *testing.T) { | 17 | func TestSystemSSHMode(t *testing.T) { |
| 18 | t.Parallel() | ||
| 18 | sshdBin := "/usr/sbin/sshd" | 19 | sshdBin := "/usr/sbin/sshd" |
| 19 | if _, err := os.Stat(sshdBin); err != nil { | 20 | if _, err := os.Stat(sshdBin); err != nil { |
| 20 | t.Skipf("no host sshd at %s", sshdBin) | 21 | t.Skipf("no host sshd at %s", sshdBin) |
e2e/tagprotect_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // Protected-tag globs refuse moving and deleting matching tags; a tag a | 10 | // Protected-tag globs refuse moving and deleting matching tags; a tag a |
| 11 | // release is anchored to refuses both on its own (#201). | 11 | // release is anchored to refuses both on its own (#201). |
| 12 | func TestTagProtection(t *testing.T) { | 12 | func TestTagProtection(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstance(t) | 14 | inst := startInstance(t) |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 16 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/teams_test.go +1
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | func TestOrgTeams(t *testing.T) { | 8 | func TestOrgTeams(t *testing.T) { |
| 9 | t.Parallel() | ||
| 9 | inst := startInstance(t) | 10 | inst := startInstance(t) |
| 10 | adminKey := inst.newKey(t, "alice") | 11 | adminKey := inst.newKey(t, "alice") |
| 11 | bobKey := inst.newKey(t, "bob") | 12 | bobKey := inst.newKey(t, "bob") |
e2e/theme_test.go +1
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | // web theme set fixes the colour scheme the layout stamps on <html>; the | 9 | // web theme set fixes the colour scheme the layout stamps on <html>; the |
| 10 | // account page shows the same setting and changes it (#232). | 10 | // account page shows the same setting and changes it (#232). |
| 11 | func TestWebTheme(t *testing.T) { | 11 | func TestWebTheme(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 13 | key := inst.newKey(t, "alice") | 14 | key := inst.newKey(t, "alice") |
| 14 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") | 15 | inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub") |
e2e/userdelete_test.go +1
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | func TestAdminUserDelete(t *testing.T) { | 8 | func TestAdminUserDelete(t *testing.T) { |
| 9 | t.Parallel() | ||
| 9 | inst := startInstance(t) | 10 | inst := startInstance(t) |
| 10 | aliceKey := inst.newKey(t, "alice") | 11 | aliceKey := inst.newKey(t, "alice") |
| 11 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") | 12 | inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") |
e2e/watchpref_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // read access is not enough, and off returns it to the default. The | 11 | // read access is not enough, and off returns it to the default. The |
| 12 | // account page carries the same switch (#194). | 12 | // account page carries the same switch (#194). |
| 13 | func TestWatchPreference(t *testing.T) { | 13 | func TestWatchPreference(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
e2e/web_test.go +1
| @@ -27,6 +27,7 @@ func (i *instance) get(t *testing.T, path string) (int, string) { | |||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | func TestWebUI(t *testing.T) { | 29 | func TestWebUI(t *testing.T) { |
| 30 | t.Parallel() | ||
| 30 | inst := startInstance(t) | 31 | inst := startInstance(t) |
| 31 | 32 | ||
| 32 | aliceKey := inst.newKey(t, "alice") | 33 | aliceKey := inst.newKey(t, "alice") |
e2e/webhook_test.go +2
| @@ -78,6 +78,7 @@ func (h *hookReceiver) waitN(t *testing.T, n int) []capturedHook { | |||
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | func TestWebhooks(t *testing.T) { | 80 | func TestWebhooks(t *testing.T) { |
| 81 | t.Parallel() | ||
| 81 | inst := startInstanceWith(t, "[webhooks]\nallow_local = true\n") | 82 | inst := startInstanceWith(t, "[webhooks]\nallow_local = true\n") |
| 82 | // Restart the daemon with a fast retry base for the failure tests. | 83 | // Restart the daemon with a fast retry base for the failure tests. |
| 83 | inst.proc.Process.Kill() | 84 | inst.proc.Process.Kill() |
| @@ -260,6 +261,7 @@ func TestWebhooks(t *testing.T) { | |||
| 260 | // asserts each reaches a subscriber. Half the forge's mutations recorded | 261 | // asserts each reaches a subscriber. Half the forge's mutations recorded |
| 261 | // nothing, so a webhook could be subscribed to them and never fire. | 262 | // nothing, so a webhook could be subscribed to them and never fire. |
| 262 | func TestWebhookEventCoverage(t *testing.T) { | 263 | func TestWebhookEventCoverage(t *testing.T) { |
| 264 | t.Parallel() | ||
| 263 | inst := startInstance(t) | 265 | inst := startInstance(t) |
| 264 | aliceKey := inst.newKey(t, "alice") | 266 | aliceKey := inst.newKey(t, "alice") |
| 265 | bobKey := inst.newKey(t, "bob") | 267 | bobKey := inst.newKey(t, "bob") |
e2e/webonly_test.go +1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // ref, an archive, and the public listing. Each existed as a web route | 11 | // ref, an archive, and the public listing. Each existed as a web route |
| 12 | // whose handler went around the registry, so no other surface had them. | 12 | // whose handler went around the registry, so no other surface had them. |
| 13 | func TestWebOnlyReadsAreCommands(t *testing.T) { | 13 | func TestWebOnlyReadsAreCommands(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstance(t) | 15 | inst := startInstance(t) |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
e2e/websessions_test.go +1
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | // A browser session can be listed and ended from SSH, one at a time or | 10 | // A browser session can be listed and ended from SSH, one at a time or |
| 11 | // all at once, and only its owner sees it. | 11 | // all at once, and only its owner sees it. |
| 12 | func TestWebSessionsListRevoke(t *testing.T) { | 12 | func TestWebSessionsListRevoke(t *testing.T) { |
| 13 | t.Parallel() | ||
| 13 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 14 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 14 | aliceKey := inst.newKey(t, "alice") | 15 | aliceKey := inst.newKey(t, "alice") |
| 15 | bobKey := inst.newKey(t, "bob") | 16 | bobKey := inst.newKey(t, "bob") |
e2e/websignup_test.go +2
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func TestWebSignup(t *testing.T) { | 11 | func TestWebSignup(t *testing.T) { |
| 12 | t.Parallel() | ||
| 12 | smtp := startFakeSMTP(t) | 13 | smtp := startFakeSMTP(t) |
| 13 | inst := startInstanceWith(t, fmt.Sprintf( | 14 | inst := startInstanceWith(t, fmt.Sprintf( |
| 14 | "[web]\nmode = \"accounts\"\n[registration]\nmode = \"invite\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", | 15 | "[web]\nmode = \"accounts\"\n[registration]\nmode = \"invite\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n", |
| @@ -73,6 +74,7 @@ func TestWebSignup(t *testing.T) { | |||
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | func TestWebSignupClosedInstance(t *testing.T) { | 76 | func TestWebSignupClosedInstance(t *testing.T) { |
| 77 | t.Parallel() | ||
| 76 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") | 78 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n") |
| 77 | // Closed registration: no signup route at all, and no landing hint. | 79 | // Closed registration: no signup route at all, and no landing hint. |
| 78 | if status, _ := inst.get(t, "/register"); status != 404 { | 80 | if status, _ := inst.get(t, "/register"); status != 404 { |
e2e/webwrites_test.go +1
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | // store directly and skip the per-account quota; issue comments skipped | 12 | // store directly and skip the per-account quota; issue comments skipped |
| 13 | // the archived check (#93). | 13 | // the archived check (#93). |
| 14 | func TestWebWritesGoThroughRegistry(t *testing.T) { | 14 | func TestWebWritesGoThroughRegistry(t *testing.T) { |
| 15 | t.Parallel() | ||
| 15 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n[limits]\nmax_repos_per_user = 1\n") | 16 | inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n[limits]\nmax_repos_per_user = 1\n") |
| 16 | aliceKey := inst.newKey(t, "alice") | 17 | aliceKey := inst.newKey(t, "alice") |
| 17 | inst.admin(t, "admin", "user", "create", "alice", | 18 | inst.admin(t, "admin", "user", "create", "alice", |
e2e/wiki_test.go +1
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | func TestWikis(t *testing.T) { | 10 | func TestWikis(t *testing.T) { |
| 11 | t.Parallel() | ||
| 11 | inst := startInstance(t) | 12 | inst := startInstance(t) |
| 12 | aliceKey := inst.newKey(t, "alice") | 13 | aliceKey := inst.newKey(t, "alice") |
| 13 | bobKey := inst.newKey(t, "bob") | 14 | bobKey := inst.newKey(t, "bob") |
e2e/writerate_test.go +2
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | // budget is the same one whichever surface spends it. Reads are not | 11 | // budget is the same one whichever surface spends it. Reads are not |
| 12 | // charged (#148). | 12 | // charged (#148). |
| 13 | func TestWriteRateLimit(t *testing.T) { | 13 | func TestWriteRateLimit(t *testing.T) { |
| 14 | t.Parallel() | ||
| 14 | inst := startInstanceWith(t, "[limits]\nwrite_rate = 4\n") | 15 | inst := startInstanceWith(t, "[limits]\nwrite_rate = 4\n") |
| 15 | aliceKey := inst.newKey(t, "alice") | 16 | aliceKey := inst.newKey(t, "alice") |
| 16 | bobKey := inst.newKey(t, "bob") | 17 | bobKey := inst.newKey(t, "bob") |
| @@ -48,6 +49,7 @@ func TestWriteRateLimit(t *testing.T) { | |||
| 48 | // The runner protocol is exempt: a build streams its log in many small | 49 | // The runner protocol is exempt: a build streams its log in many small |
| 49 | // writes, and throttling those would throttle CI itself. | 50 | // writes, and throttling those would throttle CI itself. |
| 50 | func TestWriteRateLimitSparesTheRunner(t *testing.T) { | 51 | func TestWriteRateLimitSparesTheRunner(t *testing.T) { |
| 52 | t.Parallel() | ||
| 51 | inst := startInstanceWith(t, "[limits]\nwrite_rate = 2\n") | 53 | inst := startInstanceWith(t, "[limits]\nwrite_rate = 2\n") |
| 52 | inst.runner = buildRunner(t) | 54 | inst.runner = buildRunner(t) |
| 53 | aliceKey := inst.newKey(t, "alice") | 55 | aliceKey := inst.newKey(t, "alice") |