e2e/edit_test.go

f8b976a97290a20d552056a999511f5d27d8e8ec
gitbay/e2e/edit_test.go history · blame · raw

111 lines · 4560 bytes

  1package e2e
  2
  3import (
  4	"encoding/json"
  5	"net/url"
  6	"os"
  7	"path/filepath"
  8	"strings"
  9	"testing"
 10)
 11
 12func TestIssueMREditing(t *testing.T) {
 13	t.Parallel()
 14	inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
 15	aliceKey := inst.newKey(t, "alice")
 16	bobKey := inst.newKey(t, "bob")
 17	eveKey := inst.newKey(t, "eve")
 18	inst.admin(t, "admin", "user", "create", "alice",
 19		"--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
 20	inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
 21	inst.admin(t, "admin", "user", "create", "eve", "--key", eveKey+".pub")
 22
 23	if _, _, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
 24		t.Fatal("repo create failed")
 25	}
 26	// bob authors an issue (no write access); eve is an outsider.
 27	if _, _, code := inst.ssh(t, bobKey, "", "issue", "create", "alice/app", "--title", "'typo titel'", "--body", "'first'"); code != 0 {
 28		t.Fatal("issue create failed")
 29	}
 30
 31	// SSH edit: the author may fix it; an outsider may not; empty titles
 32	// are refused; write access (alice) may edit someone else's.
 33	if _, errOut, code := inst.ssh(t, bobKey, "", "issue", "edit", "alice/app", "1", "--title", "'typo title'"); code != 0 {
 34		t.Fatalf("author edit: %s", errOut)
 35	}
 36	if _, _, code := inst.ssh(t, eveKey, "", "issue", "edit", "alice/app", "1", "--title", "'hax'"); code != 4 {
 37		t.Fatal("outsider edited an issue")
 38	}
 39	if _, _, code := inst.ssh(t, bobKey, "", "issue", "edit", "alice/app", "1", "--title", "''"); code != 2 {
 40		t.Fatal("empty title accepted")
 41	}
 42	if _, _, code := inst.ssh(t, aliceKey, "", "issue", "edit", "alice/app", "1", "--body", "'rewritten'"); code != 0 {
 43		t.Fatal("write-access edit failed")
 44	}
 45	out, _, _ := inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "1", "--json")
 46	if !strings.Contains(out, "typo title") || !strings.Contains(out, "rewritten") {
 47		t.Fatalf("edits not applied: %s", out)
 48	}
 49
 50	// MR edit over SSH.
 51	work := t.TempDir()
 52	env := inst.gitEnv(aliceKey)
 53	mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
 54	dir := filepath.Join(work, "w")
 55	os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a\n"), 0o644)
 56	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
 57	mustGit(t, dir, env, "add", ".")
 58	mustGit(t, dir, env, "commit", "-q", "-m", "base")
 59	mustGit(t, dir, env, "push", "-q", "origin", "main")
 60	mustGit(t, dir, env, "checkout", "-q", "-b", "feat")
 61	os.WriteFile(filepath.Join(dir, "b.txt"), []byte("b\n"), 0o644)
 62	mustGit(t, dir, env, "add", ".")
 63	mustGit(t, dir, env, "commit", "-q", "-m", "feat")
 64	mustGit(t, dir, env, "push", "-q", "origin", "feat")
 65	if _, _, code := inst.ssh(t, aliceKey, "", "mr", "create", "alice/app",
 66		"--source", "feat", "--target", "main", "--title", "'draft'"); code != 0 {
 67		t.Fatal("mr create failed")
 68	}
 69	if _, _, code := inst.ssh(t, aliceKey, "", "mr", "edit", "alice/app", "1", "--title", "'ready'"); code != 0 {
 70		t.Fatal("mr edit failed")
 71	}
 72	if out, _, _ := inst.ssh(t, aliceKey, "", "mr", "show", "alice/app", "1", "--json"); !strings.Contains(out, "ready") {
 73		t.Fatalf("mr edit not applied: %s", out)
 74	}
 75
 76	// Web edit: form appears for the authorized viewer, POST applies, and
 77	// with write access the label set is replaced.
 78	out, _, code := inst.ssh(t, aliceKey, "", "web", "login", "--json")
 79	if code != 0 {
 80		t.Fatal("web login failed")
 81	}
 82	var env2 struct {
 83		Data struct {
 84			URL string `json:"url"`
 85		} `json:"data"`
 86	}
 87	json.Unmarshal([]byte(out), &env2)
 88	browser := newBrowser(t)
 89	browserGet(t, browser, inst.base()+env2.Data.URL[strings.Index(env2.Data.URL, "/login"):])
 90	_, body := browserGet(t, browser, inst.base()+"/alice/app/issues/1")
 91	if !strings.Contains(body, "/alice/app/issues/1/edit") {
 92		t.Fatal("edit form missing for authorized viewer")
 93	}
 94	if status, _ := browserPost(t, browser, inst.base()+"/alice/app/issues/1/edit",
 95		url.Values{"title": {"web-edited"}, "body": {"web body"}, "labels": {"bug"}}); status != 200 {
 96		t.Fatal("web issue edit failed")
 97	}
 98	out, _, _ = inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "1", "--json")
 99	if !strings.Contains(out, "web-edited") || !strings.Contains(out, `"labels":["bug"]`) {
100		t.Fatalf("web edit not applied: %s", out)
101	}
102	if status, _ := browserPost(t, browser, inst.base()+"/alice/app/mrs/1/edit",
103		url.Values{"title": {"web-mr"}, "body": {"mb"}}); status != 200 {
104		t.Fatal("web mr edit failed")
105	}
106	// Anonymous view shows no edit affordance.
107	_, body = inst.get(t, "/alice/app/issues/1")
108	if strings.Contains(body, "/issues/1/edit") {
109		t.Fatal("edit form leaked to anonymous viewer")
110	}
111}