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