1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.transport;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertNull;
48 import static org.junit.Assert.assertSame;
49 import static org.junit.Assert.fail;
50
51 import java.io.IOException;
52 import java.net.URISyntaxException;
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.List;
56
57 import org.eclipse.jgit.api.Git;
58 import org.eclipse.jgit.api.PushCommand;
59 import org.eclipse.jgit.api.errors.GitAPIException;
60 import org.eclipse.jgit.api.errors.NoFilepatternException;
61 import org.eclipse.jgit.api.errors.TransportException;
62 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
63 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
64 import org.eclipse.jgit.junit.RepositoryTestCase;
65 import org.eclipse.jgit.lib.Constants;
66 import org.eclipse.jgit.lib.NullProgressMonitor;
67 import org.eclipse.jgit.lib.ObjectId;
68 import org.eclipse.jgit.lib.ObjectInserter;
69 import org.eclipse.jgit.lib.Repository;
70 import org.eclipse.jgit.lib.StoredConfig;
71 import org.eclipse.jgit.revwalk.RevCommit;
72 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
73 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
74 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
75 import org.junit.After;
76 import org.junit.Before;
77 import org.junit.Test;
78
79 public class PushOptionsTest extends RepositoryTestCase {
80 private URIish uri;
81 private TestProtocol<Object> testProtocol;
82 private Object ctx = new Object();
83 private InMemoryRepository server;
84 private InMemoryRepository client;
85 private ObjectId obj1;
86 private ObjectId obj2;
87 private ReceivePack receivePack;
88
89 @Before
90 public void setUp() throws Exception {
91 super.setUp();
92
93 server = newRepo("server");
94 client = newRepo("client");
95
96 testProtocol = new TestProtocol<>(null,
97 new ReceivePackFactory<Object>() {
98 @Override
99 public ReceivePack create(Object req, Repository git)
100 throws ServiceNotEnabledException,
101 ServiceNotAuthorizedException {
102 receivePack = new ReceivePack(git);
103 receivePack.setAllowPushOptions(true);
104 receivePack.setAtomic(true);
105 return receivePack;
106 }
107 });
108
109 uri = testProtocol.register(ctx, server);
110
111 try (ObjectInserter ins = client.newObjectInserter()) {
112 obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
113 obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
114 ins.flush();
115 }
116 }
117
118 @After
119 public void tearDown() {
120 Transport.unregister(testProtocol);
121 }
122
123 private static InMemoryRepository newRepo(String name) {
124 return new InMemoryRepository(new DfsRepositoryDescription(name));
125 }
126
127 private List<RemoteRefUpdate> commands(boolean atomicSafe)
128 throws IOException {
129 List<RemoteRefUpdate> cmds = new ArrayList<>();
130 cmds.add(new RemoteRefUpdate(null, null, obj1, "refs/heads/one",
131 true , null ,
132 ObjectId.zeroId()));
133 cmds.add(new RemoteRefUpdate(null, null, obj2, "refs/heads/two",
134 true , null ,
135 atomicSafe ? ObjectId.zeroId() : obj1));
136 return cmds;
137 }
138
139 private void connectLocalToRemote(Git local, Git remote)
140 throws URISyntaxException, IOException {
141 StoredConfig config = local.getRepository().getConfig();
142 RemoteConfig remoteConfig = new RemoteConfig(config, "test");
143 remoteConfig.addURI(new URIish(
144 remote.getRepository().getDirectory().toURI().toURL()));
145 remoteConfig.addFetchRefSpec(
146 new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
147 remoteConfig.update(config);
148 config.save();
149 }
150
151 private RevCommit addCommit(Git git)
152 throws IOException, NoFilepatternException, GitAPIException {
153 writeTrashFile("f", "content of f");
154 git.add().addFilepattern("f").call();
155 return git.commit().setMessage("adding f").call();
156 }
157
158 @Test
159 public void testNonAtomicPushWithOptions() throws Exception {
160 PushResult r;
161 server.setPerformsAtomicTransactions(false);
162 List<String> pushOptions = Arrays.asList("Hello", "World!");
163
164 try (Transport tn = testProtocol.open(uri, client, "server")) {
165 tn.setPushAtomic(false);
166 tn.setPushOptions(pushOptions);
167
168 r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
169 }
170
171 RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
172 RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
173
174 assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
175 assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
176 two.getStatus());
177 assertEquals(pushOptions, receivePack.getPushOptions());
178 }
179
180 @Test
181 public void testAtomicPushWithOptions() throws Exception {
182 PushResult r;
183 server.setPerformsAtomicTransactions(true);
184 List<String> pushOptions = Arrays.asList("Hello", "World!");
185
186 try (Transport tn = testProtocol.open(uri, client, "server")) {
187 tn.setPushAtomic(true);
188 tn.setPushOptions(pushOptions);
189
190 r = tn.push(NullProgressMonitor.INSTANCE, commands(true));
191 }
192
193 RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
194 RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
195
196 assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
197 assertSame(RemoteRefUpdate.Status.OK, two.getStatus());
198 assertEquals(pushOptions, receivePack.getPushOptions());
199 }
200
201 @Test
202 public void testFailedAtomicPushWithOptions() throws Exception {
203 PushResult r;
204 server.setPerformsAtomicTransactions(true);
205 List<String> pushOptions = Arrays.asList("Hello", "World!");
206
207 try (Transport tn = testProtocol.open(uri, client, "server")) {
208 tn.setPushAtomic(true);
209 tn.setPushOptions(pushOptions);
210
211 r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
212 }
213
214 RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
215 RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
216
217 assertSame(RemoteRefUpdate.Status.REJECTED_OTHER_REASON,
218 one.getStatus());
219 assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
220 two.getStatus());
221 assertNull(receivePack.getPushOptions());
222 }
223
224 @Test
225 public void testThinPushWithOptions() throws Exception {
226 PushResult r;
227 List<String> pushOptions = Arrays.asList("Hello", "World!");
228
229 try (Transport tn = testProtocol.open(uri, client, "server")) {
230 tn.setPushThin(true);
231 tn.setPushOptions(pushOptions);
232
233 r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
234 }
235
236 RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
237 RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
238
239 assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
240 assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
241 two.getStatus());
242 assertEquals(pushOptions, receivePack.getPushOptions());
243 }
244
245 @Test
246 public void testPushWithoutOptions() throws Exception {
247 try (Git local = new Git(db);
248 Git remote = new Git(createBareRepository())) {
249 connectLocalToRemote(local, remote);
250
251 final StoredConfig config2 = remote.getRepository().getConfig();
252 config2.setBoolean("receive", null, "pushoptions", true);
253 config2.save();
254
255 RevCommit commit = addCommit(local);
256
257 local.checkout().setName("not-pushed").setCreateBranch(true).call();
258 local.checkout().setName("branchtopush").setCreateBranch(true).call();
259
260 assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
261 assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
262 assertNull(remote.getRepository().resolve("refs/heads/master"));
263
264 PushCommand pushCommand = local.push().setRemote("test");
265 pushCommand.call();
266
267 assertEquals(commit.getId(),
268 remote.getRepository().resolve("refs/heads/branchtopush"));
269 assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
270 assertNull(remote.getRepository().resolve("refs/heads/master"));
271 }
272 }
273
274 @Test
275 public void testPushWithEmptyOptions() throws Exception {
276 try (Git local = new Git(db);
277 Git remote = new Git(createBareRepository())) {
278 connectLocalToRemote(local, remote);
279
280 final StoredConfig config2 = remote.getRepository().getConfig();
281 config2.setBoolean("receive", null, "pushoptions", true);
282 config2.save();
283
284 RevCommit commit = addCommit(local);
285
286 local.checkout().setName("not-pushed").setCreateBranch(true).call();
287 local.checkout().setName("branchtopush").setCreateBranch(true).call();
288 assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
289 assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
290 assertNull(remote.getRepository().resolve("refs/heads/master"));
291
292 List<String> pushOptions = new ArrayList<>();
293 PushCommand pushCommand = local.push().setRemote("test")
294 .setPushOptions(pushOptions);
295 pushCommand.call();
296
297 assertEquals(commit.getId(),
298 remote.getRepository().resolve("refs/heads/branchtopush"));
299 assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
300 assertNull(remote.getRepository().resolve("refs/heads/master"));
301 }
302 }
303
304 @Test
305 public void testAdvertisedButUnusedPushOptions() throws Exception {
306 try (Git local = new Git(db);
307 Git remote = new Git(createBareRepository())) {
308 connectLocalToRemote(local, remote);
309
310 final StoredConfig config2 = remote.getRepository().getConfig();
311 config2.setBoolean("receive", null, "pushoptions", true);
312 config2.save();
313
314 RevCommit commit = addCommit(local);
315
316 local.checkout().setName("not-pushed").setCreateBranch(true).call();
317 local.checkout().setName("branchtopush").setCreateBranch(true).call();
318
319 assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
320 assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
321 assertNull(remote.getRepository().resolve("refs/heads/master"));
322
323 PushCommand pushCommand = local.push().setRemote("test")
324 .setPushOptions(null);
325 pushCommand.call();
326
327 assertEquals(commit.getId(),
328 remote.getRepository().resolve("refs/heads/branchtopush"));
329 assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
330 assertNull(remote.getRepository().resolve("refs/heads/master"));
331 }
332 }
333
334 @Test(expected = TransportException.class)
335 public void testPushOptionsNotSupported() throws Exception {
336 try (Git local = new Git(db);
337 Git remote = new Git(createBareRepository())) {
338 connectLocalToRemote(local, remote);
339
340 final StoredConfig config2 = remote.getRepository().getConfig();
341 config2.setBoolean("receive", null, "pushoptions", false);
342 config2.save();
343
344 addCommit(local);
345
346 local.checkout().setName("not-pushed").setCreateBranch(true).call();
347 local.checkout().setName("branchtopush").setCreateBranch(true).call();
348
349 assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
350 assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
351 assertNull(remote.getRepository().resolve("refs/heads/master"));
352
353 List<String> pushOptions = new ArrayList<>();
354 PushCommand pushCommand = local.push().setRemote("test")
355 .setPushOptions(pushOptions);
356 pushCommand.call();
357
358 fail("should already have thrown TransportException");
359 }
360 }
361 }