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