e2e/feeds_test.go
93 lines · 3454 bytes
1package e2e
2
3import (
4 "net/http"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11// Atom feeds for releases, commits and an owner's public activity, read
12// with no session; private repositories stay out of them (#192).
13func TestAtomFeeds(t *testing.T) {
14 inst := startInstance(t)
15 aliceKey := inst.newKey(t, "alice")
16 inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub")
17 for _, args := range [][]string{
18 {"repo", "create", "alice/app"},
19 {"repo", "create", "alice/secret", "--private"},
20 } {
21 if _, errOut, code := inst.ssh(t, aliceKey, "", args...); code != 0 {
22 t.Fatalf("%v: %s", args, errOut)
23 }
24 }
25 if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/feed.atom"); code == 0 || !strings.Contains(errOut, ".atom") {
26 t.Fatalf("a repository named like a feed was accepted: %d %s", code, errOut)
27 }
28 env := inst.gitEnv(aliceKey)
29 for _, name := range []string{"app", "secret"} {
30 dir := filepath.Join(t.TempDir(), name)
31 mustGit(t, t.TempDir(), env, "clone", "-q", inst.sshURL("alice/"+name), dir)
32 if err := os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a\n"), 0o644); err != nil {
33 t.Fatal(err)
34 }
35 mustGit(t, dir, env, "checkout", "-q", "-b", "main")
36 mustGit(t, dir, env, "add", ".")
37 mustGit(t, dir, env, "commit", "-q", "-m", "first commit on "+name)
38 mustGit(t, dir, env, "tag", "v1.0")
39 mustGit(t, dir, env, "push", "-q", "origin", "main", "v1.0")
40 if _, errOut, code := inst.ssh(t, aliceKey, "", "release", "create", "alice/"+name, "v1.0",
41 "--title", "'First light'", "--notes", "'notes for "+name+"'"); code != 0 {
42 t.Fatalf("release create: %s", errOut)
43 }
44 }
45
46 anon := &http.Client{}
47 get := func(path string, want int) string {
48 t.Helper()
49 status, body := browserGet(t, anon, inst.base()+path)
50 if status != want {
51 t.Fatalf("GET %s: %d, want %d\n%s", path, status, want, body)
52 }
53 return body
54 }
55 resp, err := http.Get(inst.base() + "/alice/app/releases.atom")
56 if err != nil {
57 t.Fatal(err)
58 }
59 resp.Body.Close()
60 if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(ct, "application/atom+xml") {
61 t.Fatalf("content type %q", ct)
62 }
63 body := get("/alice/app/releases.atom", 200)
64 for _, want := range []string{`xmlns="http://www.w3.org/2005/Atom"`, "<title>v1.0: First light</title>", "notes for app", "/alice/app/releases#v1.0"} {
65 if !strings.Contains(body, want) {
66 t.Errorf("releases feed missing %s:\n%s", want, body)
67 }
68 }
69 for _, path := range []string{"/alice/app/log.atom", "/alice/app/log.atom/main"} {
70 if body := get(path, 200); !strings.Contains(body, "<title>first commit on app</title>") || !strings.Contains(body, "<name>t</name>") {
71 t.Errorf("%s:\n%s", path, body)
72 }
73 }
74 get("/alice/app/log.atom/nope", 404)
75 body = get("/alice/activity.atom", 200)
76 if !strings.Contains(body, "release.created alice/app v1.0") || strings.Contains(body, "secret") {
77 t.Errorf("activity feed:\n%s", body)
78 }
79 get("/nobody/activity.atom", 404)
80 get("/alice/secret/releases.atom", 404)
81 get("/alice/secret/log.atom", 404)
82
83 // The pages say where their feed is.
84 for path, feed := range map[string]string{
85 "/alice/app/releases": "/alice/app/releases.atom",
86 "/alice/app/log": "/alice/app/log.atom/main",
87 "/alice": "/alice/activity.atom",
88 } {
89 if body := get(path, 200); !strings.Contains(body, `type="application/atom+xml" href="`+feed+`"`) {
90 t.Errorf("%s has no discovery link to %s", path, feed)
91 }
92 }
93}