e2e/searchweb_test.go

419f6dfdc5489a0c6374e36dd1ebbfca68040056
gitbay/e2e/searchweb_test.go history · blame · raw

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