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