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