e2e/wiki_test.go
101 lines · 4115 bytes
1package e2e
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8)
9
10func TestWikis(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", "--key", aliceKey+".pub")
15 inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
16 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
17 t.Fatal("repo create failed")
18 }
19 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/secretive", "--private"); code != 0 {
20 t.Fatal("private repo create failed")
21 }
22
23 // No wiki yet: the tab is absent, the page shows the push hint, and
24 // cloning the companion says so.
25 _, body := inst.get(t, "/alice/app")
26 if strings.Contains(body, ">Wiki<") {
27 t.Fatal("wiki tab shown with no wiki")
28 }
29 _, body = inst.get(t, "/alice/app/wiki")
30 if !strings.Contains(body, "no wiki yet") {
31 t.Fatal("missing-wiki hint absent")
32 }
33 env := inst.gitEnv(aliceKey)
34 if out, code := gitRun(t, t.TempDir(), env, "clone", inst.sshURL("alice/app.wiki"), "w"); code == 0 || !strings.Contains(out, "no wiki yet") {
35 t.Fatalf("clone of absent wiki: %d\n%s", code, out)
36 }
37
38 // First push creates the wiki. A reader without write cannot push it.
39 work := t.TempDir()
40 mustGit(t, work, env, "init", "-q", "-b", "main", "w")
41 dir := filepath.Join(work, "w")
42 os.WriteFile(filepath.Join(dir, "Home.md"), []byte(
43 "# welcome\n\nsee [Setup](Setup.md) and \n"), 0o644)
44 os.WriteFile(filepath.Join(dir, "Setup.org"), []byte("* setup\n\nsteps here\n"), 0o644)
45 os.WriteFile(filepath.Join(dir, "shot.png"), []byte{0x89, 0x50, 0x4e, 0x47}, 0o644)
46 mustGit(t, dir, env, "add", ".")
47 mustGit(t, dir, env, "commit", "-q", "-m", "wiki start")
48 mustGit(t, dir, env, "push", "-q", inst.sshURL("alice/app.wiki"), "main")
49
50 benv := inst.gitEnv(bobKey)
51 if out, code := gitRun(t, dir, benv, "push", inst.sshURL("alice/app.wiki"), "main"); code == 0 && !strings.Contains(out, "denied") {
52 t.Fatalf("reader pushed the wiki: %d\n%s", code, out)
53 }
54
55 // Rendering: home resolves, tab appears, links rewrite to wiki pages
56 // and images to the wiki raw route; org pages render too.
57 _, body = inst.get(t, "/alice/app")
58 if !strings.Contains(body, ">Wiki<") {
59 t.Fatal("wiki tab missing after push")
60 }
61 _, body = inst.get(t, "/alice/app/wiki")
62 if !strings.Contains(body, "welcome") ||
63 !strings.Contains(body, `href="/alice/app/wiki/Setup"`) ||
64 !strings.Contains(body, `src="/alice/app/wiki/_raw/shot.png"`) {
65 t.Fatalf("wiki home rendering:\n%s", body)
66 }
67 _, body = inst.get(t, "/alice/app/wiki/Setup")
68 if !strings.Contains(body, "steps here") {
69 t.Fatal("org wiki page missing")
70 }
71 if status, _ := inst.get(t, "/alice/app/wiki/Nope"); status != 404 {
72 t.Fatalf("missing page: %d", status)
73 }
74 // The raw route serves the image bytes.
75 status, raw := inst.get(t, "/alice/app/wiki/_raw/shot.png")
76 if status != 200 || !strings.HasPrefix(raw, "\x89PNG") {
77 t.Fatalf("wiki raw: %d", status)
78 }
79
80 // 404-parity: a private repo's wiki is invisible, over web and git.
81 mustGit(t, dir, env, "push", "-q", inst.sshURL("alice/secretive.wiki"), "main")
82 if status, _ := inst.get(t, "/alice/secretive/wiki"); status != 404 {
83 t.Fatalf("private wiki page: %d", status)
84 }
85 if out, code := gitRun(t, t.TempDir(), benv, "clone", inst.sshURL("alice/secretive.wiki"), "x"); code == 0 || !strings.Contains(out, "not found") {
86 t.Fatalf("private wiki clone by outsider: %d\n%s", code, out)
87 }
88
89 // Repo names ending .wiki are refused (companion namespace).
90 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/notes.wiki"); code != 2 || !strings.Contains(errOut, "reserved") {
91 t.Fatalf(".wiki name allowed: %d %s", code, errOut)
92 }
93
94 // Deleting the repo removes the wiki companion.
95 if _, _, code := inst.ssh(t, aliceKey, "", "repo", "delete", "alice/secretive", "--yes"); code != 0 {
96 t.Fatal("repo delete failed")
97 }
98 if _, err := os.Stat(filepath.Join(inst.root, "repos", "alice", "secretive.wiki.git")); err == nil {
99 t.Fatal("wiki survived repo delete")
100 }
101}