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