e2e/search_test.go

v1.34.1
gitbay/e2e/search_test.go history · blame · raw

107 lines · 4352 bytes

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