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