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