1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.transport;
12
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertTrue;
16
17 import java.io.ByteArrayOutputStream;
18 import java.io.IOException;
19 import java.io.OutputStream;
20 import java.io.PrintStream;
21 import java.nio.charset.StandardCharsets;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Map;
25
26 import org.eclipse.jgit.api.errors.AbortedByHookException;
27 import org.eclipse.jgit.errors.NotSupportedException;
28 import org.eclipse.jgit.errors.TransportException;
29 import org.eclipse.jgit.hooks.PrePushHook;
30 import org.eclipse.jgit.lib.ObjectId;
31 import org.eclipse.jgit.lib.ObjectIdRef;
32 import org.eclipse.jgit.lib.ProgressMonitor;
33 import org.eclipse.jgit.lib.Ref;
34 import org.eclipse.jgit.lib.RefUpdate.Result;
35 import org.eclipse.jgit.lib.Repository;
36 import org.eclipse.jgit.lib.TextProgressMonitor;
37 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
38 import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
39 import org.eclipse.jgit.util.io.NullOutputStream;
40 import org.junit.Before;
41 import org.junit.Test;
42
43 public class PushProcessTest extends SampleDataRepositoryTestCase {
44 private PushProcess process;
45
46 private MockTransport transport;
47
48 private HashSet<RemoteRefUpdate> refUpdates;
49
50 private HashSet<Ref> advertisedRefs;
51
52 private Status connectionUpdateStatus;
53
54 @Override
55 @Before
56 public void setUp() throws Exception {
57 super.setUp();
58 transport = new MockTransport(db, new URIish());
59 refUpdates = new HashSet<>();
60 advertisedRefs = new HashSet<>();
61 connectionUpdateStatus = Status.OK;
62 }
63
64
65
66
67
68
69 @Test
70 public void testUpdateFastForward() throws IOException {
71 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
72 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
73 "refs/heads/master", false, null, null);
74 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
75 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
76 testOneUpdateStatus(rru, ref, Status.OK, Boolean.TRUE);
77 }
78
79
80
81
82
83
84
85 @Test
86 public void testUpdateNonFastForwardUnknownObject() throws IOException {
87 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
88 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
89 "refs/heads/master", false, null, null);
90 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
91 ObjectId.fromString("0000000000000000000000000000000000000001"));
92 testOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);
93 }
94
95
96
97
98
99
100
101 @Test
102 public void testUpdateNonFastForward() throws IOException {
103 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
104 "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
105 "refs/heads/master", false, null, null);
106 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
107 ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
108 testOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);
109 }
110
111
112
113
114
115
116 @Test
117 public void testUpdateNonFastForwardForced() throws IOException {
118 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
119 "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
120 "refs/heads/master", true, null, null);
121 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
122 ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
123 testOneUpdateStatus(rru, ref, Status.OK, Boolean.FALSE);
124 }
125
126
127
128
129
130
131 @Test
132 public void testUpdateCreateRef() throws IOException {
133 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
134 "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
135 "refs/heads/master", false, null, null);
136 testOneUpdateStatus(rru, null, Status.OK, Boolean.TRUE);
137 }
138
139
140
141
142
143
144 @Test
145 public void testUpdateDelete() throws IOException {
146 final RemoteRefUpdate rru = new RemoteRefUpdate(db, (String) null,
147 "refs/heads/master", false, null, null);
148 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
149 ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
150 testOneUpdateStatus(rru, ref, Status.OK, Boolean.TRUE);
151 }
152
153
154
155
156
157
158
159 @Test
160 public void testUpdateDeleteNonExisting() throws IOException {
161 final RemoteRefUpdate rru = new RemoteRefUpdate(db, (String) null,
162 "refs/heads/master", false, null, null);
163 testOneUpdateStatus(rru, null, Status.NON_EXISTING, null);
164 }
165
166
167
168
169
170
171 @Test
172 public void testUpdateUpToDate() throws IOException {
173 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
174 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
175 "refs/heads/master", false, null, null);
176 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
177 ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
178 testOneUpdateStatus(rru, ref, Status.UP_TO_DATE, null);
179 }
180
181
182
183
184
185
186 @Test
187 public void testUpdateExpectedRemote() throws IOException {
188 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
189 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
190 "refs/heads/master", false, null, ObjectId
191 .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
192 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
193 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
194 testOneUpdateStatus(rru, ref, Status.OK, Boolean.TRUE);
195 }
196
197
198
199
200
201
202
203 @Test
204 public void testUpdateUnexpectedRemote() throws IOException {
205 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
206 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
207 "refs/heads/master", false, null, ObjectId
208 .fromString("0000000000000000000000000000000000000001"));
209 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
210 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
211 testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);
212 }
213
214
215
216
217
218
219
220
221 @Test
222 public void testUpdateUnexpectedRemoteVsForce() throws IOException {
223 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
224 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
225 "refs/heads/master", true, null, ObjectId
226 .fromString("0000000000000000000000000000000000000001"));
227 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
228 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
229 try (ByteArrayOutputStream bytes = new ByteArrayOutputStream();
230 PrintStream out = new PrintStream(bytes, true,
231 StandardCharsets.UTF_8);
232 PrintStream err = new PrintStream(NullOutputStream.INSTANCE)) {
233 MockPrePushHook hook = new MockPrePushHook(db, out, err);
234 testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null,
235 hook);
236 out.flush();
237 String result = new String(bytes.toString(StandardCharsets.UTF_8));
238 assertEquals("", result);
239 }
240 }
241
242
243
244
245
246
247 @Test
248 public void testUpdateRejectedByConnection() throws IOException {
249 connectionUpdateStatus = Status.REJECTED_OTHER_REASON;
250 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
251 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
252 "refs/heads/master", false, null, null);
253 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
254 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
255 testOneUpdateStatus(rru, ref, Status.REJECTED_OTHER_REASON, null);
256 }
257
258
259
260
261
262
263
264 @Test
265 public void testUpdateMixedCases() throws IOException {
266 final RemoteRefUpdate rruOk = new RemoteRefUpdate(db, (String) null,
267 "refs/heads/master", false, null, null);
268 final Ref refToChange = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
269 ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
270 final RemoteRefUpdate rruReject = new RemoteRefUpdate(db,
271 (String) null, "refs/heads/nonexisting", false, null, null);
272 refUpdates.add(rruOk);
273 refUpdates.add(rruReject);
274 advertisedRefs.add(refToChange);
275 try (ByteArrayOutputStream bytes = new ByteArrayOutputStream();
276 PrintStream out = new PrintStream(bytes, true,
277 StandardCharsets.UTF_8);
278 PrintStream err = new PrintStream(NullOutputStream.INSTANCE)) {
279 MockPrePushHook hook = new MockPrePushHook(db, out, err);
280 executePush(hook);
281 assertEquals(Status.OK, rruOk.getStatus());
282 assertTrue(rruOk.isFastForward());
283 assertEquals(Status.NON_EXISTING, rruReject.getStatus());
284 out.flush();
285 String result = new String(bytes.toString(StandardCharsets.UTF_8));
286 assertEquals(
287 "null 0000000000000000000000000000000000000000 "
288 + "refs/heads/master 2c349335b7f797072cf729c4f3bb0914ecb6dec9\n",
289 result);
290 }
291 }
292
293
294
295
296
297
298 @Test
299 public void testTrackingRefUpdateEnabled() throws IOException {
300 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
301 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
302 "refs/heads/master", false, "refs/remotes/test/master", null);
303 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
304 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
305 refUpdates.add(rru);
306 advertisedRefs.add(ref);
307 final PushResult result = executePush();
308 final TrackingRefUpdate tru = result
309 .getTrackingRefUpdate("refs/remotes/test/master");
310 assertNotNull(tru);
311 assertEquals("refs/remotes/test/master", tru.getLocalName());
312 assertEquals(Result.NEW, tru.getResult());
313 }
314
315
316
317
318
319
320 @Test
321 public void testTrackingRefUpdateDisabled() throws IOException {
322 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
323 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
324 "refs/heads/master", false, null, null);
325 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
326 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
327 refUpdates.add(rru);
328 advertisedRefs.add(ref);
329 final PushResult result = executePush();
330 assertTrue(result.getTrackingRefUpdates().isEmpty());
331 }
332
333
334
335
336
337
338 @Test
339 public void testTrackingRefUpdateOnReject() throws IOException {
340 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
341 "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
342 "refs/heads/master", false, null, null);
343 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
344 ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
345 final PushResult result = testOneUpdateStatus(rru, ref,
346 Status.REJECTED_NONFASTFORWARD, null);
347 assertTrue(result.getTrackingRefUpdates().isEmpty());
348 }
349
350
351
352
353
354
355 @Test
356 public void testPushResult() throws IOException {
357 final RemoteRefUpdate rru = new RemoteRefUpdate(db,
358 "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
359 "refs/heads/master", false, "refs/remotes/test/master", null);
360 final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
361 ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
362 refUpdates.add(rru);
363 advertisedRefs.add(ref);
364 final PushResult result = executePush();
365 assertEquals(1, result.getTrackingRefUpdates().size());
366 assertEquals(1, result.getAdvertisedRefs().size());
367 assertEquals(1, result.getRemoteUpdates().size());
368 assertNotNull(result.getTrackingRefUpdate("refs/remotes/test/master"));
369 assertNotNull(result.getAdvertisedRef("refs/heads/master"));
370 assertNotNull(result.getRemoteUpdate("refs/heads/master"));
371 }
372
373 private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
374 final Ref advertisedRef, final Status expectedStatus,
375 Boolean fastForward) throws NotSupportedException,
376 TransportException {
377 return testOneUpdateStatus(rru, advertisedRef, expectedStatus,
378 fastForward, null);
379 }
380
381 private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
382 final Ref advertisedRef, final Status expectedStatus,
383 Boolean fastForward, PrePushHook hook)
384 throws NotSupportedException, TransportException {
385 refUpdates.add(rru);
386 if (advertisedRef != null)
387 advertisedRefs.add(advertisedRef);
388 final PushResult result = executePush(hook);
389 assertEquals(expectedStatus, rru.getStatus());
390 if (fastForward != null)
391 assertEquals(fastForward, Boolean.valueOf(rru.isFastForward()));
392 return result;
393 }
394
395 private PushResult executePush() throws NotSupportedException,
396 TransportException {
397 return executePush(null);
398 }
399
400 private PushResult executePush(PrePushHook hook)
401 throws NotSupportedException, TransportException {
402 process = new PushProcess(transport, refUpdates, hook);
403 return process.execute(new TextProgressMonitor());
404 }
405
406 private class MockTransport extends Transport {
407 MockTransport(Repository local, URIish uri) {
408 super(local, uri);
409 }
410
411 @Override
412 public FetchConnection openFetch() throws NotSupportedException,
413 TransportException {
414 throw new NotSupportedException("mock");
415 }
416
417 @Override
418 public PushConnection openPush() throws NotSupportedException,
419 TransportException {
420 return new MockPushConnection();
421 }
422
423 @Override
424 public void close() {
425
426 }
427 }
428
429 private class MockPushConnection extends BaseConnection implements
430 PushConnection {
431 MockPushConnection() {
432 final Map<String, Ref> refsMap = new HashMap<>();
433 for (Ref r : advertisedRefs)
434 refsMap.put(r.getName(), r);
435 available(refsMap);
436 }
437
438 @Override
439 public void close() {
440
441 }
442
443 @Override
444 public void push(ProgressMonitor monitor,
445 Map<String, RemoteRefUpdate> refsToUpdate, OutputStream out)
446 throws TransportException {
447 push(monitor, refsToUpdate);
448 }
449
450 @Override
451 public void push(ProgressMonitor monitor,
452 Map<String, RemoteRefUpdate> refsToUpdate)
453 throws TransportException {
454 for (RemoteRefUpdate rru : refsToUpdate.values()) {
455 assertEquals(Status.NOT_ATTEMPTED, rru.getStatus());
456 rru.setStatus(connectionUpdateStatus);
457 }
458 }
459 }
460
461 private static class MockPrePushHook extends PrePushHook {
462
463 private final PrintStream output;
464
465 public MockPrePushHook(Repository repo, PrintStream out,
466 PrintStream err) {
467 super(repo, out, err);
468 output = out;
469 }
470
471 @Override
472 protected void doRun() throws AbortedByHookException, IOException {
473 output.print(getStdinArgs());
474 }
475 }
476 }