You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PushOptionsTest.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Copyright (C) 2016, Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.transport;
  11. import static org.junit.Assert.assertEquals;
  12. import static org.junit.Assert.assertNull;
  13. import static org.junit.Assert.assertSame;
  14. import static org.junit.Assert.fail;
  15. import java.io.IOException;
  16. import java.net.URISyntaxException;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import java.util.List;
  20. import org.eclipse.jgit.api.Git;
  21. import org.eclipse.jgit.api.PushCommand;
  22. import org.eclipse.jgit.api.errors.GitAPIException;
  23. import org.eclipse.jgit.api.errors.NoFilepatternException;
  24. import org.eclipse.jgit.api.errors.TransportException;
  25. import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
  26. import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
  27. import org.eclipse.jgit.junit.RepositoryTestCase;
  28. import org.eclipse.jgit.junit.TestRepository;
  29. import org.eclipse.jgit.lib.NullProgressMonitor;
  30. import org.eclipse.jgit.lib.ObjectId;
  31. import org.eclipse.jgit.lib.Repository;
  32. import org.eclipse.jgit.lib.StoredConfig;
  33. import org.eclipse.jgit.revwalk.RevCommit;
  34. import org.junit.After;
  35. import org.junit.Before;
  36. import org.junit.Test;
  37. public class PushOptionsTest extends RepositoryTestCase {
  38. private URIish uri;
  39. private TestProtocol<Object> testProtocol;
  40. private Object ctx = new Object();
  41. private InMemoryRepository server;
  42. private InMemoryRepository client;
  43. private ObjectId commit1;
  44. private ObjectId commit2;
  45. private ReceivePack receivePack;
  46. @Override
  47. @Before
  48. public void setUp() throws Exception {
  49. super.setUp();
  50. server = newRepo("server");
  51. client = newRepo("client");
  52. testProtocol = new TestProtocol<>(null,
  53. (Object req, Repository git) -> {
  54. receivePack = new ReceivePack(git);
  55. receivePack.setAllowPushOptions(true);
  56. receivePack.setAtomic(true);
  57. return receivePack;
  58. });
  59. uri = testProtocol.register(ctx, server);
  60. try (TestRepository<?> clientRepo = new TestRepository<>(client)) {
  61. commit1 = clientRepo.commit().noFiles().message("test commit 1")
  62. .create();
  63. commit2 = clientRepo.commit().noFiles().message("test commit 2")
  64. .create();
  65. }
  66. }
  67. @Override
  68. @After
  69. public void tearDown() {
  70. Transport.unregister(testProtocol);
  71. }
  72. private static InMemoryRepository newRepo(String name) {
  73. return new InMemoryRepository(new DfsRepositoryDescription(name));
  74. }
  75. private List<RemoteRefUpdate> commands(boolean atomicSafe)
  76. throws IOException {
  77. List<RemoteRefUpdate> cmds = new ArrayList<>();
  78. cmds.add(new RemoteRefUpdate(null, null, commit1, "refs/heads/one",
  79. true /* force update */, null /* no local tracking ref */,
  80. ObjectId.zeroId()));
  81. cmds.add(new RemoteRefUpdate(null, null, commit2, "refs/heads/two",
  82. true /* force update */, null /* no local tracking ref */,
  83. atomicSafe ? ObjectId.zeroId() : commit1));
  84. return cmds;
  85. }
  86. private void connectLocalToRemote(Git local, Git remote)
  87. throws URISyntaxException, IOException {
  88. StoredConfig config = local.getRepository().getConfig();
  89. RemoteConfig remoteConfig = new RemoteConfig(config, "test");
  90. remoteConfig.addURI(new URIish(
  91. remote.getRepository().getDirectory().toURI().toURL()));
  92. remoteConfig.addFetchRefSpec(
  93. new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
  94. remoteConfig.update(config);
  95. config.save();
  96. }
  97. private RevCommit addCommit(Git git)
  98. throws IOException, NoFilepatternException, GitAPIException {
  99. writeTrashFile("f", "content of f");
  100. git.add().addFilepattern("f").call();
  101. return git.commit().setMessage("adding f").call();
  102. }
  103. @Test
  104. public void testNonAtomicPushWithOptions() throws Exception {
  105. PushResult r;
  106. server.setPerformsAtomicTransactions(false);
  107. List<String> pushOptions = Arrays.asList("Hello", "World!");
  108. try (Transport tn = testProtocol.open(uri, client, "server")) {
  109. tn.setPushAtomic(false);
  110. tn.setPushOptions(pushOptions);
  111. r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
  112. }
  113. RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
  114. RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
  115. assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
  116. assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
  117. two.getStatus());
  118. assertEquals(pushOptions, receivePack.getPushOptions());
  119. }
  120. @Test
  121. public void testAtomicPushWithOptions() throws Exception {
  122. PushResult r;
  123. server.setPerformsAtomicTransactions(true);
  124. List<String> pushOptions = Arrays.asList("Hello", "World!");
  125. try (Transport tn = testProtocol.open(uri, client, "server")) {
  126. tn.setPushAtomic(true);
  127. tn.setPushOptions(pushOptions);
  128. r = tn.push(NullProgressMonitor.INSTANCE, commands(true));
  129. }
  130. RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
  131. RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
  132. assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
  133. assertSame(RemoteRefUpdate.Status.OK, two.getStatus());
  134. assertEquals(pushOptions, receivePack.getPushOptions());
  135. }
  136. @Test
  137. public void testFailedAtomicPushWithOptions() throws Exception {
  138. PushResult r;
  139. server.setPerformsAtomicTransactions(true);
  140. List<String> pushOptions = Arrays.asList("Hello", "World!");
  141. try (Transport tn = testProtocol.open(uri, client, "server")) {
  142. tn.setPushAtomic(true);
  143. tn.setPushOptions(pushOptions);
  144. r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
  145. }
  146. RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
  147. RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
  148. assertSame(RemoteRefUpdate.Status.REJECTED_OTHER_REASON,
  149. one.getStatus());
  150. assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
  151. two.getStatus());
  152. assertNull(receivePack.getPushOptions());
  153. }
  154. @Test
  155. public void testThinPushWithOptions() throws Exception {
  156. PushResult r;
  157. List<String> pushOptions = Arrays.asList("Hello", "World!");
  158. try (Transport tn = testProtocol.open(uri, client, "server")) {
  159. tn.setPushThin(true);
  160. tn.setPushOptions(pushOptions);
  161. r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
  162. }
  163. RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
  164. RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
  165. assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
  166. assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
  167. two.getStatus());
  168. assertEquals(pushOptions, receivePack.getPushOptions());
  169. }
  170. @Test
  171. public void testPushWithoutOptions() throws Exception {
  172. try (Git local = new Git(db);
  173. Git remote = new Git(createBareRepository())) {
  174. connectLocalToRemote(local, remote);
  175. final StoredConfig config2 = remote.getRepository().getConfig();
  176. config2.setBoolean("receive", null, "pushoptions", true);
  177. config2.save();
  178. RevCommit commit = addCommit(local);
  179. local.checkout().setName("not-pushed").setCreateBranch(true).call();
  180. local.checkout().setName("branchtopush").setCreateBranch(true).call();
  181. assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
  182. assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
  183. assertNull(remote.getRepository().resolve("refs/heads/master"));
  184. PushCommand pushCommand = local.push().setRemote("test");
  185. pushCommand.call();
  186. assertEquals(commit.getId(),
  187. remote.getRepository().resolve("refs/heads/branchtopush"));
  188. assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
  189. assertNull(remote.getRepository().resolve("refs/heads/master"));
  190. }
  191. }
  192. @Test
  193. public void testPushWithEmptyOptions() throws Exception {
  194. try (Git local = new Git(db);
  195. Git remote = new Git(createBareRepository())) {
  196. connectLocalToRemote(local, remote);
  197. final StoredConfig config2 = remote.getRepository().getConfig();
  198. config2.setBoolean("receive", null, "pushoptions", true);
  199. config2.save();
  200. RevCommit commit = addCommit(local);
  201. local.checkout().setName("not-pushed").setCreateBranch(true).call();
  202. local.checkout().setName("branchtopush").setCreateBranch(true).call();
  203. assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
  204. assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
  205. assertNull(remote.getRepository().resolve("refs/heads/master"));
  206. List<String> pushOptions = new ArrayList<>();
  207. PushCommand pushCommand = local.push().setRemote("test")
  208. .setPushOptions(pushOptions);
  209. pushCommand.call();
  210. assertEquals(commit.getId(),
  211. remote.getRepository().resolve("refs/heads/branchtopush"));
  212. assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
  213. assertNull(remote.getRepository().resolve("refs/heads/master"));
  214. }
  215. }
  216. @Test
  217. public void testAdvertisedButUnusedPushOptions() throws Exception {
  218. try (Git local = new Git(db);
  219. Git remote = new Git(createBareRepository())) {
  220. connectLocalToRemote(local, remote);
  221. final StoredConfig config2 = remote.getRepository().getConfig();
  222. config2.setBoolean("receive", null, "pushoptions", true);
  223. config2.save();
  224. RevCommit commit = addCommit(local);
  225. local.checkout().setName("not-pushed").setCreateBranch(true).call();
  226. local.checkout().setName("branchtopush").setCreateBranch(true).call();
  227. assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
  228. assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
  229. assertNull(remote.getRepository().resolve("refs/heads/master"));
  230. PushCommand pushCommand = local.push().setRemote("test")
  231. .setPushOptions(null);
  232. pushCommand.call();
  233. assertEquals(commit.getId(),
  234. remote.getRepository().resolve("refs/heads/branchtopush"));
  235. assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
  236. assertNull(remote.getRepository().resolve("refs/heads/master"));
  237. }
  238. }
  239. @Test(expected = TransportException.class)
  240. public void testPushOptionsNotSupported() throws Exception {
  241. try (Git local = new Git(db);
  242. Git remote = new Git(createBareRepository())) {
  243. connectLocalToRemote(local, remote);
  244. final StoredConfig config2 = remote.getRepository().getConfig();
  245. config2.setBoolean("receive", null, "pushoptions", false);
  246. config2.save();
  247. addCommit(local);
  248. local.checkout().setName("not-pushed").setCreateBranch(true).call();
  249. local.checkout().setName("branchtopush").setCreateBranch(true).call();
  250. assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
  251. assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
  252. assertNull(remote.getRepository().resolve("refs/heads/master"));
  253. List<String> pushOptions = new ArrayList<>();
  254. PushCommand pushCommand = local.push().setRemote("test")
  255. .setPushOptions(pushOptions);
  256. pushCommand.call();
  257. fail("should already have thrown TransportException");
  258. }
  259. }
  260. }