e2e/rangediff_test.go
124 lines · 4709 bytes
1package e2e
2
3import (
4 "encoding/json"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11// TestMRRangeDiff is #111's last stage: a push stales every review and
12// nothing said what had changed between the two heads. A plain diff of
13// the heads cannot answer that — it shows the whole branch again.
14func TestMRRangeDiff(t *testing.T) {
15 inst := startInstance(t)
16 key := inst.newKey(t, "alice")
17 inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub")
18 if _, errOut, code := inst.ssh(t, key, "", "repo", "create", "alice/app"); code != 0 {
19 t.Fatalf("repo create: %s", errOut)
20 }
21 env := inst.gitEnv(key)
22 work := t.TempDir()
23 mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
24 dir := filepath.Join(work, "w")
25 os.WriteFile(filepath.Join(dir, "a.txt"), []byte("one\n"), 0o644)
26 mustGit(t, dir, env, "checkout", "-q", "-b", "main")
27 mustGit(t, dir, env, "add", ".")
28 mustGit(t, dir, env, "commit", "-q", "-m", "base")
29 mustGit(t, dir, env, "push", "-q", "origin", "main")
30
31 mustGit(t, dir, env, "checkout", "-q", "-b", "feat")
32 os.WriteFile(filepath.Join(dir, "b.txt"), []byte("alpha\nbeta\ngamma\n"), 0o644)
33 mustGit(t, dir, env, "add", ".")
34 mustGit(t, dir, env, "commit", "-q", "-m", "add b")
35 mustGit(t, dir, env, "push", "-q", "origin", "feat")
36 if _, errOut, code := inst.ssh(t, key, "", "mr", "create", "alice/app",
37 "--source", "feat", "--target", "main", "--title", "'add b'"); code != 0 {
38 t.Fatalf("mr create: %s", errOut)
39 }
40
41 // One revision: nothing to compare, and saying so is not a failure.
42 out, errOut, code := inst.ssh(t, key, "", "mr", "range-diff", "alice/app", "1")
43 if code != 0 || !strings.Contains(errOut, "one revision") {
44 t.Fatalf("single-revision range-diff: exit %d, %s, %s", code, errOut, out)
45 }
46
47 // Amend and force-push: the same commit with one line changed, which
48 // is what addressing review feedback looks like. A diff of the two
49 // heads cannot describe this — it shows the whole branch again.
50 os.WriteFile(filepath.Join(dir, "b.txt"), []byte("alpha\nbeta revised\ngamma\n"), 0o644)
51 mustGit(t, dir, env, "add", ".")
52 mustGit(t, dir, env, "commit", "-q", "--amend", "--no-edit")
53 mustGit(t, dir, env, "push", "-q", "--force", "origin", "feat")
54
55 revs := revisions(t, inst, key)
56 if len(revs) != 2 {
57 t.Fatalf("revisions = %d, want 2 after a force-push: %+v", len(revs), revs)
58 }
59 if !revs[1].Current {
60 t.Fatalf("the newest revision is not marked current: %+v", revs)
61 }
62
63 out, errOut, code = inst.ssh(t, key, "", "mr", "range-diff", "alice/app", "1")
64 if code != 0 {
65 t.Fatalf("range-diff: %s", errOut)
66 }
67 // The two versions of the one commit are paired — "1: <old> ! 1:
68 // <new>" — and the interdiff shows the one line that moved, not the
69 // whole branch.
70 if !strings.Contains(out, "add b") {
71 t.Fatalf("range-diff does not mention the commit:\n%s", out)
72 }
73 if !strings.Contains(out, "!") {
74 t.Fatalf("range-diff did not pair the amended commit:\n%s", out)
75 }
76 if !strings.Contains(out, "beta revised") {
77 t.Fatalf("range-diff does not show the changed line:\n%s", out)
78 }
79 // One commit on each side, paired: a plain diff of the two heads
80 // would instead show b.txt created from nothing all over again.
81 if strings.Count(out, "add b") != 1 {
82 t.Fatalf("range-diff lists the commit more than once:\n%s", out)
83 }
84
85 // Naming revisions explicitly, and refusing one that is not a
86 // revision of this merge request.
87 if _, _, code := inst.ssh(t, key, "", "mr", "range-diff", "alice/app", "1",
88 "--from", revs[0].SHA, "--to", revs[1].SHA); code != 0 {
89 t.Fatal("explicit --from/--to failed")
90 }
91 if _, errOut, code := inst.ssh(t, key, "", "mr", "range-diff", "alice/app", "1",
92 "--from", "0123456789ab"); code != 3 || !strings.Contains(errOut, "not a revision") {
93 t.Fatalf("unknown revision: exit %d, %s", code, errOut)
94 }
95 if _, _, code := inst.ssh(t, key, "", "mr", "range-diff", "alice/app", "1",
96 "--from", revs[1].SHA, "--to", revs[1].SHA); code != 2 {
97 t.Fatal("comparing a revision with itself was accepted")
98 }
99
100 // A push that changes nothing does not add a revision.
101 mustGit(t, dir, env, "push", "-q", "--force", "origin", "feat")
102 if got := revisions(t, inst, key); len(got) != 2 {
103 t.Fatalf("a no-op push added a revision: %d", len(got))
104 }
105}
106
107type revision struct {
108 N int `json:"n"`
109 SHA string `json:"sha"`
110 Current bool `json:"current"`
111}
112
113func revisions(t *testing.T, inst *instance, key string) []revision {
114 t.Helper()
115 out, errOut, code := inst.ssh(t, key, "", "mr", "revisions", "alice/app", "1", "--json")
116 if code != 0 {
117 t.Fatalf("mr revisions: %s", errOut)
118 }
119 var env struct {
120 Data []revision `json:"data"`
121 }
122 json.Unmarshal([]byte(out), &env)
123 return env.Data
124}