e2e/archive_test.go
134 lines · 5924 bytes
1package e2e
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8)
9
10func TestArchiveAndTopics(t *testing.T) {
11 inst := startInstance(t)
12 aliceKey := inst.newKey(t, "alice")
13 bobKey := inst.newKey(t, "bob")
14 inst.admin(t, "admin", "user", "create", "alice",
15 "--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
16 inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
17
18 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
19 t.Fatalf("repo create: %s", errOut)
20 }
21 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "access", "grant", "alice/app", "bob", "write"); code != 0 {
22 t.Fatal("grant failed")
23 }
24 work := t.TempDir()
25 env := inst.gitEnv(aliceKey)
26 mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
27 dir := filepath.Join(work, "w")
28 os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a\n"), 0o644)
29 mustGit(t, dir, env, "checkout", "-q", "-b", "main")
30 mustGit(t, dir, env, "add", ".")
31 mustGit(t, dir, env, "commit", "-q", "-m", "base")
32 mustGit(t, dir, env, "push", "-q", "origin", "main")
33
34 // Topics: admin-only edits, validation, idempotent add, listing.
35 if _, errOut, code := inst.ssh(t, bobKey, "", "repo", "topics", "add", "alice/app", "go"); code != 4 {
36 t.Fatalf("non-admin added topics: exit %d, %s", code, errOut)
37 }
38 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "topics", "add", "alice/app", "Bad_Topic"); code != 2 || !strings.Contains(errOut, "invalid topic") {
39 t.Fatalf("bad topic accepted: exit %d, %s", code, errOut)
40 }
41 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "topics", "add", "alice/app", "go", "cli", "go"); code != 0 {
42 t.Fatalf("topics add: %s", errOut)
43 }
44 out, _, _ := inst.ssh(t, aliceKey, "", "repo", "topics", "alice/app", "--json")
45 if !strings.Contains(out, `["cli","go"]`) {
46 t.Fatalf("topics list: %s", out)
47 }
48 out, _, _ = inst.ssh(t, aliceKey, "", "repo", "show", "alice/app", "--json")
49 if !strings.Contains(out, `"topics":["cli","go"]`) || strings.Contains(out, `"archived"`) {
50 t.Fatalf("repo show topics: %s", out)
51 }
52 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "topics", "remove", "alice/app", "cli"); code != 0 {
53 t.Fatal("topics remove failed")
54 }
55 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "topics", "remove", "alice/app", "cli"); code != 3 {
56 t.Fatal("removing an absent topic should be not-found")
57 }
58
59 // An MR and an issue that predate archiving.
60 mustGit(t, dir, env, "checkout", "-q", "-b", "feat")
61 os.WriteFile(filepath.Join(dir, "b.txt"), []byte("b\n"), 0o644)
62 mustGit(t, dir, env, "add", ".")
63 mustGit(t, dir, env, "commit", "-q", "-m", "feat")
64 mustGit(t, dir, env, "push", "-q", "origin", "feat")
65 if _, errOut, code := inst.ssh(t, aliceKey, "", "mr", "create", "alice/app",
66 "--source", "feat", "--target", "main", "--title", "'feat'"); code != 0 {
67 t.Fatalf("mr create: %s", errOut)
68 }
69 if _, errOut, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/app", "--title", "'todo'"); code != 0 {
70 t.Fatalf("issue create: %s", errOut)
71 }
72
73 // Archive: admin-only, then everything content-mutating is refused.
74 if _, _, code := inst.ssh(t, bobKey, "", "repo", "archive", "alice/app"); code != 4 {
75 t.Fatal("non-admin archived the repo")
76 }
77 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "archive", "alice/app"); code != 0 {
78 t.Fatalf("archive: %s", errOut)
79 }
80 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "archive", "alice/app"); code != 2 {
81 t.Fatal("double archive not refused")
82 }
83
84 os.WriteFile(filepath.Join(dir, "c.txt"), []byte("c\n"), 0o644)
85 mustGit(t, dir, env, "checkout", "-q", "main")
86 mustGit(t, dir, env, "add", ".")
87 mustGit(t, dir, env, "commit", "-q", "-m", "more")
88 if out, code := gitRun(t, dir, env, "push", "origin", "main"); code == 0 || !strings.Contains(out, "archived and read-only") {
89 t.Fatalf("push to archived repo: exit %d\n%s", code, out)
90 }
91 for _, cmd := range [][]string{
92 {"issue", "create", "alice/app", "--title", "'x'"},
93 {"issue", "comment", "alice/app", "1", "--message", "'x'"},
94 {"issue", "close", "alice/app", "1"},
95 {"mr", "comment", "alice/app", "1", "--message", "'x'"},
96 {"mr", "review", "alice/app", "1", "--approve"},
97 {"mr", "merge", "alice/app", "1"},
98 {"mr", "close", "alice/app", "1"},
99 {"status", "set", "alice/app", "HEAD", "--context", "ci", "--state", "success"},
100 } {
101 if _, errOut, code := inst.ssh(t, bobKey, "", cmd...); code != 4 || !strings.Contains(errOut, "archived and read-only") {
102 t.Fatalf("%v on archived repo: exit %d, %s", cmd, code, errOut)
103 }
104 }
105
106 // Reading stays untouched: clone, listings, show, web.
107 work2 := t.TempDir()
108 mustGit(t, work2, env, "clone", "-q", inst.sshURL("alice/app"), "r")
109 if out, _, code := inst.ssh(t, aliceKey, "", "issue", "list", "alice/app"); code != 0 || !strings.Contains(out, "todo") {
110 t.Fatalf("issue list on archived repo: %s", out)
111 }
112 out, _, _ = inst.ssh(t, aliceKey, "", "repo", "show", "alice/app", "--json")
113 if !strings.Contains(out, `"archived":true`) {
114 t.Fatalf("repo show archived flag: %s", out)
115 }
116 if status, _ := inst.get(t, "/alice/app"); status != 200 {
117 t.Fatalf("web browse on archived repo: %d", status)
118 }
119
120 // Settings and unarchive still work; writes come back.
121 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "settings", "protect", "alice/app", "main"); code != 0 {
122 t.Fatal("settings on archived repo should still work")
123 }
124 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "settings", "unprotect", "alice/app", "main"); code != 0 {
125 t.Fatal("unprotect failed")
126 }
127 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "unarchive", "alice/app"); code != 0 {
128 t.Fatalf("unarchive: %s", errOut)
129 }
130 mustGit(t, dir, env, "push", "-q", "origin", "main")
131 if _, errOut, code := inst.ssh(t, bobKey, "", "issue", "comment", "alice/app", "1", "--message", "'back'"); code != 0 {
132 t.Fatalf("comment after unarchive: %s", errOut)
133 }
134}