1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.transport.file;
20
21 import java.io.FileNotFoundException;
22 import java.net.URI;
23 import java.nio.charset.StandardCharsets;
24 import java.nio.file.FileSystem;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27 import java.nio.file.Paths;
28
29 import com.google.common.jimfs.Configuration;
30 import com.google.common.jimfs.Jimfs;
31 import org.eclipse.aether.DefaultRepositorySystemSession;
32 import org.eclipse.aether.internal.test.util.TestFileUtils;
33 import org.eclipse.aether.internal.test.util.TestUtils;
34 import org.eclipse.aether.repository.RemoteRepository;
35 import org.eclipse.aether.spi.connector.transport.GetTask;
36 import org.eclipse.aether.spi.connector.transport.PeekTask;
37 import org.eclipse.aether.spi.connector.transport.PutTask;
38 import org.eclipse.aether.spi.connector.transport.Transporter;
39 import org.eclipse.aether.spi.connector.transport.TransporterFactory;
40 import org.eclipse.aether.transfer.NoTransporterException;
41 import org.eclipse.aether.transfer.TransferCancelledException;
42 import org.junit.jupiter.api.AfterEach;
43 import org.junit.jupiter.api.Assertions;
44 import org.junit.jupiter.api.Test;
45 import org.junit.jupiter.params.ParameterizedTest;
46 import org.junit.jupiter.params.provider.EnumSource;
47
48 import static org.junit.jupiter.api.Assertions.*;
49
50
51
52 public class FileTransporterTest {
53
54 private DefaultRepositorySystemSession session;
55
56 private TransporterFactory factory;
57
58 private Transporter transporter;
59
60 private Path repoDir;
61
62 private FileSystem fileSystem;
63
64 enum FS {
65 DEFAULT,
66 JIMFS
67 }
68
69 private RemoteRepository newRepo(String url) {
70 return new RemoteRepository.Builder("test", "default", url).build();
71 }
72
73 private void newTransporter(String url) throws Exception {
74 if (transporter != null) {
75 transporter.close();
76 transporter = null;
77 }
78 if (factory == null) {
79 factory = new FileTransporterFactory();
80 }
81 if (session == null) {
82 session = TestUtils.newSession();
83 }
84 transporter = factory.newInstance(session, newRepo(url));
85 }
86
87 void setUp(FS fs) {
88 try {
89 fileSystem = fs == FS.JIMFS ? Jimfs.newFileSystem() : null;
90 repoDir = fileSystem == null ? TestFileUtils.createTempDir().toPath() : fileSystem.getPath(".");
91 Files.write(repoDir.resolve("file.txt"), "test".getBytes(StandardCharsets.UTF_8));
92 Files.write(repoDir.resolve("empty.txt"), "".getBytes(StandardCharsets.UTF_8));
93 Files.write(repoDir.resolve("some space.txt"), "space".getBytes(StandardCharsets.UTF_8));
94 newTransporter(repoDir.toUri().toASCIIString());
95 } catch (Exception e) {
96 Assertions.fail(e);
97 }
98 }
99
100 @AfterEach
101 void tearDown() throws Exception {
102 if (transporter != null) {
103 transporter.close();
104 transporter = null;
105 }
106 if (fileSystem != null) {
107 fileSystem.close();
108 }
109 factory = null;
110 session = null;
111 }
112
113 @ParameterizedTest
114 @EnumSource(FS.class)
115 void testClassify(FS fs) {
116 setUp(fs);
117 assertEquals(Transporter.ERROR_OTHER, transporter.classify(new FileNotFoundException()));
118 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(new ResourceNotFoundException("test")));
119 }
120
121 @ParameterizedTest
122 @EnumSource(FS.class)
123 void testPeek(FS fs) throws Exception {
124 setUp(fs);
125 transporter.peek(new PeekTask(URI.create("file.txt")));
126 }
127
128 @ParameterizedTest
129 @EnumSource(FS.class)
130 void testPeek_NotFound(FS fs) throws Exception {
131 setUp(fs);
132 try {
133 transporter.peek(new PeekTask(URI.create("missing.txt")));
134 fail("Expected error");
135 } catch (ResourceNotFoundException e) {
136 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e));
137 }
138 }
139
140 @ParameterizedTest
141 @EnumSource(FS.class)
142 void testPeek_Closed(FS fs) throws Exception {
143 setUp(fs);
144 transporter.close();
145 try {
146 transporter.peek(new PeekTask(URI.create("missing.txt")));
147 fail("Expected error");
148 } catch (IllegalStateException e) {
149 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
150 }
151 }
152
153 @ParameterizedTest
154 @EnumSource(FS.class)
155 void testGet_ToMemory(FS fs) throws Exception {
156 setUp(fs);
157 RecordingTransportListener listener = new RecordingTransportListener();
158 GetTask task = new GetTask(URI.create("file.txt")).setListener(listener);
159 transporter.get(task);
160 assertEquals("test", task.getDataString());
161 assertEquals(0L, listener.dataOffset);
162 assertEquals(4L, listener.dataLength);
163 assertEquals(1, listener.startedCount);
164 assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
165 assertEquals(task.getDataString(), new String(listener.baos.toByteArray(), StandardCharsets.UTF_8));
166 }
167
168 @ParameterizedTest
169 @EnumSource(FS.class)
170 void testGet_ToFile(FS fs) throws Exception {
171 setUp(fs);
172 Path file = TestFileUtils.createTempFile("failure").toPath();
173 RecordingTransportListener listener = new RecordingTransportListener();
174 GetTask task = new GetTask(URI.create("file.txt")).setDataPath(file).setListener(listener);
175 transporter.get(task);
176 assertEquals("test", TestFileUtils.readString(file.toFile()));
177 assertEquals(0L, listener.dataOffset);
178 assertEquals(4L, listener.dataLength);
179 assertEquals(1, listener.startedCount);
180 assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
181 assertEquals("test", new String(listener.baos.toByteArray(), StandardCharsets.UTF_8));
182 }
183
184 @ParameterizedTest
185 @EnumSource(FS.class)
186 void testGet_EmptyResource(FS fs) throws Exception {
187 setUp(fs);
188 Path file = TestFileUtils.createTempFile("failure").toPath();
189 RecordingTransportListener listener = new RecordingTransportListener();
190 GetTask task = new GetTask(URI.create("empty.txt")).setDataPath(file).setListener(listener);
191 transporter.get(task);
192 assertEquals("", TestFileUtils.readString(file.toFile()));
193 assertEquals(0L, listener.dataOffset);
194 assertEquals(0L, listener.dataLength);
195 assertEquals(1, listener.startedCount);
196 assertEquals(0, listener.progressedCount);
197 assertEquals("", new String(listener.baos.toByteArray(), StandardCharsets.UTF_8));
198 }
199
200 @ParameterizedTest
201 @EnumSource(FS.class)
202 void testGet_EncodedResourcePath(FS fs) throws Exception {
203 setUp(fs);
204 GetTask task = new GetTask(URI.create("some%20space.txt"));
205 transporter.get(task);
206 assertEquals("space", task.getDataString());
207 }
208
209 @ParameterizedTest
210 @EnumSource(FS.class)
211 void testGet_Fragment(FS fs) throws Exception {
212 setUp(fs);
213 GetTask task = new GetTask(URI.create("file.txt#ignored"));
214 transporter.get(task);
215 assertEquals("test", task.getDataString());
216 }
217
218 @ParameterizedTest
219 @EnumSource(FS.class)
220 void testGet_Query(FS fs) throws Exception {
221 setUp(fs);
222 GetTask task = new GetTask(URI.create("file.txt?ignored"));
223 transporter.get(task);
224 assertEquals("test", task.getDataString());
225 }
226
227 @ParameterizedTest
228 @EnumSource(FS.class)
229 void testGet_FileHandleLeak(FS fs) throws Exception {
230 setUp(fs);
231 for (int i = 0; i < 100; i++) {
232 Path file = TestFileUtils.createTempFile("failure").toPath();
233 transporter.get(new GetTask(URI.create("file.txt")).setDataPath(file));
234 assertTrue(file.toFile().delete(), i + ", " + file.toFile().getAbsolutePath());
235 }
236 }
237
238 @ParameterizedTest
239 @EnumSource(FS.class)
240 void testGet_NotFound(FS fs) throws Exception {
241 setUp(fs);
242 try {
243 transporter.get(new GetTask(URI.create("missing.txt")));
244 fail("Expected error");
245 } catch (ResourceNotFoundException e) {
246 assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e));
247 }
248 }
249
250 @ParameterizedTest
251 @EnumSource(FS.class)
252 void testGet_Closed(FS fs) throws Exception {
253 setUp(fs);
254 transporter.close();
255 try {
256 transporter.get(new GetTask(URI.create("file.txt")));
257 fail("Expected error");
258 } catch (IllegalStateException e) {
259 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
260 }
261 }
262
263 @ParameterizedTest
264 @EnumSource(FS.class)
265 void testGet_StartCancelled(FS fs) throws Exception {
266 setUp(fs);
267 RecordingTransportListener listener = new RecordingTransportListener();
268 listener.cancelStart = true;
269 GetTask task = new GetTask(URI.create("file.txt")).setListener(listener);
270 try {
271 transporter.get(task);
272 fail("Expected error");
273 } catch (TransferCancelledException e) {
274 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
275 }
276 assertEquals(0L, listener.dataOffset);
277 assertEquals(4L, listener.dataLength);
278 assertEquals(1, listener.startedCount);
279 assertEquals(0, listener.progressedCount);
280 }
281
282 @ParameterizedTest
283 @EnumSource(FS.class)
284 void testGet_ProgressCancelled(FS fs) throws Exception {
285 setUp(fs);
286 RecordingTransportListener listener = new RecordingTransportListener();
287 listener.cancelProgress = true;
288 GetTask task = new GetTask(URI.create("file.txt")).setListener(listener);
289 try {
290 transporter.get(task);
291 fail("Expected error");
292 } catch (TransferCancelledException e) {
293 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
294 }
295 assertEquals(0L, listener.dataOffset);
296 assertEquals(4L, listener.dataLength);
297 assertEquals(1, listener.startedCount);
298 assertEquals(1, listener.progressedCount);
299 }
300
301 @ParameterizedTest
302 @EnumSource(FS.class)
303 void testPut_FromMemory(FS fs) throws Exception {
304 setUp(fs);
305 RecordingTransportListener listener = new RecordingTransportListener();
306 PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataString("upload");
307 transporter.put(task);
308 assertEquals(0L, listener.dataOffset);
309 assertEquals(6L, listener.dataLength);
310 assertEquals(1, listener.startedCount);
311 assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
312 assertEquals("upload", new String(Files.readAllBytes(repoDir.resolve("file.txt")), StandardCharsets.UTF_8));
313 }
314
315 @ParameterizedTest
316 @EnumSource(FS.class)
317 void testPut_FromFile(FS fs) throws Exception {
318 setUp(fs);
319 Path file = TestFileUtils.createTempFile("upload").toPath();
320 RecordingTransportListener listener = new RecordingTransportListener();
321 PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataPath(file);
322 transporter.put(task);
323 assertEquals(0L, listener.dataOffset);
324 assertEquals(6L, listener.dataLength);
325 assertEquals(1, listener.startedCount);
326 assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
327 assertEquals("upload", new String(Files.readAllBytes(repoDir.resolve("file.txt")), StandardCharsets.UTF_8));
328 }
329
330 @ParameterizedTest
331 @EnumSource(FS.class)
332 void testPut_EmptyResource(FS fs) throws Exception {
333 setUp(fs);
334 RecordingTransportListener listener = new RecordingTransportListener();
335 PutTask task = new PutTask(URI.create("file.txt")).setListener(listener);
336 transporter.put(task);
337 assertEquals(0L, listener.dataOffset);
338 assertEquals(0L, listener.dataLength);
339 assertEquals(1, listener.startedCount);
340 assertEquals(0, listener.progressedCount);
341 assertEquals("", new String(Files.readAllBytes(repoDir.resolve("file.txt")), StandardCharsets.UTF_8));
342 }
343
344 @ParameterizedTest
345 @EnumSource(FS.class)
346 void testPut_NonExistentParentDir(FS fs) throws Exception {
347 setUp(fs);
348 RecordingTransportListener listener = new RecordingTransportListener();
349 PutTask task = new PutTask(URI.create("dir/sub/dir/file.txt"))
350 .setListener(listener)
351 .setDataString("upload");
352 transporter.put(task);
353 assertEquals(0L, listener.dataOffset);
354 assertEquals(6L, listener.dataLength);
355 assertEquals(1, listener.startedCount);
356 assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
357 assertEquals(
358 "upload",
359 new String(Files.readAllBytes(repoDir.resolve("dir/sub/dir/file.txt")), StandardCharsets.UTF_8));
360 }
361
362 @ParameterizedTest
363 @EnumSource(FS.class)
364 void testPut_EncodedResourcePath(FS fs) throws Exception {
365 setUp(fs);
366 RecordingTransportListener listener = new RecordingTransportListener();
367 PutTask task = new PutTask(URI.create("some%20space.txt"))
368 .setListener(listener)
369 .setDataString("OK");
370 transporter.put(task);
371 assertEquals(0L, listener.dataOffset);
372 assertEquals(2L, listener.dataLength);
373 assertEquals(1, listener.startedCount);
374 assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
375 assertEquals("OK", new String(Files.readAllBytes(repoDir.resolve("some space.txt")), StandardCharsets.UTF_8));
376 }
377
378 @ParameterizedTest
379 @EnumSource(FS.class)
380 void testPut_FileHandleLeak(FS fs) throws Exception {
381 setUp(fs);
382 for (int i = 0; i < 100; i++) {
383 Path src = TestFileUtils.createTempFile("upload").toPath();
384 Path dst = repoDir.resolve("file.txt");
385 transporter.put(new PutTask(URI.create("file.txt")).setDataPath(src));
386 assertTrue(src.toFile().delete(), i + ", " + src.toFile().getAbsolutePath());
387 assertTrue(Files.deleteIfExists(dst), i + ", " + dst.toAbsolutePath());
388 }
389 }
390
391 @ParameterizedTest
392 @EnumSource(FS.class)
393 void testPut_Closed(FS fs) throws Exception {
394 setUp(fs);
395 transporter.close();
396 try {
397 transporter.put(new PutTask(URI.create("missing.txt")));
398 fail("Expected error");
399 } catch (IllegalStateException e) {
400 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
401 }
402 }
403
404 @ParameterizedTest
405 @EnumSource(FS.class)
406 void testPut_StartCancelled(FS fs) throws Exception {
407 setUp(fs);
408 RecordingTransportListener listener = new RecordingTransportListener();
409 listener.cancelStart = true;
410 PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataString("upload");
411 try {
412 transporter.put(task);
413 fail("Expected error");
414 } catch (TransferCancelledException e) {
415 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
416 }
417 assertEquals(0L, listener.dataOffset);
418 assertEquals(6L, listener.dataLength);
419 assertEquals(1, listener.startedCount);
420 assertEquals(0, listener.progressedCount);
421 assertFalse(Files.exists(repoDir.resolve("file.txt")));
422 }
423
424 @ParameterizedTest
425 @EnumSource(FS.class)
426 void testPut_ProgressCancelled(FS fs) throws Exception {
427 setUp(fs);
428 RecordingTransportListener listener = new RecordingTransportListener();
429 listener.cancelProgress = true;
430 PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataString("upload");
431 try {
432 transporter.put(task);
433 fail("Expected error");
434 } catch (TransferCancelledException e) {
435 assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
436 }
437 assertEquals(0L, listener.dataOffset);
438 assertEquals(6L, listener.dataLength);
439 assertEquals(1, listener.startedCount);
440 assertEquals(1, listener.progressedCount);
441 assertFalse(Files.exists(repoDir.resolve("file.txt")));
442 }
443
444 @Test
445 void testInit_BadProtocol() {
446 assertThrows(NoTransporterException.class, () -> newTransporter("bad:/void"));
447 }
448
449 @Test
450 void testInit_CaseInsensitiveProtocol() throws Exception {
451 newTransporter("file:/void");
452 newTransporter("FILE:/void");
453 newTransporter("File:/void");
454 }
455
456 @Test
457 void testInit_OpaqueUrl() throws Exception {
458 testInit("file:repository", "repository");
459 }
460
461 @Test
462 void testInit_OpaqueUrlTrailingSlash() throws Exception {
463 testInit("file:repository/", "repository");
464 }
465
466 @Test
467 void testInit_OpaqueUrlSpaces() throws Exception {
468 testInit("file:repo%20space", "repo space");
469 }
470
471 @Test
472 void testInit_OpaqueUrlSpacesDecoded() throws Exception {
473 testInit("file:repo space", "repo space");
474 }
475
476 @Test
477 void testInit_HierarchicalUrl() throws Exception {
478 testInit("file:/repository", "/repository");
479 }
480
481 @Test
482 void testInit_HierarchicalUrlTrailingSlash() throws Exception {
483 testInit("file:/repository/", "/repository");
484 }
485
486 @Test
487 void testInit_HierarchicalUrlSpaces() throws Exception {
488 testInit("file:/repo%20space", "/repo space");
489 }
490
491 @Test
492 void testInit_HierarchicalUrlSpacesDecoded() throws Exception {
493 testInit("file:/repo space", "/repo space");
494 }
495
496 @Test
497 void testInit_HierarchicalUrlRoot() throws Exception {
498 testInit("file:/", "/");
499 }
500
501 @Test
502 void testInit_HierarchicalUrlHostNoPath() throws Exception {
503 testInit("file://host/", "/");
504 }
505
506 @Test
507 void testInit_HierarchicalUrlHostPath() throws Exception {
508 testInit("file://host/dir", "/dir");
509 }
510
511 @Test
512 void testInit_NonDefaultFileSystemRelative() throws Exception {
513 try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
514 Path path = fs.getPath("dir");
515 testInit(path.toUri().toASCIIString(), "/work/dir");
516 }
517 }
518
519 @Test
520 void testInit_NonDefaultFileSystemAbsolute() throws Exception {
521 try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
522 Path path = fs.getPath("/dir");
523 testInit(path.toUri().toASCIIString(), "/dir");
524 }
525 }
526
527 private void testInit(String base, String expected) throws Exception {
528 newTransporter(base);
529 String exp = expected;
530 if (base.startsWith("file:")) {
531
532
533
534 exp = Paths.get(expected).toAbsolutePath().toString();
535 }
536
537
538 assertEquals(exp, ((FileTransporter) transporter).getBasePath().toString());
539 }
540 }