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 package org.eclipse.jgit.lfs.server.fs;
44
45 import static java.nio.charset.StandardCharsets.UTF_8;
46 import static org.junit.Assert.assertEquals;
47
48 import java.io.BufferedInputStream;
49 import java.io.FileNotFoundException;
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.nio.ByteBuffer;
53 import java.nio.channels.Channels;
54 import java.nio.channels.FileChannel;
55 import java.nio.channels.ReadableByteChannel;
56 import java.nio.file.Files;
57 import java.nio.file.Path;
58 import java.nio.file.Paths;
59 import java.nio.file.StandardOpenOption;
60 import java.security.DigestInputStream;
61 import java.security.SecureRandom;
62
63 import org.apache.http.HttpEntity;
64 import org.apache.http.HttpResponse;
65 import org.apache.http.StatusLine;
66 import org.apache.http.client.ClientProtocolException;
67 import org.apache.http.client.methods.CloseableHttpResponse;
68 import org.apache.http.client.methods.HttpGet;
69 import org.apache.http.client.methods.HttpPut;
70 import org.apache.http.entity.ContentType;
71 import org.apache.http.entity.InputStreamEntity;
72 import org.apache.http.entity.StringEntity;
73 import org.apache.http.impl.client.CloseableHttpClient;
74 import org.apache.http.impl.client.HttpClientBuilder;
75 import org.eclipse.jetty.servlet.ServletContextHandler;
76 import org.eclipse.jetty.servlet.ServletHolder;
77 import org.eclipse.jgit.junit.MockSystemReader;
78 import org.eclipse.jgit.junit.http.AppServer;
79 import org.eclipse.jgit.lfs.errors.LfsException;
80 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
81 import org.eclipse.jgit.lfs.lib.Constants;
82 import org.eclipse.jgit.lfs.lib.LongObjectId;
83 import org.eclipse.jgit.lfs.server.LargeFileRepository;
84 import org.eclipse.jgit.lfs.server.LfsProtocolServlet;
85 import org.eclipse.jgit.lfs.test.LongObjectIdTestUtils;
86 import org.eclipse.jgit.util.FS;
87 import org.eclipse.jgit.util.FileUtils;
88 import org.eclipse.jgit.util.IO;
89 import org.eclipse.jgit.util.SystemReader;
90 import org.junit.After;
91 import org.junit.Before;
92
93 public abstract class LfsServerTest {
94
95 private static final long timeout = 10 * 1000;
96
97 protected static final int MiB = 1024 * 1024;
98
99
100 protected AppServer server;
101
102 private Path tmp;
103
104 private Path dir;
105
106 protected FileLfsRepository repository;
107
108 protected FileLfsServlet servlet;
109
110 public LfsServerTest() {
111 super();
112 }
113
114 public Path getTempDirectory() {
115 return tmp;
116 }
117
118 public Path getDir() {
119 return dir;
120 }
121
122 @Before
123 public void setup() throws Exception {
124 SystemReader.setInstance(new MockSystemReader());
125 tmp = Files.createTempDirectory("jgit_test_");
126
127
128
129 FS.getFileStoreAttributes(tmp.getParent());
130
131 server = new AppServer();
132 ServletContextHandler app = server.addContext("/lfs");
133 dir = Paths.get(tmp.toString(), "lfs");
134 this.repository = new FileLfsRepository(null, dir);
135 servlet = new FileLfsServlet(repository, timeout);
136 app.addServlet(new ServletHolder(servlet), "/objects/*");
137
138 LfsProtocolServlet protocol = new LfsProtocolServlet() {
139 private static final long serialVersionUID = 1L;
140
141 @Override
142 protected LargeFileRepository getLargeFileRepository(
143 LfsRequest request, String path, String auth)
144 throws LfsException {
145 return repository;
146 }
147 };
148 app.addServlet(new ServletHolder(protocol), "/objects/batch");
149
150 server.setUp();
151 this.repository.setUrl(server.getURI() + "/lfs/objects/");
152 }
153
154 @After
155 public void tearDown() throws Exception {
156 server.tearDown();
157 FileUtils.delete(tmp.toFile(), FileUtils.RECURSIVE | FileUtils.RETRY);
158 }
159
160 protected AnyLongObjectId putContent(String s)
161 throws IOException, ClientProtocolException {
162 AnyLongObjectId id = LongObjectIdTestUtils.hash(s);
163 return putContent(id, s);
164 }
165
166 protected AnyLongObjectId putContent(AnyLongObjectId id, String s)
167 throws ClientProtocolException, IOException {
168 try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
169 HttpEntity entity = new StringEntity(s,
170 ContentType.APPLICATION_OCTET_STREAM);
171 String hexId = id.name();
172 HttpPut request = new HttpPut(
173 server.getURI() + "/lfs/objects/" + hexId);
174 request.setEntity(entity);
175 try (CloseableHttpResponse response = client.execute(request)) {
176 StatusLine statusLine = response.getStatusLine();
177 int status = statusLine.getStatusCode();
178 if (status >= 400) {
179 throw new RuntimeException("Status: " + status + ". "
180 + statusLine.getReasonPhrase());
181 }
182 }
183 return id;
184 }
185 }
186
187 protected LongObjectId putContent(Path f)
188 throws FileNotFoundException, IOException {
189 try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
190 LongObjectId id1, id2;
191 String hexId1, hexId2;
192 try (DigestInputStream in = new DigestInputStream(
193 new BufferedInputStream(Files.newInputStream(f)),
194 Constants.newMessageDigest())) {
195 InputStreamEntity entity = new InputStreamEntity(in,
196 Files.size(f), ContentType.APPLICATION_OCTET_STREAM);
197 id1 = LongObjectIdTestUtils.hash(f);
198 hexId1 = id1.name();
199 HttpPut request = new HttpPut(
200 server.getURI() + "/lfs/objects/" + hexId1);
201 request.setEntity(entity);
202 HttpResponse response = client.execute(request);
203 checkResponseStatus(response);
204 id2 = LongObjectId.fromRaw(in.getMessageDigest().digest());
205 hexId2 = id2.name();
206 assertEquals(hexId1, hexId2);
207 }
208 return id1;
209 }
210 }
211
212 private void checkResponseStatus(HttpResponse response) {
213 StatusLine statusLine = response.getStatusLine();
214 int status = statusLine.getStatusCode();
215 if (statusLine.getStatusCode() >= 400) {
216 String error;
217 try {
218 ByteBuffer buf = IO.readWholeStream(new BufferedInputStream(
219 response.getEntity().getContent()), 1024);
220 if (buf.hasArray()) {
221 error = new String(buf.array(),
222 buf.arrayOffset() + buf.position(), buf.remaining(),
223 UTF_8);
224 } else {
225 final byte[] b = new byte[buf.remaining()];
226 buf.duplicate().get(b);
227 error = new String(b, UTF_8);
228 }
229 } catch (IOException e) {
230 error = statusLine.getReasonPhrase();
231 }
232 throw new RuntimeException("Status: " + status + " " + error);
233 }
234 assertEquals(200, status);
235 }
236
237 protected long getContent(AnyLongObjectId id, Path f) throws IOException {
238 String hexId = id.name();
239 return getContent(hexId, f);
240 }
241
242 protected long getContent(String hexId, Path f) throws IOException {
243 try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
244 HttpGet request = new HttpGet(
245 server.getURI() + "/lfs/objects/" + hexId);
246 HttpResponse response = client.execute(request);
247 checkResponseStatus(response);
248 HttpEntity entity = response.getEntity();
249 long pos = 0;
250 try (InputStream in = entity.getContent();
251 ReadableByteChannel inChannel = Channels.newChannel(in);
252 FileChannel outChannel = FileChannel.open(f,
253 StandardOpenOption.CREATE_NEW,
254 StandardOpenOption.WRITE)) {
255 long transferred;
256 do {
257 transferred = outChannel.transferFrom(inChannel, pos, MiB);
258 pos += transferred;
259 } while (transferred > 0);
260 }
261 return pos;
262 }
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276 protected long createPseudoRandomContentFile(Path f, long size)
277 throws IOException {
278 SecureRandom rnd = new SecureRandom();
279 byte[] buf = new byte[4096];
280 rnd.nextBytes(buf);
281 ByteBuffer bytebuf = ByteBuffer.wrap(buf);
282 try (FileChannel outChannel = FileChannel.open(f,
283 StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
284 long len = 0;
285 do {
286 len += outChannel.write(bytebuf);
287 if (bytebuf.position() == 4096) {
288 bytebuf.rewind();
289 }
290 } while (len < size);
291 }
292 return Files.size(f);
293 }
294 }