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.

PushConnectionTest.java 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Copyright (C) 2015, 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.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_REPORT_STATUS;
  12. import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K;
  13. import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
  14. import static org.junit.Assert.assertEquals;
  15. import static org.junit.Assert.fail;
  16. import java.io.IOException;
  17. import java.io.StringWriter;
  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import org.eclipse.jgit.errors.TransportException;
  24. import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
  25. import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
  26. import org.eclipse.jgit.junit.TestRepository;
  27. import org.eclipse.jgit.lib.Constants;
  28. import org.eclipse.jgit.lib.NullProgressMonitor;
  29. import org.eclipse.jgit.lib.ObjectId;
  30. import org.eclipse.jgit.lib.ObjectInserter;
  31. import org.eclipse.jgit.lib.RefUpdate;
  32. import org.eclipse.jgit.lib.Repository;
  33. import org.junit.After;
  34. import org.junit.Before;
  35. import org.junit.Test;
  36. public class PushConnectionTest {
  37. private URIish uri;
  38. private TestProtocol<Object> testProtocol;
  39. private Object ctx = new Object();
  40. private InMemoryRepository server;
  41. private InMemoryRepository client;
  42. private List<String> processedRefs;
  43. private ObjectId obj1;
  44. private ObjectId obj2;
  45. private ObjectId obj3;
  46. private String refName = "refs/tags/blob";
  47. @Before
  48. public void setUp() throws Exception {
  49. server = newRepo("server");
  50. client = newRepo("client");
  51. processedRefs = new ArrayList<>();
  52. testProtocol = new TestProtocol<>(null, (Object req, Repository db) -> {
  53. ReceivePack rp = new ReceivePack(db);
  54. rp.setPreReceiveHook((ReceivePack receivePack,
  55. Collection<ReceiveCommand> cmds) -> {
  56. for (ReceiveCommand cmd : cmds) {
  57. processedRefs.add(cmd.getRefName());
  58. }
  59. });
  60. return rp;
  61. });
  62. uri = testProtocol.register(ctx, server);
  63. try (ObjectInserter ins = server.newObjectInserter()) {
  64. obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
  65. obj3 = ins.insert(Constants.OBJ_BLOB, Constants.encode("not"));
  66. ins.flush();
  67. RefUpdate u = server.updateRef(refName);
  68. u.setNewObjectId(obj1);
  69. assertEquals(RefUpdate.Result.NEW, u.update());
  70. }
  71. try (ObjectInserter ins = client.newObjectInserter()) {
  72. obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
  73. ins.flush();
  74. }
  75. }
  76. @After
  77. public void tearDown() {
  78. Transport.unregister(testProtocol);
  79. }
  80. private static InMemoryRepository newRepo(String name) {
  81. return new InMemoryRepository(new DfsRepositoryDescription(name));
  82. }
  83. @Test
  84. public void testWrongOldIdDoesNotReplace() throws IOException {
  85. RemoteRefUpdate rru = new RemoteRefUpdate(null, null, obj2, refName,
  86. false, null, obj3);
  87. Map<String, RemoteRefUpdate> updates = new HashMap<>();
  88. updates.put(rru.getRemoteName(), rru);
  89. try (Transport tn = testProtocol.open(uri, client, "server");
  90. PushConnection connection = tn.openPush()) {
  91. connection.push(NullProgressMonitor.INSTANCE, updates);
  92. }
  93. assertEquals(REJECTED_OTHER_REASON, rru.getStatus());
  94. assertEquals("invalid old id sent", rru.getMessage());
  95. }
  96. @Test
  97. public void invalidCommand() throws IOException {
  98. try (Transport tn = testProtocol.open(uri, client, "server");
  99. InternalPushConnection c = (InternalPushConnection) tn.openPush()) {
  100. StringWriter msgs = new StringWriter();
  101. PacketLineOut pckOut = c.pckOut;
  102. @SuppressWarnings("resource")
  103. SideBandInputStream in = new SideBandInputStream(c.in,
  104. NullProgressMonitor.INSTANCE, msgs, null);
  105. // Explicitly invalid command, but sane enough capabilities.
  106. StringBuilder buf = new StringBuilder();
  107. buf.append("42");
  108. buf.append(' ');
  109. buf.append(obj2.name());
  110. buf.append(' ');
  111. buf.append("refs/heads/A" + obj2.name());
  112. buf.append('\0').append(CAPABILITY_SIDE_BAND_64K);
  113. buf.append(' ').append(CAPABILITY_REPORT_STATUS);
  114. buf.append('\n');
  115. pckOut.writeString(buf.toString());
  116. pckOut.end();
  117. try {
  118. in.read();
  119. fail("expected TransportException");
  120. } catch (TransportException e) {
  121. assertEquals(
  122. "remote: error: invalid protocol: wanted 'old new ref'",
  123. e.getMessage());
  124. }
  125. }
  126. }
  127. @Test
  128. public void limitCommandBytes() throws IOException {
  129. Map<String, RemoteRefUpdate> updates = new HashMap<>();
  130. for (int i = 0; i < 4; i++) {
  131. RemoteRefUpdate rru = new RemoteRefUpdate(
  132. null, null, obj2, "refs/test/T" + i,
  133. false, null, ObjectId.zeroId());
  134. updates.put(rru.getRemoteName(), rru);
  135. }
  136. server.getConfig().setInt("receive", null, "maxCommandBytes", 195);
  137. try (Transport tn = testProtocol.open(uri, client, "server");
  138. PushConnection connection = tn.openPush()) {
  139. try {
  140. connection.push(NullProgressMonitor.INSTANCE, updates);
  141. fail("server did not abort");
  142. } catch (TransportException e) {
  143. String msg = e.getMessage();
  144. assertEquals(
  145. "remote: Commands size exceeds limit defined in receive.maxCommandBytes",
  146. msg);
  147. }
  148. }
  149. }
  150. @Test
  151. public void commandOrder() throws Exception {
  152. List<RemoteRefUpdate> updates = new ArrayList<>();
  153. try (TestRepository<?> tr = new TestRepository<>(client)) {
  154. // Arbitrary non-sorted order.
  155. for (int i = 9; i >= 0; i--) {
  156. String name = "refs/heads/b" + i;
  157. tr.branch(name).commit().create();
  158. RemoteRefUpdate rru = new RemoteRefUpdate(client, name, name,
  159. false, null, ObjectId.zeroId());
  160. updates.add(rru);
  161. }
  162. }
  163. PushResult result;
  164. try (Transport tn = testProtocol.open(uri, client, "server")) {
  165. result = tn.push(NullProgressMonitor.INSTANCE, updates);
  166. }
  167. for (RemoteRefUpdate remoteUpdate : result.getRemoteUpdates()) {
  168. assertEquals(
  169. "update should succeed on " + remoteUpdate.getRemoteName(),
  170. RemoteRefUpdate.Status.OK, remoteUpdate.getStatus());
  171. }
  172. List<String> expected = remoteRefNames(updates);
  173. assertEquals(
  174. "ref names processed by ReceivePack should match input ref names in order",
  175. expected, processedRefs);
  176. assertEquals(
  177. "remote ref names should match input ref names in order",
  178. expected, remoteRefNames(result.getRemoteUpdates()));
  179. }
  180. private static List<String> remoteRefNames(Collection<RemoteRefUpdate> updates) {
  181. List<String> result = new ArrayList<>();
  182. for (RemoteRefUpdate u : updates) {
  183. result.add(u.getRemoteName());
  184. }
  185. return result;
  186. }
  187. }