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.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_REPORT_STATUS;
47 import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K;
48 import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.fail;
51
52 import java.io.IOException;
53 import java.io.StringWriter;
54 import java.util.ArrayList;
55 import java.util.Collection;
56 import java.util.HashMap;
57 import java.util.List;
58 import java.util.Map;
59
60 import org.eclipse.jgit.errors.TransportException;
61 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
62 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
63 import org.eclipse.jgit.junit.TestRepository;
64 import org.eclipse.jgit.lib.Constants;
65 import org.eclipse.jgit.lib.NullProgressMonitor;
66 import org.eclipse.jgit.lib.ObjectId;
67 import org.eclipse.jgit.lib.ObjectInserter;
68 import org.eclipse.jgit.lib.RefUpdate;
69 import org.eclipse.jgit.lib.Repository;
70 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
71 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
72 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
73 import org.junit.After;
74 import org.junit.Before;
75 import org.junit.Test;
76
77 public class PushConnectionTest {
78 private URIish uri;
79 private TestProtocol<Object> testProtocol;
80 private Object ctx = new Object();
81 private InMemoryRepository server;
82 private InMemoryRepository client;
83 private List<String> processedRefs;
84 private ObjectId obj1;
85 private ObjectId obj2;
86 private ObjectId obj3;
87 private String refName = "refs/tags/blob";
88
89 @Before
90 public void setUp() throws Exception {
91 server = newRepo("server");
92 client = newRepo("client");
93 processedRefs = new ArrayList<>();
94 testProtocol = new TestProtocol<>(
95 null,
96 new ReceivePackFactory<Object>() {
97 @Override
98 public ReceivePack create(Object req, Repository db)
99 throws ServiceNotEnabledException,
100 ServiceNotAuthorizedException {
101 ReceivePack rp = new ReceivePack(db);
102 rp.setPreReceiveHook(
103 new PreReceiveHook() {
104 @Override
105 public void onPreReceive(ReceivePack receivePack,
106 Collection<ReceiveCommand> cmds) {
107 for (ReceiveCommand cmd : cmds) {
108 processedRefs.add(cmd.getRefName());
109 }
110 }
111 });
112 return rp;
113 }
114 });
115 uri = testProtocol.register(ctx, server);
116
117 try (ObjectInserter ins = server.newObjectInserter()) {
118 obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
119 obj3 = ins.insert(Constants.OBJ_BLOB, Constants.encode("not"));
120 ins.flush();
121
122 RefUpdate u = server.updateRef(refName);
123 u.setNewObjectId(obj1);
124 assertEquals(RefUpdate.Result.NEW, u.update());
125 }
126
127 try (ObjectInserter ins = client.newObjectInserter()) {
128 obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
129 ins.flush();
130 }
131 }
132
133 @After
134 public void tearDown() {
135 Transport.unregister(testProtocol);
136 }
137
138 private static InMemoryRepository newRepo(String name) {
139 return new InMemoryRepository(new DfsRepositoryDescription(name));
140 }
141
142 @Test
143 public void testWrongOldIdDoesNotReplace() throws IOException {
144 RemoteRefUpdate rru = new RemoteRefUpdate(null, null, obj2, refName,
145 false, null, obj3);
146
147 Map<String, RemoteRefUpdate> updates = new HashMap<>();
148 updates.put(rru.getRemoteName(), rru);
149
150 try (Transport tn = testProtocol.open(uri, client, "server");
151 PushConnection connection = tn.openPush()) {
152 connection.push(NullProgressMonitor.INSTANCE, updates);
153 }
154
155 assertEquals(REJECTED_OTHER_REASON, rru.getStatus());
156 assertEquals("invalid old id sent", rru.getMessage());
157 }
158
159 @Test
160 public void invalidCommand() throws IOException {
161 try (Transport tn = testProtocol.open(uri, client, "server");
162 InternalPushConnection c = (InternalPushConnection) tn.openPush()) {
163 StringWriter msgs = new StringWriter();
164 PacketLineOut pckOut = c.pckOut;
165
166 @SuppressWarnings("resource")
167 SideBandInputStream in = new SideBandInputStream(c.in,
168 NullProgressMonitor.INSTANCE, msgs, null);
169
170
171 StringBuilder buf = new StringBuilder();
172 buf.append("42");
173 buf.append(' ');
174 buf.append(obj2.name());
175 buf.append(' ');
176 buf.append("refs/heads/A" + obj2.name());
177 buf.append('\0').append(CAPABILITY_SIDE_BAND_64K);
178 buf.append(' ').append(CAPABILITY_REPORT_STATUS);
179 buf.append('\n');
180 pckOut.writeString(buf.toString());
181 pckOut.end();
182
183 try {
184 in.read();
185 fail("expected TransportException");
186 } catch (TransportException e) {
187 assertEquals(
188 "remote: error: invalid protocol: wanted 'old new ref'",
189 e.getMessage());
190 }
191 }
192 }
193
194 @Test
195 public void limitCommandBytes() throws IOException {
196 Map<String, RemoteRefUpdate> updates = new HashMap<>();
197 for (int i = 0; i < 4; i++) {
198 RemoteRefUpdate rru = new RemoteRefUpdate(
199 null, null, obj2, "refs/test/T" + i,
200 false, null, ObjectId.zeroId());
201 updates.put(rru.getRemoteName(), rru);
202 }
203
204 server.getConfig().setInt("receive", null, "maxCommandBytes", 195);
205 try (Transport tn = testProtocol.open(uri, client, "server");
206 PushConnection connection = tn.openPush()) {
207 try {
208 connection.push(NullProgressMonitor.INSTANCE, updates);
209 fail("server did not abort");
210 } catch (TransportException e) {
211 String msg = e.getMessage();
212 assertEquals("remote: Too many commands", msg);
213 }
214 }
215 }
216
217 @Test
218 public void commandOrder() throws Exception {
219 List<RemoteRefUpdate> updates = new ArrayList<>();
220 try (TestRepository<?> tr = new TestRepository<>(client)) {
221
222 for (int i = 9; i >= 0; i--) {
223 String name = "refs/heads/b" + i;
224 tr.branch(name).commit().create();
225 RemoteRefUpdate rru = new RemoteRefUpdate(client, name, name,
226 false, null, ObjectId.zeroId());
227 updates.add(rru);
228 }
229 }
230
231 PushResult result;
232 try (Transport tn = testProtocol.open(uri, client, "server")) {
233 result = tn.push(NullProgressMonitor.INSTANCE, updates);
234 }
235
236 for (RemoteRefUpdate remoteUpdate : result.getRemoteUpdates()) {
237 assertEquals(
238 "update should succeed on " + remoteUpdate.getRemoteName(),
239 RemoteRefUpdate.Status.OK, remoteUpdate.getStatus());
240 }
241
242 List<String> expected = remoteRefNames(updates);
243 assertEquals(
244 "ref names processed by ReceivePack should match input ref names in order",
245 expected, processedRefs);
246 assertEquals(
247 "remote ref names should match input ref names in order",
248 expected, remoteRefNames(result.getRemoteUpdates()));
249 }
250
251 private static List<String> remoteRefNames(Collection<RemoteRefUpdate> updates) {
252 List<String> result = new ArrayList<>();
253 for (RemoteRefUpdate u : updates) {
254 result.add(u.getRemoteName());
255 }
256 return result;
257 }
258 }