e2e/search_test.go

b347d6c8c464e3c965455795f4e22e0aaeed0652
gitbay/e2e/search_test.go history · blame · raw

106 lines · 4338 bytes

  1package e2e
  2
  3import (
  4	"os"
  5	"path/filepath"
  6	"strings"
  7	"testing"
  8)
  9
 10func TestSearch(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",
 15		"--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
 16	inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
 17
 18	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/webapp",
 19		"--description", "'a small web application'"); code != 0 {
 20		t.Fatalf("repo create: %s", errOut)
 21	}
 22	if _, _, code := inst.ssh(t, aliceKey, "", "repo", "topics", "add", "alice/webapp", "golang"); code != 0 {
 23		t.Fatal("topics add failed")
 24	}
 25	if _, _, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/secret", "--private",
 26		"--description", "'hidden things'"); code != 0 {
 27		t.Fatal("private repo create failed")
 28	}
 29
 30	work := t.TempDir()
 31	env := inst.gitEnv(aliceKey)
 32	mustGit(t, work, env, "clone", inst.sshURL("alice/webapp"), "w")
 33	dir := filepath.Join(work, "w")
 34	os.WriteFile(filepath.Join(dir, "main.go"),
 35		[]byte("package main\n\nfunc Greet() string {\n\treturn \"hello, forge\"\n}\n"), 0o644)
 36	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
 37	mustGit(t, dir, env, "add", ".")
 38	mustGit(t, dir, env, "commit", "-q", "-m", "base")
 39	mustGit(t, dir, env, "push", "-q", "origin", "main")
 40
 41	// repo search over SSH: by name, description, and topic; visibility
 42	// respected — bob never sees the private repo, alice does.
 43	out, _, code := inst.ssh(t, aliceKey, "", "repo", "search", "webapp")
 44	if code != 0 || !strings.Contains(out, "alice/webapp") {
 45		t.Fatalf("search by name: %s", out)
 46	}
 47	if out, _, _ = inst.ssh(t, bobKey, "", "repo", "search", "application"); !strings.Contains(out, "alice/webapp") {
 48		t.Fatalf("search by description: %s", out)
 49	}
 50	if out, _, _ = inst.ssh(t, bobKey, "", "repo", "search", "golang"); !strings.Contains(out, "alice/webapp") {
 51		t.Fatalf("search by topic: %s", out)
 52	}
 53	if out, _, _ = inst.ssh(t, bobKey, "", "repo", "search", "secret"); strings.Contains(out, "alice/secret") {
 54		t.Fatal("private repo leaked to bob's search")
 55	}
 56	if out, _, _ = inst.ssh(t, aliceKey, "", "repo", "search", "hidden"); !strings.Contains(out, "alice/secret") {
 57		t.Fatalf("owner's search missed private repo: %s", out)
 58	}
 59	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "search", "x"); code != 2 || !strings.Contains(errOut, "2 to 200") {
 60		t.Fatalf("short query: exit %d, %s", code, errOut)
 61	}
 62
 63	// repo grep over SSH: literal, case-insensitive, 404-parity on private.
 64	out, _, code = inst.ssh(t, aliceKey, "", "repo", "grep", "alice/webapp", "HELLO", "--json")
 65	if code != 0 || !strings.Contains(out, `"path":"main.go"`) || !strings.Contains(out, `"line":4`) {
 66		t.Fatalf("grep: %s", out)
 67	}
 68	if _, errOut, code := inst.ssh(t, bobKey, "", "repo", "grep", "alice/secret", "anything"); code != 3 || !strings.Contains(errOut, "not found") {
 69		t.Fatalf("private grep parity: exit %d, %s", code, errOut)
 70	}
 71
 72	// Web: explore filter respects the query and visibility.
 73	status, body := inst.get(t, "/explore?q=webapp")
 74	if status != 200 || !strings.Contains(body, "alice/webapp") {
 75		t.Fatalf("explore filter: %d", status)
 76	}
 77	_, body = inst.get(t, "/explore?q=nomatchhere")
 78	if strings.Contains(body, "alice/webapp") {
 79		t.Fatal("explore filter did not filter")
 80	}
 81	_, body = inst.get(t, "/explore?q=hidden")
 82	if strings.Contains(body, "secret") {
 83		t.Fatal("private repo leaked on explore search")
 84	}
 85
 86	// Web: repo code search with mark and blob line anchor.
 87	status, body = inst.get(t, "/alice/webapp/search?q=hello")
 88	if status != 200 || !strings.Contains(body, `<mark>hello</mark>`) ||
 89		!strings.Contains(body, `/alice/webapp/blob/main/main.go#L4">main.go:4</a>`) {
 90		t.Fatalf("repo search page: %d\n%s", status, body)
 91	}
 92	_, body = inst.get(t, "/alice/webapp/search?q=zzznothing")
 93	if !strings.Contains(body, "no matches") {
 94		t.Fatal("empty state missing")
 95	}
 96	_, body = inst.get(t, "/alice/webapp/search?q=x")
 97	if !strings.Contains(body, "2 to 200") {
 98		t.Fatal("short query error missing")
 99	}
100
101	// Blob line numbers are linkable anchors for the search links.
102	_, body = inst.get(t, "/alice/webapp/blob/main/main.go")
103	if !strings.Contains(body, `id="L4"`) {
104		t.Fatal("blob line anchors missing")
105	}
106}