View Javadoc
1   package org.apache.maven.wagon.providers.webdav;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import it.could.webdav.DAVServlet;
23  import org.apache.http.HttpException;
24  import org.apache.http.client.methods.CloseableHttpResponse;
25  import org.apache.http.client.methods.HttpUriRequest;
26  import org.apache.maven.wagon.ResourceDoesNotExistException;
27  import org.apache.maven.wagon.StreamingWagon;
28  import org.apache.maven.wagon.TransferFailedException;
29  import org.apache.maven.wagon.Wagon;
30  import org.apache.maven.wagon.http.HttpWagonTestCase;
31  import org.apache.maven.wagon.repository.Repository;
32  import org.apache.maven.wagon.resource.Resource;
33  import org.apache.maven.wagon.shared.http.HttpConfiguration;
34  import org.apache.maven.wagon.shared.http.HttpMethodConfiguration;
35  import org.eclipse.jetty.server.Server;
36  import org.eclipse.jetty.servlet.ServletContextHandler;
37  import org.eclipse.jetty.servlet.ServletHolder;
38  
39  import java.io.File;
40  import java.io.IOException;
41  import java.net.SocketTimeoutException;
42  import java.util.List;
43  import java.util.Properties;
44  
45  import javax.servlet.http.HttpServletResponse;
46  
47  /*
48   * WebDAV Wagon Test
49   *
50   * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
51   *
52   * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
53   */
54  public class WebDavWagonTest
55      extends HttpWagonTestCase
56  {
57  
58      protected String getTestRepositoryUrl()
59          throws IOException
60      {
61          return getProtocol() + "://localhost:" + getTestRepositoryPort() + "/newfolder/folder2/";
62      }
63  
64      protected String getProtocol()
65      {
66          return "dav";
67      }
68  
69      protected ServletContextHandler createContext( Server server, File repositoryDirectory )
70          throws IOException
71      {
72          ServletContextHandler dav = new ServletContextHandler( ServletContextHandler.SESSIONS );
73          ServletHolder davServletHolder = new ServletHolder( new DAVServlet() );
74          davServletHolder.setInitParameter( "rootPath", repositoryDirectory.getAbsolutePath() );
75          davServletHolder.setInitParameter( "xmlOnly", "false" );
76          dav.addServlet( davServletHolder, "/*" );
77          return dav;
78      }
79  
80      protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource )
81      {
82          File file = new File( getDavRepository(), resource.getName() );
83          return ( file.lastModified() / 1000L ) * 1000L;
84      }
85  
86  
87      private File getDavRepository()
88      {
89          return getTestFile( "target/test-output/http-repository/newfolder/folder2" );
90      }
91  
92      private void assertURL( String userUrl, String expectedUrl )
93      {
94          Repository repo = new Repository( "test-geturl", userUrl );
95          String actualUrl = ( new WebDavWagon() ).getURL( repo );
96          assertEquals( "WebDavWagon.getURL(" + userUrl + ")", expectedUrl, actualUrl );
97      }
98  
99      /**
100      * Tests the maven 2.0.x way to define a webdav URL without SSL.
101      */
102     public void testGetURLDavHttp()
103     {
104         assertURL( "dav:http://localhost:9080/dav/",
105                    "http://localhost:9080/dav/" );
106     }
107 
108     /**
109      * Tests the maven 2.0.x way to define a webdav URL with SSL.
110      */
111     public void testGetURLDavHttps()
112     {
113         assertURL( "dav:https://localhost:9443/dav/",
114                    "https://localhost:9443/dav/" );
115     }
116 
117     /**
118      * Tests the URI spec way of defining a webdav URL without SSL.
119      */
120     public void testGetURLDavUri()
121     {
122         assertURL( "dav://localhost:9080/dav/",
123                    "http://localhost:9080/dav/" );
124     }
125 
126     /**
127      * Tests the URI spec way of defining a webdav URL with SSL.
128      */
129     public void testGetURLDavUriWithSsl()
130     {
131         assertURL( "davs://localhost:9443/dav/",
132                    "https://localhost:9443/dav/" );
133     }
134 
135     /**
136      * Tests the URI spec way of defining a webdav URL without SSL.
137      */
138     public void testGetURLDavPlusHttp()
139     {
140         assertURL( "dav+https://localhost:" + getTestRepositoryPort() + "/dav/",
141                    "https://localhost:" + getTestRepositoryPort() + "/dav/" );
142     }
143 
144     /**
145      * Tests the URI spec way of defining a webdav URL with SSL.
146      */
147     public void testGetURLDavPlusHttps()
148     {
149         assertURL( "dav+https://localhost:9443/dav/",
150                    "https://localhost:9443/dav/" );
151     }
152 
153     public void testMkdirs()
154         throws Exception
155     {
156         setupWagonTestingFixtures();
157 
158         setupRepositories();
159 
160         WebDavWagon wagon = (WebDavWagon) getWagon();
161         wagon.connect( testRepository, getAuthInfo() );
162 
163         try
164         {
165             File dir = getRepositoryDirectory();
166 
167             // check basedir also doesn't exist and will need to be created
168             dir = new File( dir, testRepository.getBasedir() );
169             assertFalse( dir.exists() );
170 
171             // test leading /
172             assertFalse( new File( dir, "foo" ).exists() );
173             wagon.mkdirs( "/foo" );
174             assertTrue( new File( dir, "foo" ).exists() );
175 
176             // test trailing /
177             assertFalse( new File( dir, "bar" ).exists() );
178             wagon.mkdirs( "bar/" );
179             assertTrue( new File( dir, "bar" ).exists() );
180 
181             // test when already exists
182             wagon.mkdirs( "bar" );
183 
184             // test several parts
185             assertFalse( new File( dir, "1/2/3/4" ).exists() );
186             wagon.mkdirs( "1/2/3/4" );
187             assertTrue( new File( dir, "1/2/3/4" ).exists() );
188 
189             // test additional part and trailing /
190             assertFalse( new File( dir, "1/2/3/4/5" ).exists() );
191             wagon.mkdirs( "1/2/3/4/5/" );
192             assertTrue( new File( dir, "1/2/3/4" ).exists() );
193         }
194         finally
195         {
196             wagon.disconnect();
197 
198             tearDownWagonTestingFixtures();
199         }
200     }
201 
202     public void testMkdirsWithNoBasedir()
203         throws Exception
204     {
205         // WAGON-244
206         setupWagonTestingFixtures();
207 
208         setupRepositories();
209 
210         // reconstruct with no basedir
211         testRepository.setUrl(
212             testRepository.getProtocol() + "://" + testRepository.getHost() + ":" + testRepository.getPort() );
213 
214         WebDavWagon wagon = (WebDavWagon) getWagon();
215         wagon.connect( testRepository, getAuthInfo() );
216 
217         try
218         {
219             File dir = getRepositoryDirectory();
220 
221             // check basedir also doesn't exist and will need to be created
222             dir = new File( dir, testRepository.getBasedir() );
223             assertTrue( dir.exists() );
224 
225             // test leading /
226             assertFalse( new File( dir, "foo" ).exists() );
227             wagon.mkdirs( "/foo" );
228             assertTrue( new File( dir, "foo" ).exists() );
229         }
230         finally
231         {
232             wagon.disconnect();
233 
234             tearDownWagonTestingFixtures();
235         }
236     }
237 
238     protected void setHttpConfiguration( StreamingWagon wagon, Properties headers, Properties params )
239     {
240         HttpConfiguration config = new HttpConfiguration();
241 
242         HttpMethodConfiguration methodConfiguration = new HttpMethodConfiguration();
243         methodConfiguration.setHeaders( headers );
244         methodConfiguration.setParams( params );
245         config.setAll( methodConfiguration );
246         ( (WebDavWagon) wagon ).setHttpConfiguration( config );
247     }
248 
249     /**
250      * Make sure Wagon WebDAV can detect remote directory
251      *
252      * @throws Exception
253      */
254     public void testWagonWebDavGetFileList()
255         throws Exception
256     {
257         setupWagonTestingFixtures();
258 
259         setupRepositories();
260 
261         String dirName = "file-list";
262 
263         String filenames[] =
264             new String[]{ "test-resource.txt", "test-resource.pom", "test-resource b.txt", "more-resources.dat" };
265 
266         for ( int i = 0; i < filenames.length; i++ )
267         {
268             putFile( dirName + "/" + filenames[i], dirName + "/" + filenames[i], filenames[i] + "\n" );
269         }
270 
271         String dirnames[] = new String[]{ "test-dir1", "test-dir2" };
272 
273         for ( int i = 0; i < dirnames.length; i++ )
274         {
275             new File( getDavRepository(), dirName + "/" + dirnames[i] ).mkdirs();
276         }
277 
278         Wagon wagon = getWagon();
279 
280         wagon.connect( testRepository, getAuthInfo() );
281 
282         List<String> list = wagon.getFileList( dirName );
283 
284         assertNotNull( "file list should not be null.", list );
285         assertEquals( "file list should contain 6 items", 6, list.size() );
286 
287         for ( int i = 0; i < filenames.length; i++ )
288         {
289             assertTrue( "Filename '" + filenames[i] + "' should be in list.", list.contains( filenames[i] ) );
290         }
291 
292         for ( int i = 0; i < dirnames.length; i++ )
293         {
294             assertTrue( "Directory '" + dirnames[i] + "' should be in list.", list.contains( dirnames[i] + "/" ) );
295         }
296 
297         ///////////////////////////////////////////////////////////////////////////
298         list = wagon.getFileList( "" );
299         assertNotNull( "file list should not be null.", list );
300         assertEquals( "file list should contain 1 items", 1, list.size() );
301 
302         ///////////////////////////////////////////////////////////////////////////
303         list = wagon.getFileList( dirName + "/test-dir1" );
304         assertNotNull( "file list should not be null.", list );
305         assertEquals( "file list should contain 0 items", 0, list.size() );
306 
307         /////////////////////////////////////////////////////////////////////////////
308         try
309         {
310             list = wagon.getFileList( dirName + "/test-dir-bogus" );
311             fail( "Exception expected" );
312         }
313         catch ( ResourceDoesNotExistException e )
314         {
315 
316         }
317 
318         wagon.disconnect();
319 
320         tearDownWagonTestingFixtures();
321     }
322 
323 
324     public void testWagonFailsOnPutFailureByDefault()
325         throws Exception
326     {
327         setupWagonTestingFixtures();
328 
329         setupRepositories();
330 
331         File testFile = getTempFile();
332 
333         System.clearProperty( WebDavWagon.CONTINUE_ON_FAILURE_PROPERTY );
334 
335         WebDavWagon wagon = new TimeoutSimulatingWagon();
336         wagon.connect( testRepository, getAuthInfo() );
337 
338         try
339         {
340             String filename = TimeoutSimulatingWagon.TIMEOUT_TRIGGER + ".txt";
341 
342             try
343             {
344                 wagon.put( testFile, filename );
345                 fail( "Exception expected" );
346             }
347             catch ( TransferFailedException e )
348             {
349 
350             }
351         }
352         finally
353         {
354             wagon.disconnect();
355 
356             tearDownWagonTestingFixtures();
357         }
358     }
359 
360     private File getTempFile()
361         throws IOException
362     {
363         File inputFile = File.createTempFile( "test-resource", ".txt" );
364         inputFile.deleteOnExit();
365         return inputFile;
366     }
367 
368     private static class TimeoutSimulatingWagon
369         extends WebDavWagon
370     {
371         private static final String TIMEOUT_TRIGGER = "timeout";
372 
373         protected CloseableHttpResponse execute( HttpUriRequest httpRequestBase )
374             throws HttpException, IOException
375         {
376             if ( httpRequestBase.getURI().getPath().contains( TIMEOUT_TRIGGER ) )
377             {
378                 throw new SocketTimeoutException( "Timeout triggered by request for '" + httpRequestBase.getURI().getPath() + "'" );
379             }
380             else
381             {
382                 return super.execute( httpRequestBase );
383             }
384         }
385     }
386 
387     public void testWagonContinuesOnPutFailureIfPropertySet()
388         throws Exception
389     {
390         setupWagonTestingFixtures();
391 
392         setupRepositories();
393 
394         File testFile = getTempFile();
395 
396         String continueOnFailureProperty = WebDavWagon.CONTINUE_ON_FAILURE_PROPERTY;
397         System.setProperty( continueOnFailureProperty, "true" );
398 
399         WebDavWagon wagon = new TimeoutSimulatingWagon();
400         wagon.connect( testRepository, getAuthInfo() );
401 
402         try
403         {
404             String filename = TimeoutSimulatingWagon.TIMEOUT_TRIGGER + ".txt";
405 
406             wagon.put( testFile, filename );
407         }
408         finally
409         {
410             wagon.disconnect();
411 
412             System.clearProperty( continueOnFailureProperty );
413 
414             tearDownWagonTestingFixtures();
415         }
416     }
417 
418     @Override
419     protected boolean supportPreemptiveAuthenticationPut()
420     {
421         return false;
422     }
423 
424     @Override
425     protected boolean supportPreemptiveAuthenticationGet()
426     {
427         return false;
428     }
429 
430     @Override
431     protected boolean supportProxyPreemptiveAuthentication()
432     {
433         return true;
434     }
435 
436     protected void testPreemptiveAuthenticationGet( TestSecurityHandler sh, boolean preemptive )
437     {
438         if ( preemptive )
439         {
440             assertEquals( "testPreemptiveAuthenticationGet preemptive=true: expected 1 request, got "
441                 + sh.handlerRequestResponses, 1, sh.handlerRequestResponses.size() );
442             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 0 ).responseCode );
443         }
444         else
445         {
446             assertEquals( "testPreemptiveAuthenticationGet preemptive=false: expected 2 requests (401,200), got "
447                 + sh.handlerRequestResponses, 2, sh.handlerRequestResponses.size() );
448             assertEquals( HttpServletResponse.SC_UNAUTHORIZED, sh.handlerRequestResponses.get( 0 ).responseCode );
449             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 1 ).responseCode );
450         }
451     }
452 
453     protected void testPreemptiveAuthenticationPut( TestSecurityHandler sh, boolean preemptive )
454     {
455         if ( preemptive )
456         {
457             assertEquals( "testPreemptiveAuthenticationPut preemptive=true: expected 2 requests (200,201), got "
458                 + sh.handlerRequestResponses, 2, sh.handlerRequestResponses.size() );
459             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 0 ).responseCode );
460             assertEquals( HttpServletResponse.SC_CREATED, sh.handlerRequestResponses.get( 1 ).responseCode );
461         }
462         else
463         {
464             assertEquals( "testPreemptiveAuthenticationPut preemptive=false: expected 3 requests (401,200,201), got "
465                 + sh.handlerRequestResponses, 3, sh.handlerRequestResponses.size() );
466             assertEquals( HttpServletResponse.SC_UNAUTHORIZED, sh.handlerRequestResponses.get( 0 ).responseCode );
467             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 1 ).responseCode );
468             assertEquals( HttpServletResponse.SC_CREATED, sh.handlerRequestResponses.get( 2 ).responseCode );
469         }
470     }
471 
472 
473     /* This method cannot be reasonable used to represend GET and PUT for WebDAV, it would contain too much
474      * duplicate code. Leave as-is, but don't use it.
475      */
476     protected void testPreemptiveAuthentication( TestSecurityHandler sh, boolean preemptive )
477     {
478         if ( preemptive )
479         {
480             assertEquals( "testPreemptiveAuthentication preemptive=false: expected 2 requests (200,.), got "
481                 + sh.handlerRequestResponses, 2, sh.handlerRequestResponses.size() );
482             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 0 ).responseCode );
483         }
484         else
485         {
486             assertEquals( "testPreemptiveAuthentication preemptive=false: expected 3 requests (401,200,200), got "
487                 + sh.handlerRequestResponses, 3, sh.handlerRequestResponses.size() );
488             assertEquals( HttpServletResponse.SC_UNAUTHORIZED, sh.handlerRequestResponses.get( 0 ).responseCode );
489             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 1 ).responseCode );
490             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 2 ).responseCode );
491 
492         }
493     }
494 
495     @Override
496     protected void checkRequestResponseForRedirectPutWithFullUrl( RedirectHandler redirectHandler,
497                                                                   PutHandler putHandler )
498     {
499         assertEquals( "found:" + putHandler.handlerRequestResponses, 1, putHandler.handlerRequestResponses.size() );
500         assertEquals( "found:" + putHandler.handlerRequestResponses, HttpServletResponse.SC_CREATED,
501                       putHandler.handlerRequestResponses.get( 0 ).responseCode );
502         assertEquals( "found:" + redirectHandler.handlerRequestResponses, 2,
503                       redirectHandler.handlerRequestResponses.size() );
504         assertEquals( "found:" + redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER,
505                       redirectHandler.handlerRequestResponses.get( 0 ).responseCode );
506     }
507 
508     @Override
509     protected void checkRequestResponseForRedirectPutWithRelativeUrl( RedirectHandler redirectHandler,
510                                                                       PutHandler putHandler )
511     {
512         assertEquals( "found:" + putHandler.handlerRequestResponses, 0, putHandler.handlerRequestResponses.size() );
513 
514         assertEquals( "found:" + redirectHandler.handlerRequestResponses, 4,
515                       redirectHandler.handlerRequestResponses.size() );
516         assertEquals( "found:" + redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER,
517                       redirectHandler.handlerRequestResponses.get( 0 ).responseCode );
518         assertEquals( "found:" + redirectHandler.handlerRequestResponses, HttpServletResponse.SC_OK,
519                       redirectHandler.handlerRequestResponses.get( 1 ).responseCode );
520         assertEquals( "found:" + redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER,
521                       redirectHandler.handlerRequestResponses.get( 2 ).responseCode );
522 
523     }
524 
525     @Override
526     protected void verifyWagonExceptionMessage( Exception e, int forStatusCode, String forUrl, String forReasonPhrase )
527     {
528         Repository repo = new Repository( "test-geturl", forUrl );
529         String expectedMessageUrl = ( new WebDavWagon() ).getURL( repo );
530         super.verifyWagonExceptionMessage( e, forStatusCode, expectedMessageUrl, forReasonPhrase );
531     }
532 }