e2e/releaseweb_test.go
122 lines · 5068 bytes
1package e2e
2
3import (
4 "net/url"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11// TestReleaseAndBuildWeb creates and edits a release and triggers a build
12// from the browser, each through the command the CLI runs.
13func TestReleaseAndBuildWeb(t *testing.T) {
14 t.Parallel()
15 inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
16 inst.runner = buildRunner(t)
17 aliceKey := inst.newKey(t, "alice")
18 inst.admin(t, "admin", "user", "create", "alice",
19 "--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
20 runnerKey := inst.newKey(t, "ci")
21 inst.admin(t, "admin", "user", "create", "ci", "--key", runnerKey+".pub", "--admin")
22
23 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
24 t.Fatalf("repo create: %s", errOut)
25 }
26 env := inst.gitEnv(aliceKey)
27 work := t.TempDir()
28 mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
29 dir := filepath.Join(work, "w")
30 os.MkdirAll(filepath.Join(dir, ".gitbay"), 0o755)
31 os.WriteFile(filepath.Join(dir, ".gitbay", "ci.yml"),
32 []byte("jobs:\n smoke:\n steps:\n - echo ok\n"), 0o644)
33 os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a\n"), 0o644)
34 mustGit(t, dir, env, "checkout", "-q", "-b", "main")
35 mustGit(t, dir, env, "add", ".")
36 mustGit(t, dir, env, "commit", "-q", "-m", "base")
37 mustGit(t, dir, env, "tag", "-a", "v1.0", "-m", "first")
38 mustGit(t, dir, env, "push", "-q", "origin", "main", "v1.0")
39
40 alice := inst.login(t, aliceKey)
41 base := inst.base() + "/alice/app"
42
43 // The pushed tag is offered, and creating from it works.
44 _, page := browserGet(t, alice, base+"/releases")
45 if !strings.Contains(page, `value="v1.0"`) {
46 t.Fatalf("tag not offered:\n%s", page)
47 }
48 if status, _ := browserPost(t, alice, base+"/releases", url.Values{
49 "tag": {"v1.0"}, "title": {"First light"}, "notes": {"the **first** one"}}); status != 200 {
50 t.Fatal("release create failed")
51 }
52 out, _, _ := inst.ssh(t, aliceKey, "", "release", "show", "alice/app", "v1.0", "--json")
53 if !strings.Contains(out, "First light") || !strings.Contains(out, "the **first** one") {
54 t.Fatalf("release not created:\n%s", out)
55 }
56
57 // Editing keeps the tag and replaces the fields.
58 if status, _ := browserPost(t, alice, base+"/releases", url.Values{
59 "action": {"edit"}, "tag": {"v1.0"}, "title": {"Second light"}, "notes": {"revised"}}); status != 200 {
60 t.Fatal("release edit failed")
61 }
62 out, _, _ = inst.ssh(t, aliceKey, "", "release", "show", "alice/app", "v1.0", "--json")
63 if !strings.Contains(out, "Second light") || !strings.Contains(out, "revised") {
64 t.Fatalf("release not edited:\n%s", out)
65 }
66 // A released tag is no longer offered for creation.
67 if _, page = browserGet(t, alice, base+"/releases"); strings.Contains(page, `<option value="v1.0"`) {
68 t.Fatalf("released tag still offered:\n%s", page)
69 }
70
71 // Builds: the job from the config is offered and runs on demand.
72 _, bpage := browserGet(t, alice, base+"/builds")
73 if !strings.Contains(bpage, `value="smoke"`) {
74 t.Fatalf("job not offered:\n%s", bpage)
75 }
76 if status, _ := browserPost(t, alice, base+"/builds", url.Values{"job": {"smoke"}}); status != 200 {
77 t.Fatal("trigger failed")
78 }
79 inst.runnerOnce(t, runnerKey)
80 out, _, _ = inst.ssh(t, aliceKey, "", "build", "list", "alice/app")
81 if !strings.Contains(out, "smoke\tsuccess") {
82 t.Fatalf("triggered build did not run:\n%s", out)
83 }
84
85 // A reader sees neither control.
86 bobKey := inst.newKey(t, "bob")
87 inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
88 bob := inst.login(t, bobKey)
89 if _, p := browserGet(t, bob, base+"/builds"); strings.Contains(p, "Run a job now") {
90 t.Fatal("reader sees the trigger control")
91 }
92 if _, p := browserGet(t, bob, base+"/releases"); strings.Contains(p, "New release") ||
93 strings.Contains(p, "Delete release") {
94 t.Fatal("reader sees a release control")
95 }
96
97 // Delete is offered to a repo admin and removes the release; the tag
98 // survives, so it is offered for creation again (#165).
99 if _, p := browserGet(t, alice, base+"/releases"); !strings.Contains(p, "Delete release") {
100 t.Fatalf("owner is not offered the delete control:\n%s", p)
101 }
102 _, body := browserPost(t, alice, base+"/releases", url.Values{
103 "action": {"delete"}, "tag": {"v1.0"}})
104 if !strings.Contains(body, "type v1.0 to confirm") {
105 t.Fatalf("unconfirmed delete was not refused:\n%s", body)
106 }
107 out, _, _ = inst.ssh(t, aliceKey, "", "release", "list", "alice/app", "--json")
108 if !strings.Contains(out, "v1.0") {
109 t.Fatalf("release removed without confirmation: %s", out)
110 }
111 if status, _ := browserPost(t, alice, base+"/releases", url.Values{
112 "action": {"delete"}, "tag": {"v1.0"}, "confirm": {"v1.0"}}); status != 200 {
113 t.Fatal("release delete failed")
114 }
115 out, _, _ = inst.ssh(t, aliceKey, "", "release", "list", "alice/app", "--json")
116 if strings.Contains(out, "v1.0") {
117 t.Fatalf("release still listed after delete:\n%s", out)
118 }
119 if _, p := browserGet(t, alice, base+"/releases"); !strings.Contains(p, `<option value="v1.0"`) {
120 t.Fatalf("tag not free again after delete:\n%s", p)
121 }
122}