View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.transport.wagon;
20  
21  import java.io.File;
22  import java.net.URI;
23  import java.nio.charset.StandardCharsets;
24  import java.util.Map;
25  import java.util.UUID;
26  
27  import org.apache.maven.wagon.ResourceDoesNotExistException;
28  import org.apache.maven.wagon.TransferFailedException;
29  import org.apache.maven.wagon.Wagon;
30  import org.eclipse.aether.ConfigurationProperties;
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.Authentication;
35  import org.eclipse.aether.repository.Proxy;
36  import org.eclipse.aether.repository.RemoteRepository;
37  import org.eclipse.aether.spi.connector.transport.GetTask;
38  import org.eclipse.aether.spi.connector.transport.PeekTask;
39  import org.eclipse.aether.spi.connector.transport.PutTask;
40  import org.eclipse.aether.spi.connector.transport.Transporter;
41  import org.eclipse.aether.spi.connector.transport.TransporterFactory;
42  import org.eclipse.aether.spi.io.PathProcessorSupport;
43  import org.eclipse.aether.transfer.NoTransporterException;
44  import org.eclipse.aether.transfer.TransferCancelledException;
45  import org.eclipse.aether.util.repository.AuthenticationBuilder;
46  import org.junit.jupiter.api.AfterEach;
47  import org.junit.jupiter.api.BeforeEach;
48  import org.junit.jupiter.api.Test;
49  
50  import static org.eclipse.aether.transport.wagon.WagonTransporterConfigurationKeys.CONFIG_PROP_CONFIG;
51  import static org.junit.jupiter.api.Assertions.*;
52  
53  /**
54   */
55  public abstract class AbstractWagonTransporterTest {
56  
57      private DefaultRepositorySystemSession session;
58  
59      private TransporterFactory factory;
60  
61      private Transporter transporter;
62  
63      private String id;
64  
65      private Map<String, String> fs;
66  
67      protected abstract Wagon newWagon();
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          newTransporter(newRepo(url));
75      }
76  
77      private void newTransporter(RemoteRepository repo) throws Exception {
78          if (transporter != null) {
79              transporter.close();
80              transporter = null;
81          }
82          transporter = factory.newInstance(session, repo);
83      }
84  
85      @BeforeEach
86      void setUp() throws Exception {
87          session = TestUtils.newSession();
88          factory = new WagonTransporterFactory(
89                  new WagonProvider() {
90                      public Wagon lookup(String roleHint) {
91                          if ("mem".equalsIgnoreCase(roleHint)) {
92                              return newWagon();
93                          }
94                          throw new IllegalArgumentException("unknown wagon role: " + roleHint);
95                      }
96  
97                      public void release(Wagon wagon) {}
98                  },
99                  new WagonConfigurator() {
100                     public void configure(Wagon wagon, Object configuration) {
101                         ((Configurable) wagon).setConfiguration(configuration);
102                     }
103                 },
104                 new PathProcessorSupport());
105         id = UUID.randomUUID().toString().replace("-", "");
106         fs = MemWagonUtils.getFilesystem(id);
107         fs.put("file.txt", "test");
108         fs.put("empty.txt", "");
109         fs.put("some space.txt", "space");
110         newTransporter("mem://" + id);
111     }
112 
113     @AfterEach
114     void tearDown() {
115         if (transporter != null) {
116             transporter.close();
117             transporter = null;
118         }
119         factory = null;
120         session = null;
121     }
122 
123     @Test
124     void testClassify() {
125         assertEquals(Transporter.ERROR_OTHER, transporter.classify(new TransferFailedException("test")));
126         assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(new ResourceDoesNotExistException("test")));
127     }
128 
129     @Test
130     void testPeek() throws Exception {
131         transporter.peek(new PeekTask(URI.create("file.txt")));
132     }
133 
134     @Test
135     void testPeek_NotFound() throws Exception {
136         try {
137             transporter.peek(new PeekTask(URI.create("missing.txt")));
138             fail("Expected error");
139         } catch (ResourceDoesNotExistException e) {
140             assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e));
141         }
142     }
143 
144     @Test
145     void testPeek_Closed() throws Exception {
146         transporter.close();
147         try {
148             transporter.peek(new PeekTask(URI.create("missing.txt")));
149             fail("Expected error");
150         } catch (IllegalStateException e) {
151             assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
152         }
153     }
154 
155     @Test
156     void testGet_ToMemory() throws Exception {
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     @Test
169     void testGet_ToFile() throws Exception {
170         File file = TestFileUtils.createTempFile("failure");
171         RecordingTransportListener listener = new RecordingTransportListener();
172         GetTask task = new GetTask(URI.create("file.txt")).setDataFile(file).setListener(listener);
173         transporter.get(task);
174         assertEquals("test", TestFileUtils.readString(file));
175         assertEquals(0L, listener.dataOffset);
176         assertEquals(4L, listener.dataLength);
177         assertEquals(1, listener.startedCount);
178         assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
179         assertEquals("test", new String(listener.baos.toByteArray(), StandardCharsets.UTF_8));
180     }
181 
182     @Test
183     void testGet_EmptyResource() throws Exception {
184         File file = TestFileUtils.createTempFile("failure");
185         assertTrue(file.delete() && !file.exists());
186         RecordingTransportListener listener = new RecordingTransportListener();
187         GetTask task = new GetTask(URI.create("empty.txt")).setDataFile(file).setListener(listener);
188         transporter.get(task);
189         assertEquals("", TestFileUtils.readString(file));
190         assertEquals(0L, listener.dataOffset);
191         assertEquals(0L, listener.dataLength);
192         assertEquals(1, listener.startedCount);
193         assertEquals(0, listener.progressedCount);
194         assertEquals("", new String(listener.baos.toByteArray(), StandardCharsets.UTF_8));
195     }
196 
197     @Test
198     void testGet_EncodedResourcePath() throws Exception {
199         GetTask task = new GetTask(URI.create("some%20space.txt"));
200         transporter.get(task);
201         assertEquals("space", task.getDataString());
202     }
203 
204     @Test
205     void testGet_FileHandleLeak() throws Exception {
206         for (int i = 0; i < 100; i++) {
207             File file = TestFileUtils.createTempFile("failure");
208             transporter.get(new GetTask(URI.create("file.txt")).setDataFile(file));
209             assertTrue(file.delete(), i + ", " + file.getAbsolutePath());
210         }
211     }
212 
213     @Test
214     void testGet_NotFound() throws Exception {
215         try {
216             transporter.get(new GetTask(URI.create("missing.txt")));
217             fail("Expected error");
218         } catch (ResourceDoesNotExistException e) {
219             assertEquals(Transporter.ERROR_NOT_FOUND, transporter.classify(e));
220         }
221     }
222 
223     @Test
224     void testGet_Closed() throws Exception {
225         transporter.close();
226         try {
227             transporter.get(new GetTask(URI.create("file.txt")));
228             fail("Expected error");
229         } catch (IllegalStateException e) {
230             assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
231         }
232     }
233 
234     @Test
235     void testGet_StartCancelled() throws Exception {
236         RecordingTransportListener listener = new RecordingTransportListener();
237         listener.cancelStart = true;
238         GetTask task = new GetTask(URI.create("file.txt")).setListener(listener);
239         transporter.get(task);
240         assertEquals(1, listener.startedCount);
241     }
242 
243     @Test
244     void testGet_ProgressCancelled() throws Exception {
245         RecordingTransportListener listener = new RecordingTransportListener();
246         listener.cancelProgress = true;
247         GetTask task = new GetTask(URI.create("file.txt")).setListener(listener);
248         try {
249             transporter.get(task);
250             fail("Expected error");
251         } catch (TransferCancelledException e) {
252             assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
253         }
254         assertEquals(0L, listener.dataOffset);
255         assertEquals(4L, listener.dataLength);
256         assertEquals(1, listener.startedCount);
257         assertEquals(1, listener.progressedCount);
258     }
259 
260     @Test
261     void testPut_FromMemory() throws Exception {
262         RecordingTransportListener listener = new RecordingTransportListener();
263         PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataString("upload");
264         transporter.put(task);
265         assertEquals(0L, listener.dataOffset);
266         assertEquals(6L, listener.dataLength);
267         assertEquals(1, listener.startedCount);
268         assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
269         assertEquals("upload", fs.get("file.txt"));
270     }
271 
272     @Test
273     void testPut_FromFile() throws Exception {
274         File file = TestFileUtils.createTempFile("upload");
275         RecordingTransportListener listener = new RecordingTransportListener();
276         PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataFile(file);
277         transporter.put(task);
278         assertEquals(0L, listener.dataOffset);
279         assertEquals(6L, listener.dataLength);
280         assertEquals(1, listener.startedCount);
281         assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
282         assertEquals("upload", fs.get("file.txt"));
283     }
284 
285     @Test
286     void testPut_EmptyResource() throws Exception {
287         RecordingTransportListener listener = new RecordingTransportListener();
288         PutTask task = new PutTask(URI.create("file.txt")).setListener(listener);
289         transporter.put(task);
290         assertEquals(0L, listener.dataOffset);
291         assertEquals(0L, listener.dataLength);
292         assertEquals(1, listener.startedCount);
293         assertEquals(0, listener.progressedCount);
294         assertEquals("", fs.get("file.txt"));
295     }
296 
297     @Test
298     void testPut_NonExistentParentDir() throws Exception {
299         RecordingTransportListener listener = new RecordingTransportListener();
300         PutTask task = new PutTask(URI.create("dir/sub/dir/file.txt"))
301                 .setListener(listener)
302                 .setDataString("upload");
303         transporter.put(task);
304         assertEquals(0L, listener.dataOffset);
305         assertEquals(6L, listener.dataLength);
306         assertEquals(1, listener.startedCount);
307         assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
308         assertEquals("upload", fs.get("dir/sub/dir/file.txt"));
309     }
310 
311     @Test
312     void testPut_EncodedResourcePath() throws Exception {
313         RecordingTransportListener listener = new RecordingTransportListener();
314         PutTask task = new PutTask(URI.create("some%20space.txt"))
315                 .setListener(listener)
316                 .setDataString("OK");
317         transporter.put(task);
318         assertEquals(0L, listener.dataOffset);
319         assertEquals(2L, listener.dataLength);
320         assertEquals(1, listener.startedCount);
321         assertTrue(listener.progressedCount > 0, "Count: " + listener.progressedCount);
322         assertEquals("OK", fs.get("some space.txt"));
323     }
324 
325     @Test
326     void testPut_FileHandleLeak() throws Exception {
327         for (int i = 0; i < 100; i++) {
328             File src = TestFileUtils.createTempFile("upload");
329             transporter.put(new PutTask(URI.create("file.txt")).setDataFile(src));
330             assertTrue(src.delete(), i + ", " + src.getAbsolutePath());
331         }
332     }
333 
334     @Test
335     void testPut_Closed() throws Exception {
336         transporter.close();
337         try {
338             transporter.put(new PutTask(URI.create("missing.txt")));
339             fail("Expected error");
340         } catch (IllegalStateException e) {
341             assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
342         }
343     }
344 
345     @Test
346     void testPut_StartCancelled() throws Exception {
347         RecordingTransportListener listener = new RecordingTransportListener();
348         listener.cancelStart = true;
349         PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataString("upload");
350         transporter.put(task);
351         assertEquals(1, listener.startedCount);
352     }
353 
354     @Test
355     void testPut_ProgressCancelled() throws Exception {
356         RecordingTransportListener listener = new RecordingTransportListener();
357         listener.cancelProgress = true;
358         PutTask task = new PutTask(URI.create("file.txt")).setListener(listener).setDataString("upload");
359         try {
360             transporter.put(task);
361             fail("Expected error");
362         } catch (TransferCancelledException e) {
363             assertEquals(Transporter.ERROR_OTHER, transporter.classify(e));
364         }
365         assertEquals(0L, listener.dataOffset);
366         assertEquals(6L, listener.dataLength);
367         assertEquals(1, listener.startedCount);
368         assertEquals(1, listener.progressedCount);
369     }
370 
371     @Test
372     void testInit_BadProtocol() {
373         assertThrows(NoTransporterException.class, () -> newTransporter("bad:/void"));
374     }
375 
376     @Test
377     void testInit_CaseInsensitiveProtocol() throws Exception {
378         newTransporter("mem:/void");
379         newTransporter("MEM:/void");
380         newTransporter("mEm:/void");
381     }
382 
383     @Test
384     void testInit_Configuration() throws Exception {
385         session.setConfigProperty(CONFIG_PROP_CONFIG + ".test", "passed");
386         newTransporter("mem://" + id + "?config=passed");
387         transporter.peek(new PeekTask(URI.create("file.txt")));
388     }
389 
390     @Test
391     void testInit_UserAgent() throws Exception {
392         session.setConfigProperty(ConfigurationProperties.USER_AGENT, "Test/1.0");
393         newTransporter("mem://" + id + "?userAgent=Test/1.0");
394         transporter.peek(new PeekTask(URI.create("file.txt")));
395     }
396 
397     @Test
398     void testInit_Timeout() throws Exception {
399         session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, "12345678");
400         newTransporter("mem://" + id + "?requestTimeout=12345678");
401         transporter.peek(new PeekTask(URI.create("file.txt")));
402     }
403 
404     @Test
405     void testInit_ServerAuth() throws Exception {
406         String url = "mem://" + id + "?serverUsername=testuser&serverPassword=testpass"
407                 + "&serverPrivateKey=testkey&serverPassphrase=testphrase";
408         Authentication auth = new AuthenticationBuilder()
409                 .addUsername("testuser")
410                 .addPassword("testpass")
411                 .addPrivateKey("testkey", "testphrase")
412                 .build();
413         RemoteRepository repo = new RemoteRepository.Builder("test", "default", url)
414                 .setAuthentication(auth)
415                 .build();
416         newTransporter(repo);
417         transporter.peek(new PeekTask(URI.create("file.txt")));
418     }
419 
420     @Test
421     void testInit_Proxy() throws Exception {
422         String url = "mem://" + id + "?proxyHost=testhost&proxyPort=8888";
423         RemoteRepository repo = new RemoteRepository.Builder("test", "default", url)
424                 .setProxy(new Proxy("http", "testhost", 8888))
425                 .build();
426         newTransporter(repo);
427         transporter.peek(new PeekTask(URI.create("file.txt")));
428     }
429 
430     @Test
431     void testInit_ProxyAuth() throws Exception {
432         String url = "mem://" + id + "?proxyUsername=testuser&proxyPassword=testpass";
433         Authentication auth = new AuthenticationBuilder()
434                 .addUsername("testuser")
435                 .addPassword("testpass")
436                 .build();
437         RemoteRepository repo = new RemoteRepository.Builder("test", "default", url)
438                 .setProxy(new Proxy("http", "testhost", 8888, auth))
439                 .build();
440         newTransporter(repo);
441         transporter.peek(new PeekTask(URI.create("file.txt")));
442     }
443 }