e2e/searchweb_test.go

v1.14.0
gitbay/e2e/searchweb_test.go history · blame · raw

111 lines · 4571 bytes

  1package e2e
  2
  3import (
  4	"net/url"
  5	"strings"
  6	"testing"
  7)
  8
  9// TestGlobalSearchAndNotificationsWeb covers the two web surfaces #118
 10// still lacked: /search across the instance, and the notification inbox.
 11func TestGlobalSearchAndNotificationsWeb(t *testing.T) {
 12	inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
 13	aliceKey := inst.newKey(t, "alice")
 14	bobKey := inst.newKey(t, "bob")
 15	inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub")
 16	inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
 17
 18	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/widget"); code != 0 {
 19		t.Fatalf("repo create: %s", errOut)
 20	}
 21	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/secret", "--private"); code != 0 {
 22		t.Fatalf("private repo create: %s", errOut)
 23	}
 24	if _, errOut, code := inst.ssh(t, bobKey, "", "issue", "create", "alice/widget",
 25		"--title", "'widget leaks memory'", "--body", "'it climbs'"); code != 0 {
 26		t.Fatalf("issue create: %s", errOut)
 27	}
 28	if _, errOut, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/secret",
 29		"--title", "'widget in the private repo'"); code != 0 {
 30		t.Fatalf("private issue create: %s", errOut)
 31	}
 32
 33	// Anonymous search reaches the public repository and its issue, and
 34	// neither the private repository nor its issue.
 35	status, body := inst.get(t, "/search?q=widget")
 36	if status != 200 {
 37		t.Fatalf("anonymous search: %d", status)
 38	}
 39	if !strings.Contains(body, `href="/alice/widget"`) ||
 40		!strings.Contains(body, "widget leaks memory") ||
 41		!strings.Contains(body, `href="/alice/widget/issues/1"`) {
 42		t.Fatalf("anonymous search missing public hits:\n%s", body)
 43	}
 44	if strings.Contains(body, "alice/secret") || strings.Contains(body, "private repo") {
 45		t.Fatal("anonymous search leaked a private repository")
 46	}
 47
 48	// Filtering by kind keeps the repository row and drops the issue.
 49	_, body = inst.get(t, "/search?q=widget&kind=repo")
 50	if !strings.Contains(body, `href="/alice/widget"`) || strings.Contains(body, "widget leaks memory") {
 51		t.Fatalf("kind=repo filter:\n%s", body)
 52	}
 53	_, body = inst.get(t, "/search?q=x")
 54	if !strings.Contains(body, "2 to 200 characters") {
 55		t.Fatal("short query not refused")
 56	}
 57
 58	// Alice sees her private repository and its issue in the same page.
 59	browser := inst.login(t, aliceKey)
 60	status, body = browserGet(t, browser, inst.base()+"/search?q=widget")
 61	if status != 200 || !strings.Contains(body, "alice/secret") ||
 62		!strings.Contains(body, "widget in the private repo") {
 63		t.Fatalf("owner search misses private rows:\n%s", body)
 64	}
 65
 66	// The rail carries the unread badge and the notifications page lists
 67	// the issue bob opened.
 68	status, body = browserGet(t, browser, inst.base()+"/notifications")
 69	if status != 200 || !strings.Contains(body, "bob opened issue #1") ||
 70		!strings.Contains(body, `href="/alice/widget/issues/1"`) {
 71		t.Fatalf("notifications page:\n%s", body)
 72	}
 73	if !strings.Contains(body, `href="/notifications"`) {
 74		t.Fatal("rail has no notifications link")
 75	}
 76
 77	// Marking all read empties the unread list but not the full one.
 78	if status, _ := browserPost(t, browser, inst.base()+"/notifications", url.Values{}); status != 200 {
 79		t.Fatalf("mark all read: %d", status)
 80	}
 81	_, body = browserGet(t, browser, inst.base()+"/notifications")
 82	if !strings.Contains(body, "nothing unread") {
 83		t.Fatalf("unread list after sweep:\n%s", body)
 84	}
 85	_, body = browserGet(t, browser, inst.base()+"/notifications?all=1")
 86	if !strings.Contains(body, "bob opened issue #1") {
 87		t.Fatalf("all list after sweep:\n%s", body)
 88	}
 89
 90	// Watching from the repository header is the same state the CLI sets.
 91	if status, _ := browserPost(t, browser, inst.base()+"/alice/widget/watch", url.Values{}); status != 200 {
 92		t.Fatalf("watch toggle: %d", status)
 93	}
 94	out, errOut, code := inst.ssh(t, aliceKey, "", "notifications", "list", "--all", "--json")
 95	if code != 0 {
 96		t.Fatalf("notifications list: %s", errOut)
 97	}
 98	if !strings.Contains(out, "alice/widget") {
 99		t.Fatalf("inbox over ssh: %s", out)
100	}
101	_, body = browserGet(t, browser, inst.base()+"/alice/widget")
102	if !strings.Contains(body, ">Watching</button>") {
103		t.Fatalf("repo header does not show the watch state:\n%s", body)
104	}
105
106	// Anonymous visitors get the search page; the inbox sends them to log
107	// in. http.Get follows the redirect, so the login page is the proof.
108	if status, body := inst.get(t, "/notifications"); status != 200 || !strings.Contains(body, "Sign in") {
109		t.Fatalf("anonymous /notifications: %d\n%s", status, body)
110	}
111}