blob: 29111fcd62f03473446a05089af5c2f5f0174407 [file] [log] [blame]
Russ Coxe7952912014-12-12 16:16:11 -05001// 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
5package main
6
7import (
Austin Clements7cc8d772015-11-05 16:02:35 -05008 "os"
Alex Brainmana8389552016-01-13 14:00:54 +11009 "runtime"
Russ Coxe7952912014-12-12 16:16:11 -050010 "strings"
11 "testing"
12)
13
14func 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 Coxc3e58182014-12-23 14:12:53 -050023 testPrintedStderr(t, "cannot submit: no changes pending")
Russ Coxe7952912014-12-12 16:16:11 -050024 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 Gerrandf473ce12014-12-18 11:25:48 +110033 "git status", "!git stash", "!git add", "git-codereview change")
Russ Coxe7952912014-12-12 16:16:11 -050034 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 Gerrandf473ce12014-12-18 11:25:48 +110040 "git status", "git stash", "git add", "git-codereview change")
Russ Coxe7952912014-12-12 16:16:11 -050041 testNoStdout(t)
42 testRan(t)
Russ Coxccaabdb2014-12-15 17:03:45 -050043 trun(t, gt.client, "git", "add", "file1")
Russ Coxe7952912014-12-12 16:16:11 -050044 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 Coxc3e58182014-12-23 14:12:53 -050050 const id = "I123456789"
Russ Coxe7952912014-12-12 16:16:11 -050051
52 t.Logf("> malformed json")
Russ Coxc3e58182014-12-23 14:12:53 -050053 srv.setJSON(id, "XXX")
Russ Coxe7952912014-12-12 16:16:11 -050054 testMainDied(t, "submit")
55 testRan(t) // nothing
56 testPrintedStderr(t, "malformed json response")
57
58 t.Logf("> unexpected change status")
Russ Coxc3e58182014-12-23 14:12:53 -050059 srv.setJSON(id, `{"status": "UNEXPECTED"}`)
Russ Coxe7952912014-12-12 16:16:11 -050060 testMainDied(t, "submit")
61 testRan(t) // nothing
62 testPrintedStderr(t, "cannot submit: unexpected Gerrit change status \"UNEXPECTED\"")
63
64 t.Logf("> already merged")
Russ Coxc3e58182014-12-23 14:12:53 -050065 srv.setJSON(id, `{"status": "MERGED"}`)
Russ Coxe7952912014-12-12 16:16:11 -050066 testMainDied(t, "submit")
67 testRan(t) // nothing
68 testPrintedStderr(t, "cannot submit: change already submitted, run 'git sync'")
69
70 t.Logf("> abandoned")
Russ Coxc3e58182014-12-23 14:12:53 -050071 srv.setJSON(id, `{"status": "ABANDONED"}`)
Russ Coxe7952912014-12-12 16:16:11 -050072 testMainDied(t, "submit")
73 testRan(t) // nothing
74 testPrintedStderr(t, "cannot submit: change abandoned")
75
76 t.Logf("> missing approval")
Russ Coxc3e58182014-12-23 14:12:53 -050077 srv.setJSON(id, `{"status": "NEW", "labels": {"Code-Review": {}}}`)
Russ Coxe7952912014-12-12 16:16:11 -050078 testMainDied(t, "submit")
79 testRan(t) // nothing
80 testPrintedStderr(t, "cannot submit: change missing Code-Review approval")
81
82 t.Logf("> rejection")
Russ Coxc3e58182014-12-23 14:12:53 -050083 srv.setJSON(id, `{"status": "NEW", "labels": {"Code-Review": {"rejected": {}}}}`)
Russ Coxe7952912014-12-12 16:16:11 -050084 testMainDied(t, "submit")
85 testRan(t) // nothing
86 testPrintedStderr(t, "cannot submit: change has Code-Review rejection")
87
88 t.Logf("> unmergeable")
Russ Coxc3e58182014-12-23 14:12:53 -050089 srv.setJSON(id, `{"status": "NEW", "mergeable": false, "labels": {"Code-Review": {"approved": {}}}}`)
Russ Coxe7952912014-12-12 16:16:11 -050090 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 Coxc3e58182014-12-23 14:12:53 -050096 srv.setJSON(id, newJSON)
Russ Coxe7952912014-12-12 16:16:11 -050097 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 Coxccaabdb2014-12-15 17:03:45 -0500100 testPrintedStderr(t, "submit error: unexpected post-submit Gerrit change status \"NEW\"")
Russ Coxe7952912014-12-12 16:16:11 -0500101}
102
103func 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
124func 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 Clements0d7a1432015-11-05 15:02:37 -0500168
169func TestSubmitMultiple(t *testing.T) {
170 gt := newGitTest(t)
171 defer gt.done()
172
173 srv := newGerritServer(t)
174 defer srv.done()
175
Austin Clements7cc8d772015-11-05 16:02:35 -0500176 cl1, cl2 := testSubmitMultiple(t, gt, srv)
177 testMain(t, "submit", cl1.CurrentRevision, cl2.CurrentRevision)
178}
179
Austin Clements36fe8922016-02-05 11:19:05 -0500180func 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 Clements7cc8d772015-11-05 16:02:35 -0500191func TestSubmitInteractive(t *testing.T) {
Alex Brainmana8389552016-01-13 14:00:54 +1100192 if runtime.GOOS == "windows" {
193 t.Skip("see golang.org/issue/13406")
194 }
195
Austin Clements7cc8d772015-11-05 16:02:35 -0500196 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
213func testSubmitMultiple(t *testing.T, gt *gitTest, srv *gerritServer) (*GerritChange, *GerritChange) {
Austin Clements0d7a1432015-11-05 15:02:37 -0500214 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 Clements7cc8d772015-11-05 16:02:35 -0500261 return &cl1, &cl2
Austin Clements0d7a1432015-11-05 15:02:37 -0500262}