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.assertTrue;
49
50 import java.util.ArrayList;
51 import java.util.List;
52 import java.util.concurrent.atomic.AtomicInteger;
53
54 import org.eclipse.jgit.api.Git;
55 import org.eclipse.jgit.api.errors.InvalidRemoteException;
56 import org.eclipse.jgit.api.errors.TransportException;
57 import org.eclipse.jgit.internal.JGitText;
58 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
59 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
60 import org.eclipse.jgit.junit.TestRepository;
61 import org.eclipse.jgit.lib.ObjectId;
62 import org.eclipse.jgit.lib.Repository;
63 import org.eclipse.jgit.revwalk.RevCommit;
64 import org.eclipse.jgit.storage.pack.PackStatistics;
65 import org.eclipse.jgit.transport.BasePackFetchConnection.FetchConfig;
66 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
67 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
68 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
69 import org.junit.After;
70 import org.junit.Before;
71 import org.junit.Test;
72
73 public class TestProtocolTest {
74 private static final RefSpec HEADS = new RefSpec("+refs/heads/*:refs/heads/*");
75
76 private static final RefSpec MASTER = new RefSpec(
77 "+refs/heads/master:refs/heads/master");
78
79 private static final int HAVES_PER_ROUND = 32;
80
81 private static class User {
82 private final String name;
83
84 private User(String name) {
85 this.name = name;
86 }
87 }
88
89 private static class DefaultUpload implements UploadPackFactory<User> {
90 @Override
91 public UploadPack create(User req, Repository db) {
92 UploadPack up = new UploadPack(db);
93 up.setPostUploadHook(new PostUploadHook() {
94 @Override
95 public void onPostUpload(PackStatistics stats) {
96 havesCount = stats.getHaves();
97 }
98 });
99 return up;
100 }
101 }
102
103 private static class DefaultReceive implements ReceivePackFactory<User> {
104 @Override
105 public ReceivePack create(User req, Repository db) {
106 return new ReceivePack(db);
107 }
108 }
109
110 private static long havesCount;
111
112 private List<TransportProtocol> protos;
113 private TestRepository<InMemoryRepository> local;
114 private TestRepository<InMemoryRepository> remote;
115
116 @Before
117 public void setUp() throws Exception {
118 protos = new ArrayList<>();
119 local = new TestRepository<>(
120 new InMemoryRepository(new DfsRepositoryDescription("local")));
121 remote = new TestRepository<>(
122 new InMemoryRepository(new DfsRepositoryDescription("remote")));
123 }
124
125 @After
126 public void tearDown() {
127 for (TransportProtocol proto : protos) {
128 Transport.unregister(proto);
129 }
130 }
131
132 @Test
133 public void testFetch() throws Exception {
134 ObjectId master = remote.branch("master").commit().create();
135
136 TestProtocol<User> proto = registerDefault();
137 URIish uri = proto.register(new User("user"), remote.getRepository());
138
139 try (Git git = new Git(local.getRepository())) {
140 git.fetch()
141 .setRemote(uri.toString())
142 .setRefSpecs(HEADS)
143 .call();
144 assertEquals(master,
145 local.getRepository().exactRef("refs/heads/master").getObjectId());
146 }
147 }
148
149 @Test
150 public void testPush() throws Exception {
151 ObjectId master = local.branch("master").commit().create();
152
153 TestProtocol<User> proto = registerDefault();
154 URIish uri = proto.register(new User("user"), remote.getRepository());
155
156 try (Git git = new Git(local.getRepository())) {
157 git.push()
158 .setRemote(uri.toString())
159 .setRefSpecs(HEADS)
160 .call();
161 assertEquals(master,
162 remote.getRepository().exactRef("refs/heads/master").getObjectId());
163 }
164 }
165
166 @Test
167 public void testFullNegotiation() throws Exception {
168 TestProtocol<User> proto = registerDefault();
169 URIish uri = proto.register(new User("user"), remote.getRepository());
170
171
172
173 for (int i = 0; i < 10 * HAVES_PER_ROUND; i++) {
174 local.branch("local-branch-" + i).commit().create();
175 }
176 remote.tick(11 * HAVES_PER_ROUND);
177 RevCommit master = remote.branch("master").commit()
178 .add("readme.txt", "unique commit").create();
179
180 try (Git git = new Git(local.getRepository())) {
181 assertNull(local.getRepository().exactRef("refs/heads/master"));
182 git.fetch().setRemote(uri.toString()).setRefSpecs(MASTER).call();
183 assertEquals(master, local.getRepository()
184 .exactRef("refs/heads/master").getObjectId());
185 assertEquals(10 * HAVES_PER_ROUND, havesCount);
186 }
187 }
188
189 @Test
190 public void testMinimalNegotiation() throws Exception {
191 TestProtocol<User> proto = registerDefault();
192 URIish uri = proto.register(new User("user"), remote.getRepository());
193
194
195
196 for (int i = 0; i < 10 * HAVES_PER_ROUND; i++) {
197 local.branch("local-branch-" + i).commit().create();
198 }
199 remote.tick(11 * HAVES_PER_ROUND);
200 RevCommit master = remote.branch("master").commit()
201 .add("readme.txt", "unique commit").create();
202
203 TestProtocol.setFetchConfig(new FetchConfig(true, true));
204 try (Git git = new Git(local.getRepository())) {
205 assertNull(local.getRepository().exactRef("refs/heads/master"));
206 git.fetch().setRemote(uri.toString()).setRefSpecs(MASTER).call();
207 assertEquals(master, local.getRepository()
208 .exactRef("refs/heads/master").getObjectId());
209 assertTrue(havesCount <= 2 * HAVES_PER_ROUND);
210
211
212
213
214
215
216 master = remote.branch("master").commit().parent(master).create();
217 local.tick(2 * HAVES_PER_ROUND);
218 for (int i = 0; i < 5 * HAVES_PER_ROUND; i++) {
219 local.branch("local-" + i).commit().create();
220 }
221 git.fetch().setRemote(uri.toString()).setRefSpecs(MASTER).call();
222 assertEquals(master, local.getRepository()
223 .exactRef("refs/heads/master").getObjectId());
224 assertEquals(6 * HAVES_PER_ROUND, havesCount);
225 }
226 }
227
228 @Test
229 public void testUploadPackFactory() throws Exception {
230 ObjectId master = remote.branch("master").commit().create();
231
232 final AtomicInteger rejected = new AtomicInteger();
233 TestProtocol<User> proto = registerProto(new UploadPackFactory<User>() {
234 @Override
235 public UploadPack create(User req, Repository db)
236 throws ServiceNotAuthorizedException {
237 if (!"user2".equals(req.name)) {
238 rejected.incrementAndGet();
239 throw new ServiceNotAuthorizedException();
240 }
241 return new UploadPack(db);
242 }
243 }, new DefaultReceive());
244
245
246 URIish user1Uri = proto.register(new User("user1"), remote.getRepository());
247 URIish user2Uri = proto.register(new User("user2"), remote.getRepository());
248
249 try (Git git = new Git(local.getRepository())) {
250 try {
251 git.fetch()
252 .setRemote(user1Uri.toString())
253 .setRefSpecs(MASTER)
254 .call();
255 } catch (InvalidRemoteException expected) {
256
257 }
258 assertEquals(1, rejected.get());
259 assertNull(local.getRepository().exactRef("refs/heads/master"));
260
261 git.fetch()
262 .setRemote(user2Uri.toString())
263 .setRefSpecs(MASTER)
264 .call();
265 assertEquals(1, rejected.get());
266 assertEquals(master,
267 local.getRepository().exactRef("refs/heads/master").getObjectId());
268 }
269 }
270
271 @Test
272 public void testReceivePackFactory() throws Exception {
273 ObjectId master = local.branch("master").commit().create();
274
275 final AtomicInteger rejected = new AtomicInteger();
276 TestProtocol<User> proto = registerProto(new DefaultUpload(),
277 new ReceivePackFactory<User>() {
278 @Override
279 public ReceivePack create(User req, Repository db)
280 throws ServiceNotAuthorizedException {
281 if (!"user2".equals(req.name)) {
282 rejected.incrementAndGet();
283 throw new ServiceNotAuthorizedException();
284 }
285 return new ReceivePack(db);
286 }
287 });
288
289
290 URIish user1Uri = proto.register(new User("user1"), remote.getRepository());
291 URIish user2Uri = proto.register(new User("user2"), remote.getRepository());
292
293 try (Git git = new Git(local.getRepository())) {
294 try {
295 git.push()
296 .setRemote(user1Uri.toString())
297 .setRefSpecs(HEADS)
298 .call();
299 } catch (TransportException expected) {
300 assertTrue(expected.getMessage().contains(
301 JGitText.get().pushNotPermitted));
302 }
303 assertEquals(1, rejected.get());
304 assertNull(remote.getRepository().exactRef("refs/heads/master"));
305
306 git.push()
307 .setRemote(user2Uri.toString())
308 .setRefSpecs(HEADS)
309 .call();
310 assertEquals(1, rejected.get());
311 assertEquals(master,
312 remote.getRepository().exactRef("refs/heads/master").getObjectId());
313 }
314 }
315
316 private TestProtocol<User> registerDefault() {
317 return registerProto(new DefaultUpload(), new DefaultReceive());
318 }
319
320 private TestProtocol<User> registerProto(UploadPackFactory<User> upf,
321 ReceivePackFactory<User> rpf) {
322 TestProtocol<User> proto = new TestProtocol<>(upf, rpf);
323 protos.add(proto);
324 Transport.register(proto);
325 return proto;
326 }
327 }