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