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