001package org.apache.maven.wagon.providers.webdav; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license 005 * agreements. See the NOTICE file distributed with this work for additional information regarding 006 * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance with the License. You may obtain a 008 * copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed under the License 013 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 014 * or implied. See the License for the specific language governing permissions and limitations under 015 * the License. 016 */ 017 018import it.could.webdav.DAVServlet; 019import org.apache.commons.httpclient.HttpException; 020import org.apache.commons.httpclient.HttpMethod; 021import org.apache.maven.wagon.ResourceDoesNotExistException; 022import org.apache.maven.wagon.StreamingWagon; 023import org.apache.maven.wagon.TransferFailedException; 024import org.apache.maven.wagon.Wagon; 025import org.apache.maven.wagon.http.HttpWagonTestCase; 026import org.apache.maven.wagon.repository.Repository; 027import org.apache.maven.wagon.resource.Resource; 028import org.mortbay.jetty.Server; 029import org.mortbay.jetty.servlet.Context; 030import org.mortbay.jetty.servlet.ServletHolder; 031 032import java.io.File; 033import java.io.IOException; 034import java.net.SocketTimeoutException; 035import java.util.List; 036import java.util.Properties; 037 038/* 039 * WebDAV Wagon Test 040 * 041 * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> 042 * 043 * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a> 044 */ 045public class WebDavWagonTest 046 extends HttpWagonTestCase 047{ 048 protected String getTestRepositoryUrl() 049 throws IOException 050 { 051 return getProtocol() + "://localhost:" + getTestRepositoryPort() + "/newfolder/folder2/"; 052 } 053 054 protected String getProtocol() 055 { 056 return "dav"; 057 } 058 059 protected void createContext( Server server, File repositoryDirectory ) 060 throws IOException 061 { 062 Context dav = new Context( server, "/", Context.SESSIONS ); 063 ServletHolder davServletHolder = new ServletHolder( new DAVServlet() ); 064 davServletHolder.setInitParameter( "rootPath", repositoryDirectory.getAbsolutePath() ); 065 davServletHolder.setInitParameter( "xmlOnly", "false" ); 066 dav.addServlet( davServletHolder, "/*" ); 067 } 068 069 protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource ) 070 { 071 File file = new File( getDavRepository(), resource.getName() ); 072 return ( file.lastModified() / 1000 ) * 1000; 073 } 074 075 076 private File getDavRepository() 077 { 078 return getTestFile( "target/test-output/http-repository/newfolder/folder2" ); 079 } 080 081 private void assertURL( String userUrl, String expectedUrl ) 082 { 083 Repository repo = new Repository( "test-geturl", userUrl ); 084 String actualUrl = ( new WebDavWagon() ).getURL( repo ); 085 assertEquals( "WebDavWagon.getURL(" + userUrl + ")", expectedUrl, actualUrl ); 086 } 087 088 /** 089 * Tests the maven 2.0.x way to define a webdav URL without SSL. 090 */ 091 public void testGetURLDavHttp() 092 { 093 assertURL( "dav:http://localhost:" + getTestRepositoryPort() + "/dav/", 094 "http://localhost:" + getTestRepositoryPort() + "/dav/" ); 095 } 096 097 /** 098 * Tests the maven 2.0.x way to define a webdav URL with SSL. 099 */ 100 public void testGetURLDavHttps() 101 { 102 assertURL( "dav:https://localhost:" + getTestRepositoryPort() + "/dav/", 103 "https://localhost:" + getTestRepositoryPort() + "/dav/" ); 104 } 105 106 /** 107 * Tests the URI spec way of defining a webdav URL without SSL. 108 */ 109 public void testGetURLDavUri() 110 { 111 assertURL( "dav://localhost:" + getTestRepositoryPort() + "/dav/", 112 "http://localhost:" + getTestRepositoryPort() + "/dav/" ); 113 } 114 115 /** 116 * Tests the URI spec way of defining a webdav URL with SSL. 117 */ 118 public void testGetURLDavUriWithSsl() 119 { 120 assertURL( "davs://localhost:" + getTestRepositoryPort() + "/dav/", 121 "https://localhost:" + getTestRepositoryPort() + "/dav/" ); 122 } 123 124 /** 125 * Tests the URI spec way of defining a webdav URL without SSL. 126 */ 127 public void testGetURLDavPlusHttp() 128 { 129 assertURL( "dav+https://localhost:" + getTestRepositoryPort() + "/dav/", 130 "https://localhost:" + getTestRepositoryPort() + "/dav/" ); 131 } 132 133 /** 134 * Tests the URI spec way of defining a webdav URL with SSL. 135 */ 136 public void testGetURLDavPlusHttps() 137 { 138 assertURL( "dav+https://localhost:" + getTestRepositoryPort() + "/dav/", 139 "https://localhost:" + getTestRepositoryPort() + "/dav/" ); 140 } 141 142 public void testMkdirs() 143 throws Exception 144 { 145 setupRepositories(); 146 147 setupWagonTestingFixtures(); 148 149 WebDavWagon wagon = (WebDavWagon) getWagon(); 150 wagon.connect( testRepository, getAuthInfo() ); 151 152 try 153 { 154 File dir = getRepositoryDirectory(); 155 156 // check basedir also doesn't exist and will need to be created 157 dir = new File( dir, testRepository.getBasedir() ); 158 assertFalse( dir.exists() ); 159 160 // test leading / 161 assertFalse( new File( dir, "foo" ).exists() ); 162 wagon.mkdirs( "/foo" ); 163 assertTrue( new File( dir, "foo" ).exists() ); 164 165 // test trailing / 166 assertFalse( new File( dir, "bar" ).exists() ); 167 wagon.mkdirs( "bar/" ); 168 assertTrue( new File( dir, "bar" ).exists() ); 169 170 // test when already exists 171 wagon.mkdirs( "bar" ); 172 173 // test several parts 174 assertFalse( new File( dir, "1/2/3/4" ).exists() ); 175 wagon.mkdirs( "1/2/3/4" ); 176 assertTrue( new File( dir, "1/2/3/4" ).exists() ); 177 178 // test additional part and trailing / 179 assertFalse( new File( dir, "1/2/3/4/5" ).exists() ); 180 wagon.mkdirs( "1/2/3/4/5/" ); 181 assertTrue( new File( dir, "1/2/3/4" ).exists() ); 182 } 183 finally 184 { 185 wagon.disconnect(); 186 187 tearDownWagonTestingFixtures(); 188 } 189 } 190 191 public void testMkdirsWithNoBasedir() 192 throws Exception 193 { 194 // WAGON-244 195 setupRepositories(); 196 197 setupWagonTestingFixtures(); 198 199 // reconstruct with no basedir 200 testRepository.setUrl( 201 testRepository.getProtocol() + "://" + testRepository.getHost() + ":" + testRepository.getPort() ); 202 203 WebDavWagon wagon = (WebDavWagon) getWagon(); 204 wagon.connect( testRepository, getAuthInfo() ); 205 206 try 207 { 208 File dir = getRepositoryDirectory(); 209 210 // check basedir also doesn't exist and will need to be created 211 dir = new File( dir, testRepository.getBasedir() ); 212 assertTrue( dir.exists() ); 213 214 // test leading / 215 assertFalse( new File( dir, "foo" ).exists() ); 216 wagon.mkdirs( "/foo" ); 217 assertTrue( new File( dir, "foo" ).exists() ); 218 } 219 finally 220 { 221 wagon.disconnect(); 222 223 tearDownWagonTestingFixtures(); 224 } 225 } 226 227 protected void setHttpHeaders( StreamingWagon wagon, Properties properties ) 228 { 229 ( (WebDavWagon) wagon ).setHttpHeaders( properties ); 230 } 231 232 /** 233 * Make sure wagon webdav can detect remote directory 234 * 235 * @throws Exception 236 */ 237 public void testWagonWebDavGetFileList() 238 throws Exception 239 { 240 setupRepositories(); 241 242 setupWagonTestingFixtures(); 243 244 String dirName = "file-list"; 245 246 String filenames[] = 247 new String[]{ "test-resource.txt", "test-resource.pom", "test-resource b.txt", "more-resources.dat" }; 248 249 for ( int i = 0; i < filenames.length; i++ ) 250 { 251 putFile( dirName + "/" + filenames[i], dirName + "/" + filenames[i], filenames[i] + "\n" ); 252 } 253 254 String dirnames[] = new String[]{ "test-dir1", "test-dir2" }; 255 256 for ( int i = 0; i < dirnames.length; i++ ) 257 { 258 new File( getDavRepository(), dirName + "/" + dirnames[i] ).mkdirs(); 259 } 260 261 Wagon wagon = getWagon(); 262 263 wagon.connect( testRepository, getAuthInfo() ); 264 265 List<String> list = wagon.getFileList( dirName ); 266 267 assertNotNull( "file list should not be null.", list ); 268 assertEquals( "file list should contain 6 items", 6, list.size() ); 269 270 for ( int i = 0; i < filenames.length; i++ ) 271 { 272 assertTrue( "Filename '" + filenames[i] + "' should be in list.", list.contains( filenames[i] ) ); 273 } 274 275 for ( int i = 0; i < dirnames.length; i++ ) 276 { 277 assertTrue( "Directory '" + dirnames[i] + "' should be in list.", list.contains( dirnames[i] + "/" ) ); 278 } 279 280 /////////////////////////////////////////////////////////////////////////// 281 list = wagon.getFileList( "" ); 282 assertNotNull( "file list should not be null.", list ); 283 assertEquals( "file list should contain 1 items", 1, list.size() ); 284 285 /////////////////////////////////////////////////////////////////////////// 286 list = wagon.getFileList( dirName + "/test-dir1" ); 287 assertNotNull( "file list should not be null.", list ); 288 assertEquals( "file list should contain 0 items", 0, list.size() ); 289 290 ///////////////////////////////////////////////////////////////////////////// 291 try 292 { 293 list = wagon.getFileList( dirName + "/test-dir-bogus" ); 294 fail( "Exception expected" ); 295 } 296 catch ( ResourceDoesNotExistException e ) 297 { 298 299 } 300 301 wagon.disconnect(); 302 303 tearDownWagonTestingFixtures(); 304 } 305 306 307 public void testWagonFailsOnPutFailureByDefault() 308 throws Exception 309 { 310 setupRepositories(); 311 312 setupWagonTestingFixtures(); 313 314 File testFile = getTempFile(); 315 316 System.clearProperty( WebDavWagon.CONTINUE_ON_FAILURE_PROPERTY ); 317 318 WebDavWagon wagon = new TimeoutSimulatingWagon(); 319 wagon.connect( testRepository, getAuthInfo() ); 320 321 try 322 { 323 String filename = TimeoutSimulatingWagon.TIMEOUT_TRIGGER + ".txt"; 324 325 try 326 { 327 wagon.put( testFile, filename ); 328 fail( "Exception expected" ); 329 } 330 catch ( TransferFailedException e ) 331 { 332 333 } 334 } 335 finally 336 { 337 wagon.disconnect(); 338 339 tearDownWagonTestingFixtures(); 340 } 341 } 342 343 private File getTempFile() 344 throws IOException 345 { 346 File inputFile = File.createTempFile( "test-resource", ".txt" ); 347 inputFile.deleteOnExit(); 348 return inputFile; 349 } 350 351 private static class TimeoutSimulatingWagon 352 extends WebDavWagon 353 { 354 private static final String TIMEOUT_TRIGGER = "timeout"; 355 356 protected int execute( HttpMethod httpMethod ) 357 throws HttpException, IOException 358 { 359 if ( httpMethod.getPath().contains( TIMEOUT_TRIGGER ) ) 360 { 361 throw new SocketTimeoutException( "Timeout triggered by request for '" + httpMethod.getPath() + "'" ); 362 } 363 else 364 { 365 return super.execute( httpMethod ); 366 } 367 } 368 } 369 370 public void testWagonContinuesOnPutFailureIfPropertySet() 371 throws Exception 372 { 373 setupRepositories(); 374 375 setupWagonTestingFixtures(); 376 377 File testFile = getTempFile(); 378 379 String continueOnFailureProperty = WebDavWagon.CONTINUE_ON_FAILURE_PROPERTY; 380 System.setProperty( continueOnFailureProperty, "true" ); 381 382 WebDavWagon wagon = new TimeoutSimulatingWagon(); 383 wagon.connect( testRepository, getAuthInfo() ); 384 385 try 386 { 387 String filename = TimeoutSimulatingWagon.TIMEOUT_TRIGGER + ".txt"; 388 389 wagon.put( testFile, filename ); 390 } 391 finally 392 { 393 wagon.disconnect(); 394 395 System.clearProperty( continueOnFailureProperty ); 396 397 tearDownWagonTestingFixtures(); 398 } 399 } 400 401 @Override 402 protected boolean supportPreemptiveAuthenticationPut() 403 { 404 return true; 405 } 406 407 @Override 408 protected boolean supportPreemptiveAuthenticationGet() 409 { 410 return false; 411 } 412 413 @Override 414 protected boolean supportProxyPreemptiveAuthentication() 415 { 416 return false; 417 } 418 419 protected void testPreemptiveAuthenticationGet( TestSecurityHandler sh, boolean preemptive ) 420 { 421 if ( preemptive ) 422 { 423 assertEquals( "testPreemptiveAuthenticationGet preemptive=true: expected 1 request, got " 424 + sh.handlerRequestResponses, 1, sh.handlerRequestResponses.size() ); 425 assertEquals( 200, sh.handlerRequestResponses.get( 0 ).responseCode ); 426 } 427 else 428 { 429 assertEquals( "testPreemptiveAuthenticationGet preemptive=false: expected 2 requests (401,200), got " 430 + sh.handlerRequestResponses, 2, sh.handlerRequestResponses.size() ); 431 assertEquals( 401, sh.handlerRequestResponses.get( 0 ).responseCode ); 432 assertEquals( 200, sh.handlerRequestResponses.get( 1 ).responseCode ); 433 } 434 } 435 436 protected void testPreemptiveAuthenticationPut( TestSecurityHandler sh, boolean preemptive ) 437 { 438 if ( preemptive ) 439 { 440 assertEquals( "testPreemptiveAuthenticationPut preemptive=true: expected 2 requests (200,.), got " 441 + sh.handlerRequestResponses, 2, sh.handlerRequestResponses.size() ); 442 assertEquals( 200, sh.handlerRequestResponses.get( 0 ).responseCode ); 443 } 444 else 445 { 446 assertEquals( "testPreemptiveAuthenticationPut preemptive=false: expected 3 requests (401,200,.), got " 447 + sh.handlerRequestResponses, 3, sh.handlerRequestResponses.size() ); 448 assertEquals( 401, sh.handlerRequestResponses.get( 0 ).responseCode ); 449 assertEquals( 200, sh.handlerRequestResponses.get( 1 ).responseCode ); 450 } 451 } 452 453 454 @Override 455 protected void testPreemptiveAuthentication( TestSecurityHandler sh, boolean preemptive ) 456 { 457 if ( preemptive ) 458 { 459 assertEquals( "testPreemptiveAuthentication preemptive=false: expected 2 requests (200,.), got " 460 + sh.handlerRequestResponses, 2, sh.handlerRequestResponses.size() ); 461 assertEquals( 200, sh.handlerRequestResponses.get( 0 ).responseCode ); 462 } 463 else 464 { 465 assertEquals( "testPreemptiveAuthentication preemptive=false: expected 3 requests (401,200,200), got " 466 + sh.handlerRequestResponses, 3, sh.handlerRequestResponses.size() ); 467 assertEquals( 401, sh.handlerRequestResponses.get( 0 ).responseCode ); 468 assertEquals( 200, sh.handlerRequestResponses.get( 1 ).responseCode ); 469 assertEquals( 200, sh.handlerRequestResponses.get( 2 ).responseCode ); 470 471 } 472 } 473 474 protected void checkRequestResponseForRedirectPutFromStreamWithFullUrl( PutHandler putHandler, 475 RedirectHandler redirectHandler ) 476 { 477 assertEquals( "found:" + putHandler.handlerRequestResponses, 1, putHandler.handlerRequestResponses.size() ); 478 assertEquals( "found:" + putHandler.handlerRequestResponses, 201, 479 putHandler.handlerRequestResponses.get( 0 ).responseCode ); 480 assertEquals( "found:" + redirectHandler.handlerRequestResponses, 3, 481 redirectHandler.handlerRequestResponses.size() ); 482 assertEquals( "found:" + redirectHandler.handlerRequestResponses, 302, 483 redirectHandler.handlerRequestResponses.get( 0 ).responseCode ); 484 } 485 486 protected void checkRequestResponseForRedirectPutFromStreamWithRelativeUrl( PutHandler putHandler, 487 RedirectHandler redirectHandler ) 488 { 489 assertEquals( "found:" + putHandler.handlerRequestResponses, 0, putHandler.handlerRequestResponses.size() ); 490 491 assertEquals( "found:" + redirectHandler.handlerRequestResponses, 4, 492 redirectHandler.handlerRequestResponses.size() ); 493 assertEquals( "found:" + redirectHandler.handlerRequestResponses, 302, 494 redirectHandler.handlerRequestResponses.get( 0 ).responseCode ); 495 assertEquals( "found:" + redirectHandler.handlerRequestResponses, 302, 496 redirectHandler.handlerRequestResponses.get( 1 ).responseCode ); 497 assertEquals( "found:" + redirectHandler.handlerRequestResponses, 201, 498 redirectHandler.handlerRequestResponses.get( 3 ).responseCode ); 499 500 } 501 502}