Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 1 | // Copyright 2014 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package main |
| 6 | |
| 7 | import ( |
Austin Clements | 7cc8d77 | 2015-11-05 16:02:35 -0500 | [diff] [blame] | 8 | "os" |
Alex Brainman | a838955 | 2016-01-13 14:00:54 +1100 | [diff] [blame] | 9 | "runtime" |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 10 | "strings" |
| 11 | "testing" |
| 12 | ) |
| 13 | |
| 14 | func TestSubmitErrors(t *testing.T) { |
| 15 | gt := newGitTest(t) |
| 16 | defer gt.done() |
| 17 | |
| 18 | srv := newGerritServer(t) |
| 19 | defer srv.done() |
| 20 | |
| 21 | t.Logf("> no commit") |
| 22 | testMainDied(t, "submit") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 23 | testPrintedStderr(t, "cannot submit: no changes pending") |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 24 | write(t, gt.client+"/file1", "") |
| 25 | trun(t, gt.client, "git", "add", "file1") |
| 26 | trun(t, gt.client, "git", "commit", "-m", "msg\n\nChange-Id: I123456789\n") |
| 27 | |
| 28 | t.Logf("> staged changes") |
| 29 | write(t, gt.client+"/file1", "asdf") |
| 30 | trun(t, gt.client, "git", "add", "file1") |
| 31 | testMainDied(t, "submit") |
| 32 | testPrintedStderr(t, "cannot submit: staged changes exist", |
Andrew Gerrand | f473ce1 | 2014-12-18 11:25:48 +1100 | [diff] [blame] | 33 | "git status", "!git stash", "!git add", "git-codereview change") |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 34 | testNoStdout(t) |
| 35 | |
| 36 | t.Logf("> unstaged changes") |
| 37 | write(t, gt.client+"/file1", "actual content") |
| 38 | testMainDied(t, "submit") |
| 39 | testPrintedStderr(t, "cannot submit: unstaged changes exist", |
Andrew Gerrand | f473ce1 | 2014-12-18 11:25:48 +1100 | [diff] [blame] | 40 | "git status", "git stash", "git add", "git-codereview change") |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 41 | testNoStdout(t) |
| 42 | testRan(t) |
Russ Cox | ccaabdb | 2014-12-15 17:03:45 -0500 | [diff] [blame] | 43 | trun(t, gt.client, "git", "add", "file1") |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 44 | trun(t, gt.client, "git", "commit", "--amend", "--no-edit") |
| 45 | |
| 46 | t.Logf("> not found") |
| 47 | testMainDied(t, "submit") |
| 48 | testPrintedStderr(t, "change not found on Gerrit server") |
| 49 | |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 50 | const id = "I123456789" |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 51 | |
| 52 | t.Logf("> malformed json") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 53 | srv.setJSON(id, "XXX") |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 54 | testMainDied(t, "submit") |
| 55 | testRan(t) // nothing |
| 56 | testPrintedStderr(t, "malformed json response") |
| 57 | |
| 58 | t.Logf("> unexpected change status") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 59 | srv.setJSON(id, `{"status": "UNEXPECTED"}`) |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 60 | testMainDied(t, "submit") |
| 61 | testRan(t) // nothing |
| 62 | testPrintedStderr(t, "cannot submit: unexpected Gerrit change status \"UNEXPECTED\"") |
| 63 | |
| 64 | t.Logf("> already merged") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 65 | srv.setJSON(id, `{"status": "MERGED"}`) |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 66 | testMainDied(t, "submit") |
| 67 | testRan(t) // nothing |
| 68 | testPrintedStderr(t, "cannot submit: change already submitted, run 'git sync'") |
| 69 | |
| 70 | t.Logf("> abandoned") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 71 | srv.setJSON(id, `{"status": "ABANDONED"}`) |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 72 | testMainDied(t, "submit") |
| 73 | testRan(t) // nothing |
| 74 | testPrintedStderr(t, "cannot submit: change abandoned") |
| 75 | |
| 76 | t.Logf("> missing approval") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 77 | srv.setJSON(id, `{"status": "NEW", "labels": {"Code-Review": {}}}`) |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 78 | testMainDied(t, "submit") |
| 79 | testRan(t) // nothing |
| 80 | testPrintedStderr(t, "cannot submit: change missing Code-Review approval") |
| 81 | |
| 82 | t.Logf("> rejection") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 83 | srv.setJSON(id, `{"status": "NEW", "labels": {"Code-Review": {"rejected": {}}}}`) |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 84 | testMainDied(t, "submit") |
| 85 | testRan(t) // nothing |
| 86 | testPrintedStderr(t, "cannot submit: change has Code-Review rejection") |
| 87 | |
| 88 | t.Logf("> unmergeable") |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 89 | srv.setJSON(id, `{"status": "NEW", "mergeable": false, "labels": {"Code-Review": {"approved": {}}}}`) |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 90 | testMainDied(t, "submit") |
| 91 | testRan(t, "git push -q origin HEAD:refs/for/master") |
| 92 | testPrintedStderr(t, "cannot submit: conflicting changes submitted, run 'git sync'") |
| 93 | |
| 94 | t.Logf("> submit with unexpected status") |
| 95 | const newJSON = `{"status": "NEW", "mergeable": true, "labels": {"Code-Review": {"approved": {}}}}` |
Russ Cox | c3e5818 | 2014-12-23 14:12:53 -0500 | [diff] [blame] | 96 | srv.setJSON(id, newJSON) |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 97 | srv.setReply("/a/changes/proj~master~I123456789/submit", gerritReply{body: ")]}'\n" + newJSON}) |
| 98 | testMainDied(t, "submit") |
| 99 | testRan(t, "git push -q origin HEAD:refs/for/master") |
Russ Cox | ccaabdb | 2014-12-15 17:03:45 -0500 | [diff] [blame] | 100 | testPrintedStderr(t, "submit error: unexpected post-submit Gerrit change status \"NEW\"") |
Russ Cox | e795291 | 2014-12-12 16:16:11 -0500 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | func TestSubmitTimeout(t *testing.T) { |
| 104 | gt := newGitTest(t) |
| 105 | defer gt.done() |
| 106 | srv := newGerritServer(t) |
| 107 | defer srv.done() |
| 108 | |
| 109 | gt.work(t) |
| 110 | |
| 111 | setJSON := func(json string) { |
| 112 | srv.setReply("/a/changes/proj~master~I123456789", gerritReply{body: ")]}'\n" + json}) |
| 113 | } |
| 114 | |
| 115 | t.Log("> submit with timeout") |
| 116 | const submittedJSON = `{"status": "SUBMITTED", "mergeable": true, "labels": {"Code-Review": {"approved": {}}}}` |
| 117 | setJSON(submittedJSON) |
| 118 | srv.setReply("/a/changes/proj~master~I123456789/submit", gerritReply{body: ")]}'\n" + submittedJSON}) |
| 119 | testMainDied(t, "submit") |
| 120 | testRan(t, "git push -q origin HEAD:refs/for/master") |
| 121 | testPrintedStderr(t, "cannot submit: timed out waiting for change to be submitted by Gerrit") |
| 122 | } |
| 123 | |
| 124 | func TestSubmit(t *testing.T) { |
| 125 | gt := newGitTest(t) |
| 126 | defer gt.done() |
| 127 | srv := newGerritServer(t) |
| 128 | defer srv.done() |
| 129 | |
| 130 | gt.work(t) |
| 131 | trun(t, gt.client, "git", "tag", "-f", "work.mailed") |
| 132 | clientHead := strings.TrimSpace(trun(t, gt.client, "git", "log", "-n", "1", "--format=format:%H")) |
| 133 | |
| 134 | write(t, gt.server+"/file", "another change") |
| 135 | trun(t, gt.server, "git", "add", "file") |
| 136 | trun(t, gt.server, "git", "commit", "-m", "conflict") |
| 137 | serverHead := strings.TrimSpace(trun(t, gt.server, "git", "log", "-n", "1", "--format=format:%H")) |
| 138 | |
| 139 | t.Log("> submit") |
| 140 | var ( |
| 141 | newJSON = `{"status": "NEW", "mergeable": true, "current_revision": "` + clientHead + `", "labels": {"Code-Review": {"approved": {}}}}` |
| 142 | submittedJSON = `{"status": "SUBMITTED", "mergeable": true, "current_revision": "` + clientHead + `", "labels": {"Code-Review": {"approved": {}}}}` |
| 143 | mergedJSON = `{"status": "MERGED", "mergeable": true, "current_revision": "` + serverHead + `", "labels": {"Code-Review": {"approved": {}}}}` |
| 144 | ) |
| 145 | submitted := false |
| 146 | npoll := 0 |
| 147 | srv.setReply("/a/changes/proj~master~I123456789", gerritReply{f: func() gerritReply { |
| 148 | if !submitted { |
| 149 | return gerritReply{body: ")]}'\n" + newJSON} |
| 150 | } |
| 151 | if npoll++; npoll <= 2 { |
| 152 | return gerritReply{body: ")]}'\n" + submittedJSON} |
| 153 | } |
| 154 | return gerritReply{body: ")]}'\n" + mergedJSON} |
| 155 | }}) |
| 156 | srv.setReply("/a/changes/proj~master~I123456789/submit", gerritReply{f: func() gerritReply { |
| 157 | if submitted { |
| 158 | return gerritReply{status: 409} |
| 159 | } |
| 160 | submitted = true |
| 161 | return gerritReply{body: ")]}'\n" + submittedJSON} |
| 162 | }}) |
| 163 | testMain(t, "submit") |
| 164 | testRan(t, |
| 165 | "git fetch -q", |
| 166 | "git checkout -q -B work "+serverHead+" --") |
| 167 | } |
Austin Clements | 0d7a143 | 2015-11-05 15:02:37 -0500 | [diff] [blame] | 168 | |
| 169 | func TestSubmitMultiple(t *testing.T) { |
| 170 | gt := newGitTest(t) |
| 171 | defer gt.done() |
| 172 | |
| 173 | srv := newGerritServer(t) |
| 174 | defer srv.done() |
| 175 | |
Austin Clements | 7cc8d77 | 2015-11-05 16:02:35 -0500 | [diff] [blame] | 176 | cl1, cl2 := testSubmitMultiple(t, gt, srv) |
| 177 | testMain(t, "submit", cl1.CurrentRevision, cl2.CurrentRevision) |
| 178 | } |
| 179 | |
Austin Clements | 36fe892 | 2016-02-05 11:19:05 -0500 | [diff] [blame] | 180 | func TestSubmitMultipleNamed(t *testing.T) { |
| 181 | gt := newGitTest(t) |
| 182 | defer gt.done() |
| 183 | |
| 184 | srv := newGerritServer(t) |
| 185 | defer srv.done() |
| 186 | |
| 187 | _, _ = testSubmitMultiple(t, gt, srv) |
| 188 | testMain(t, "submit", "HEAD^", "HEAD") |
| 189 | } |
| 190 | |
Austin Clements | 7cc8d77 | 2015-11-05 16:02:35 -0500 | [diff] [blame] | 191 | func TestSubmitInteractive(t *testing.T) { |
Alex Brainman | a838955 | 2016-01-13 14:00:54 +1100 | [diff] [blame] | 192 | if runtime.GOOS == "windows" { |
| 193 | t.Skip("see golang.org/issue/13406") |
| 194 | } |
| 195 | |
Austin Clements | 7cc8d77 | 2015-11-05 16:02:35 -0500 | [diff] [blame] | 196 | gt := newGitTest(t) |
| 197 | defer gt.done() |
| 198 | |
| 199 | srv := newGerritServer(t) |
| 200 | defer srv.done() |
| 201 | |
| 202 | cl1, cl2 := testSubmitMultiple(t, gt, srv) |
| 203 | os.Setenv("GIT_EDITOR", "echo "+cl1.CurrentRevision+" > ") |
| 204 | testMain(t, "submit", "-i") |
| 205 | if cl1.Status != "MERGED" { |
| 206 | t.Fatalf("want cl1.Status == MERGED; got %v", cl1.Status) |
| 207 | } |
| 208 | if cl2.Status != "NEW" { |
| 209 | t.Fatalf("want cl2.Status == NEW; got %v", cl1.Status) |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | func testSubmitMultiple(t *testing.T, gt *gitTest, srv *gerritServer) (*GerritChange, *GerritChange) { |
Austin Clements | 0d7a143 | 2015-11-05 15:02:37 -0500 | [diff] [blame] | 214 | write(t, gt.client+"/file1", "") |
| 215 | trun(t, gt.client, "git", "add", "file1") |
| 216 | trun(t, gt.client, "git", "commit", "-m", "msg\n\nChange-Id: I0000001\n") |
| 217 | hash1 := strings.TrimSpace(trun(t, gt.client, "git", "log", "-n", "1", "--format=format:%H")) |
| 218 | |
| 219 | write(t, gt.client+"/file2", "") |
| 220 | trun(t, gt.client, "git", "add", "file2") |
| 221 | trun(t, gt.client, "git", "commit", "-m", "msg\n\nChange-Id: I0000002\n") |
| 222 | hash2 := strings.TrimSpace(trun(t, gt.client, "git", "log", "-n", "1", "--format=format:%H")) |
| 223 | |
| 224 | testMainDied(t, "submit") |
| 225 | testPrintedStderr(t, "cannot submit: multiple changes pending") |
| 226 | |
| 227 | cl1 := GerritChange{ |
| 228 | Status: "NEW", |
| 229 | Mergeable: true, |
| 230 | CurrentRevision: hash1, |
| 231 | Labels: map[string]*GerritLabel{"Code-Review": &GerritLabel{Approved: new(GerritAccount)}}, |
| 232 | } |
| 233 | cl2 := GerritChange{ |
| 234 | Status: "NEW", |
| 235 | Mergeable: false, |
| 236 | CurrentRevision: hash2, |
| 237 | Labels: map[string]*GerritLabel{"Code-Review": &GerritLabel{Approved: new(GerritAccount)}}, |
| 238 | } |
| 239 | |
| 240 | srv.setReply("/a/changes/proj~master~I0000001", gerritReply{f: func() gerritReply { |
| 241 | return gerritReply{json: cl1} |
| 242 | }}) |
| 243 | srv.setReply("/a/changes/proj~master~I0000001/submit", gerritReply{f: func() gerritReply { |
| 244 | if cl1.Status != "NEW" { |
| 245 | return gerritReply{status: 409} |
| 246 | } |
| 247 | cl1.Status = "MERGED" |
| 248 | cl2.Mergeable = true |
| 249 | return gerritReply{json: cl1} |
| 250 | }}) |
| 251 | srv.setReply("/a/changes/proj~master~I0000002", gerritReply{f: func() gerritReply { |
| 252 | return gerritReply{json: cl2} |
| 253 | }}) |
| 254 | srv.setReply("/a/changes/proj~master~I0000002/submit", gerritReply{f: func() gerritReply { |
| 255 | if cl2.Status != "NEW" || !cl2.Mergeable { |
| 256 | return gerritReply{status: 409} |
| 257 | } |
| 258 | cl2.Status = "MERGED" |
| 259 | return gerritReply{json: cl2} |
| 260 | }}) |
Austin Clements | 7cc8d77 | 2015-11-05 16:02:35 -0500 | [diff] [blame] | 261 | return &cl1, &cl2 |
Austin Clements | 0d7a143 | 2015-11-05 15:02:37 -0500 | [diff] [blame] | 262 | } |