1 package org.apache.archiva.webdav;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.gargoylesoftware.htmlunit.HttpMethod;
23 import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
24 import com.gargoylesoftware.htmlunit.WebClient;
25 import com.gargoylesoftware.htmlunit.WebRequest;
26 import com.gargoylesoftware.htmlunit.WebResponse;
27 import junit.framework.TestCase;
28 import net.sf.ehcache.CacheManager;
29 import org.apache.archiva.admin.model.beans.ManagedRepository;
30 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
31 import org.apache.archiva.configuration.ArchivaConfiguration;
32 import org.apache.archiva.configuration.Configuration;
33 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
34 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
35 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
36 import org.apache.archiva.webdav.httpunit.MkColMethodWebRequest;
37 import org.apache.archiva.webdav.util.MavenIndexerCleaner;
38 import org.apache.commons.io.FileUtils;
39 import org.apache.commons.io.IOUtils;
40 import org.junit.After;
41 import org.junit.Assert;
42 import org.junit.Before;
43 import org.junit.runner.RunWith;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.beans.BeansException;
47 import org.springframework.beans.factory.BeanFactory;
48 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
49 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
50 import org.springframework.context.ApplicationContext;
51 import org.springframework.context.ApplicationEvent;
52 import org.springframework.context.MessageSourceResolvable;
53 import org.springframework.context.NoSuchMessageException;
54 import org.springframework.core.ResolvableType;
55 import org.springframework.core.env.Environment;
56 import org.springframework.core.io.Resource;
57 import org.springframework.mock.web.MockHttpServletRequest;
58 import org.springframework.mock.web.MockHttpServletResponse;
59 import org.springframework.mock.web.MockServletConfig;
60 import org.springframework.mock.web.MockServletContext;
61 import org.springframework.test.context.ContextConfiguration;
62 import org.springframework.web.context.WebApplicationContext;
63
64 import javax.inject.Inject;
65 import javax.servlet.Servlet;
66 import javax.servlet.ServletContext;
67 import javax.servlet.http.HttpServletRequest;
68 import javax.servlet.http.HttpServletResponse;
69 import java.io.File;
70 import java.io.IOException;
71 import java.io.InputStream;
72 import java.io.UnsupportedEncodingException;
73 import java.lang.annotation.Annotation;
74 import java.net.URL;
75 import java.nio.charset.Charset;
76 import java.util.Locale;
77 import java.util.Map;
78 import org.apache.commons.lang.StringUtils;
79
80
81
82
83 @RunWith( ArchivaSpringJUnit4ClassRunner.class )
84 @ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:spring-context.xml",
85 "classpath*:/repository-servlet-simple.xml" } )
86 public abstract class AbstractRepositoryServletTestCase
87 extends TestCase
88 {
89 protected static final String REPOID_INTERNAL = "internal";
90
91 protected File repoRootInternal;
92
93 protected File repoRootLegacy;
94
95 @Inject
96 protected ArchivaConfiguration archivaConfiguration;
97
98 @Inject
99 protected ApplicationContext applicationContext;
100
101 @Inject
102 protected ManagedRepositoryAdmin managedRepositoryAdmin;
103
104 protected Logger log = LoggerFactory.getLogger( getClass() );
105
106
107 protected void saveConfiguration()
108 throws Exception
109 {
110 saveConfiguration( archivaConfiguration );
111 }
112
113 @Before
114 @Override
115 public void setUp()
116 throws Exception
117 {
118
119 super.setUp();
120
121 String appserverBase = new File( "target/appserver-base" ).getAbsolutePath();
122 System.setProperty( "appserver.base", appserverBase );
123
124 File testConf = new File( "src/test/resources/repository-archiva.xml" );
125 File testConfDest = new File( appserverBase, "conf/archiva.xml" );
126 if ( testConfDest.exists() )
127 {
128 FileUtils.deleteQuietly( testConfDest );
129 }
130 FileUtils.copyFile( testConf, testConfDest );
131
132 repoRootInternal = new File( appserverBase, "data/repositories/internal" );
133 repoRootLegacy = new File( appserverBase, "data/repositories/legacy" );
134 Configuration config = archivaConfiguration.getConfiguration();
135
136 config.getManagedRepositories().clear();
137
138 config.addManagedRepository(
139 createManagedRepository( REPOID_INTERNAL, "Internal Test Repo", repoRootInternal, true ) );
140
141 managedRepositoryAdmin.createIndexContext( managedRepositoryAdmin.getManagedRepository( REPOID_INTERNAL ) );
142
143 config.getProxyConnectors().clear();
144
145 config.getRemoteRepositories().clear();
146
147 saveConfiguration( archivaConfiguration );
148
149 CacheManager.getInstance().clearAll();
150
151 applicationContext.getBean( MavenIndexerCleaner.class ).cleanupIndex();
152
153
154 }
155
156 protected UnauthenticatedRepositoryServlet unauthenticatedRepositoryServlet =
157 new UnauthenticatedRepositoryServlet();
158
159 protected void startRepository()
160 throws Exception
161 {
162
163 final MockServletContext mockServletContext = new MockServletContext();
164
165 WebApplicationContext webApplicationContext =
166 new TestWebapplicationContext( applicationContext, mockServletContext );
167
168 mockServletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
169 webApplicationContext );
170
171 MockServletConfig mockServletConfig = new MockServletConfig()
172 {
173 @Override
174 public ServletContext getServletContext()
175 {
176 return mockServletContext;
177 }
178 };
179
180 unauthenticatedRepositoryServlet.init( mockServletConfig );
181
182 }
183
184 protected String createVersionMetadata(String groupId, String artifactId, String version) {
185 return createVersionMetadata(groupId, artifactId, version, null, null, null);
186 }
187
188 protected String createVersionMetadata(String groupId, String artifactId, String version, String timestamp, String buildNumber, String lastUpdated) {
189 StringBuilder buf = new StringBuilder();
190 buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
191 buf.append("<metadata>\n");
192 buf.append(" <groupId>").append(groupId).append("</groupId>\n");
193 buf.append(" <artifactId>").append(artifactId).append("</artifactId>\n");
194 buf.append(" <version>").append(version).append("</version>\n");
195 boolean hasSnapshot = StringUtils.isNotBlank(timestamp) || StringUtils.isNotBlank(buildNumber);
196 boolean hasLastUpdated = StringUtils.isNotBlank(lastUpdated);
197 if (hasSnapshot || hasLastUpdated) {
198 buf.append(" <versioning>\n");
199 if (hasSnapshot) {
200 buf.append(" <snapshot>\n");
201 buf.append(" <buildNumber>").append(buildNumber).append("</buildNumber>\n");
202 buf.append(" <timestamp>").append(timestamp).append("</timestamp>\n");
203 buf.append(" </snapshot>\n");
204 }
205 if (hasLastUpdated) {
206 buf.append(" <lastUpdated>").append(lastUpdated).append("</lastUpdated>\n");
207 }
208 buf.append(" </versioning>\n");
209 }
210 buf.append("</metadata>");
211 return buf.toString();
212 }
213
214
215 public static class TestWebapplicationContext
216 implements WebApplicationContext
217 {
218 private ApplicationContext applicationContext;
219
220 private ServletContext servletContext;
221
222 TestWebapplicationContext( ApplicationContext applicationContext, ServletContext servletContext )
223 {
224 this.applicationContext = applicationContext;
225 }
226
227 @Override
228 public ServletContext getServletContext()
229 {
230 return servletContext;
231 }
232
233 @Override
234 public String getId()
235 {
236 return applicationContext.getId();
237 }
238
239 @Override
240 public String getApplicationName()
241 {
242 return applicationContext.getApplicationName();
243 }
244
245 @Override
246 public String getDisplayName()
247 {
248 return applicationContext.getDisplayName();
249 }
250
251 @Override
252 public long getStartupDate()
253 {
254 return applicationContext.getStartupDate();
255 }
256
257 @Override
258 public ApplicationContext getParent()
259 {
260 return applicationContext.getParent();
261 }
262
263 @Override
264 public AutowireCapableBeanFactory getAutowireCapableBeanFactory()
265 throws IllegalStateException
266 {
267 return applicationContext.getAutowireCapableBeanFactory();
268 }
269
270 @Override
271 public void publishEvent( ApplicationEvent applicationEvent )
272 {
273 applicationContext.publishEvent( applicationEvent );
274 }
275
276 @Override
277 public Environment getEnvironment()
278 {
279 return applicationContext.getEnvironment();
280 }
281
282 @Override
283 public BeanFactory getParentBeanFactory()
284 {
285 return applicationContext.getParentBeanFactory();
286 }
287
288 @Override
289 public boolean containsLocalBean( String s )
290 {
291 return applicationContext.containsLocalBean( s );
292 }
293
294 @Override
295 public boolean containsBeanDefinition( String s )
296 {
297 return applicationContext.containsBeanDefinition( s );
298 }
299
300 @Override
301 public int getBeanDefinitionCount()
302 {
303 return applicationContext.getBeanDefinitionCount();
304 }
305
306 @Override
307 public String[] getBeanDefinitionNames()
308 {
309 return applicationContext.getBeanDefinitionNames();
310 }
311
312 @Override
313 public String[] getBeanNamesForType( Class<?> aClass )
314 {
315 return applicationContext.getBeanNamesForType( aClass );
316 }
317
318 @Override
319 public String[] getBeanNamesForType( Class<?> aClass, boolean b, boolean b2 )
320 {
321 return applicationContext.getBeanNamesForType( aClass, b, b2 );
322 }
323
324 @Override
325 public <T> Map<String, T> getBeansOfType( Class<T> tClass )
326 throws BeansException
327 {
328 return applicationContext.getBeansOfType( tClass );
329 }
330
331 @Override
332 public <T> Map<String, T> getBeansOfType( Class<T> tClass, boolean b, boolean b2 )
333 throws BeansException
334 {
335 return applicationContext.getBeansOfType( tClass, b, b2 );
336 }
337
338 @Override
339 public String[] getBeanNamesForAnnotation( Class<? extends Annotation> aClass )
340 {
341 return applicationContext.getBeanNamesForAnnotation( aClass );
342 }
343
344 @Override
345 public Map<String, Object> getBeansWithAnnotation( Class<? extends Annotation> aClass )
346 throws BeansException
347 {
348 return applicationContext.getBeansWithAnnotation( aClass );
349 }
350
351 @Override
352 public <A extends Annotation> A findAnnotationOnBean( String s, Class<A> aClass )
353 throws NoSuchBeanDefinitionException
354 {
355 return applicationContext.findAnnotationOnBean( s, aClass );
356 }
357
358 @Override
359 public <T> T getBean( Class<T> aClass, Object... objects )
360 throws BeansException
361 {
362 return applicationContext.getBean( aClass, objects );
363 }
364
365 @Override
366 public Object getBean( String s )
367 throws BeansException
368 {
369 return applicationContext.getBean( s );
370 }
371
372 @Override
373 public <T> T getBean( String s, Class<T> tClass )
374 throws BeansException
375 {
376 return applicationContext.getBean( s, tClass );
377 }
378
379 @Override
380 public <T> T getBean( Class<T> tClass )
381 throws BeansException
382 {
383 return applicationContext.getBean( tClass );
384 }
385
386 @Override
387 public Object getBean( String s, Object... objects )
388 throws BeansException
389 {
390 return applicationContext.getBean( s, objects );
391 }
392
393 @Override
394 public boolean containsBean( String s )
395 {
396 return applicationContext.containsBean( s );
397 }
398
399 @Override
400 public boolean isSingleton( String s )
401 throws NoSuchBeanDefinitionException
402 {
403 return applicationContext.isSingleton( s );
404 }
405
406 @Override
407 public boolean isPrototype( String s )
408 throws NoSuchBeanDefinitionException
409 {
410 return applicationContext.isPrototype( s );
411 }
412
413 @Override
414 public boolean isTypeMatch( String s, Class<?> aClass )
415 throws NoSuchBeanDefinitionException
416 {
417 return applicationContext.isTypeMatch( s, aClass );
418 }
419
420 @Override
421 public Class<?> getType( String s )
422 throws NoSuchBeanDefinitionException
423 {
424 return applicationContext.getType( s );
425 }
426
427 @Override
428 public String[] getAliases( String s )
429 {
430 return applicationContext.getAliases( s );
431 }
432
433 @Override
434 public String getMessage( String s, Object[] objects, String s2, Locale locale )
435 {
436 return applicationContext.getMessage( s, objects, s2, locale );
437 }
438
439 @Override
440 public String getMessage( String s, Object[] objects, Locale locale )
441 throws NoSuchMessageException
442 {
443 return applicationContext.getMessage( s, objects, locale );
444 }
445
446 @Override
447 public String getMessage( MessageSourceResolvable messageSourceResolvable, Locale locale )
448 throws NoSuchMessageException
449 {
450 return applicationContext.getMessage( messageSourceResolvable, locale );
451 }
452
453 @Override
454 public Resource[] getResources( String s )
455 throws IOException
456 {
457 return applicationContext.getResources( s );
458 }
459
460 @Override
461 public void publishEvent( Object o )
462 {
463
464 }
465
466 @Override
467 public String[] getBeanNamesForType( ResolvableType resolvableType )
468 {
469 return new String[0];
470 }
471
472 @Override
473 public boolean isTypeMatch( String s, ResolvableType resolvableType )
474 throws NoSuchBeanDefinitionException
475 {
476 return false;
477 }
478
479 @Override
480 public Resource getResource( String s )
481 {
482 return applicationContext.getResource( s );
483 }
484
485 @Override
486 public ClassLoader getClassLoader()
487 {
488 return applicationContext.getClassLoader();
489 }
490 }
491
492 protected Servlet findServlet( String name )
493 throws Exception
494 {
495 return unauthenticatedRepositoryServlet;
496
497 }
498
499 protected String getSpringConfigLocation()
500 {
501 return "classpath*:/META-INF/spring-context.xml,classpath*:spring-context.xml";
502 }
503
504
505 protected static WebClient newClient()
506 {
507 final WebClient webClient = new WebClient();
508 webClient.getOptions().setJavaScriptEnabled( false );
509 webClient.getOptions().setCssEnabled( false );
510 webClient.getOptions().setAppletEnabled( false );
511 webClient.getOptions().setThrowExceptionOnFailingStatusCode( false );
512 webClient.setAjaxController( new NicelyResynchronizingAjaxController() );
513 return webClient;
514 }
515
516
517 protected WebResponse getWebResponse( String path )
518 throws Exception
519 {
520 return getWebResponse( new GetMethodWebRequest( "http://localhost" + path ) );//, false );
521 }
522
523 protected WebResponse getWebResponse( WebRequest webRequest )
524 throws Exception
525 {
526
527 MockHttpServletRequest request = new MockHttpServletRequest();
528 request.setRequestURI( webRequest.getUrl().getPath() );
529 request.addHeader( "User-Agent", "Apache Archiva unit test" );
530
531 request.setMethod( webRequest.getHttpMethod().name() );
532
533 if ( webRequest.getHttpMethod() == HttpMethod.PUT )
534 {
535 PutMethodWebRequest putRequest = PutMethodWebRequest.class.cast( webRequest );
536 request.setContentType( putRequest.contentType );
537 request.setContent( IOUtils.toByteArray( putRequest.inputStream ) );
538 }
539
540 if ( webRequest instanceof MkColMethodWebRequest )
541 {
542 request.setMethod( "MKCOL" );
543 }
544
545 final MockHttpServletResponse response = execute( request );
546
547 if ( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY
548 || response.getStatus() == HttpServletResponse.SC_MOVED_TEMPORARILY )
549 {
550 String location = response.getHeader( "Location" );
551 log.debug( "follow redirect to {}", location );
552 return getWebResponse( new GetMethodWebRequest( location ) );
553 }
554
555 return new WebResponse( null, null, 1 )
556 {
557 @Override
558 public String getContentAsString()
559 {
560 try
561 {
562 return response.getContentAsString();
563 }
564 catch ( UnsupportedEncodingException e )
565 {
566 throw new RuntimeException( e.getMessage(), e );
567 }
568 }
569
570 @Override
571 public int getStatusCode()
572 {
573 return response.getStatus();
574 }
575
576 @Override
577 public String getResponseHeaderValue( String headerName )
578 {
579 return response.getHeader( headerName );
580 }
581 };
582 }
583
584 protected MockHttpServletResponse execute( HttpServletRequest request )
585 throws Exception
586 {
587 MockHttpServletResponse response = new MockHttpServletResponse()
588 {
589 @Override
590 public String getContentAsString()
591 throws UnsupportedEncodingException
592 {
593 String errorMessage = getErrorMessage();
594 return ( errorMessage != null ) ? errorMessage : super.getContentAsString();
595 }
596 };
597 this.unauthenticatedRepositoryServlet.service( request, response );
598 return response;
599 }
600
601 public static class GetMethodWebRequest
602 extends WebRequest
603 {
604 String url;
605
606 public GetMethodWebRequest( String url )
607 throws Exception
608 {
609 super( new URL( url ) );
610 this.url = url;
611
612 }
613 }
614
615 public static class PutMethodWebRequest
616 extends WebRequest
617 {
618 String url;
619
620 InputStream inputStream;
621
622 String contentType;
623
624 public PutMethodWebRequest( String url, InputStream inputStream, String contentType )
625 throws Exception
626 {
627 super( new URL( url ), HttpMethod.PUT );
628 this.url = url;
629 this.inputStream = inputStream;
630 this.contentType = contentType;
631 }
632
633
634 }
635
636 public static class ServletUnitClient
637 {
638
639 AbstractRepositoryServletTestCase abstractRepositoryServletTestCase;
640
641 public ServletUnitClient( AbstractRepositoryServletTestCase abstractRepositoryServletTestCase )
642 {
643 this.abstractRepositoryServletTestCase = abstractRepositoryServletTestCase;
644 }
645
646 public WebResponse getResponse( WebRequest request )
647 throws Exception
648 {
649 return getResponse( request, false );
650 }
651
652 public WebResponse getResponse( WebRequest request, boolean followRedirect )
653 throws Exception
654 {
655
656 return abstractRepositoryServletTestCase.getWebResponse( request );
657 }
658
659 public WebResponse getResource( WebRequest request )
660 throws Exception
661 {
662 return getResponse( request );
663 }
664 }
665
666 public ServletUnitClient getServletUnitClient()
667 {
668 return new ServletUnitClient( this );
669 }
670
671 @Override
672 @After
673 public void tearDown()
674 throws Exception
675 {
676
677 if ( repoRootInternal.exists() )
678 {
679 FileUtils.deleteDirectory( repoRootInternal );
680 }
681
682 if ( repoRootLegacy.exists() )
683 {
684 FileUtils.deleteDirectory( repoRootLegacy );
685 }
686
687 }
688
689
690 protected void assertFileContents( String expectedContents, File repoRoot, String path )
691 throws IOException
692 {
693 File actualFile = new File( repoRoot, path );
694 assertTrue( "File <" + actualFile.getAbsolutePath() + "> should exist.", actualFile.exists() );
695 assertTrue( "File <" + actualFile.getAbsolutePath() + "> should be a file (not a dir/link/device/etc).",
696 actualFile.isFile() );
697
698 String actualContents = FileUtils.readFileToString( actualFile, Charset.defaultCharset() );
699 assertEquals( "File Contents of <" + actualFile.getAbsolutePath() + ">", expectedContents, actualContents );
700 }
701
702 protected void assertRepositoryValid( RepositoryServlet servlet, String repoId )
703 throws Exception
704 {
705 ManagedRepository repository = servlet.getRepository( repoId );
706 assertNotNull( "Archiva Managed Repository id:<" + repoId + "> should exist.", repository );
707 File repoRoot = new File( repository.getLocation() );
708 assertTrue( "Archiva Managed Repository id:<" + repoId + "> should have a valid location on disk.",
709 repoRoot.exists() && repoRoot.isDirectory() );
710 }
711
712 protected void assertResponseOK( WebResponse response )
713 {
714 assertNotNull( "Should have recieved a response", response );
715 Assert.assertEquals( "Should have been an OK response code",
716 HttpServletResponse.SC_OK,
717 response.getStatusCode() );
718 }
719
720 protected void assertResponseOK( WebResponse response, String path )
721 {
722 assertNotNull( "Should have recieved a response", response );
723 Assert.assertEquals( "Should have been an OK response code for path: " + path, HttpServletResponse.SC_OK,
724 response.getStatusCode() );
725 }
726
727 protected void assertResponseNotFound( WebResponse response )
728 {
729 assertNotNull( "Should have recieved a response", response );
730 Assert.assertEquals( "Should have been an 404/Not Found response code.", HttpServletResponse.SC_NOT_FOUND,
731 response.getStatusCode() );
732 }
733
734 protected void assertResponseInternalServerError( WebResponse response )
735 {
736 assertNotNull( "Should have recieved a response", response );
737 Assert.assertEquals( "Should have been an 500/Internal Server Error response code.",
738 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatusCode() );
739 }
740
741 protected void assertResponseConflictError( WebResponse response )
742 {
743 assertNotNull( "Should have received a response", response );
744 Assert.assertEquals( "Should have been a 409/Conflict response code.", HttpServletResponse.SC_CONFLICT,
745 response.getStatusCode() );
746 }
747
748 protected ManagedRepositoryConfiguration createManagedRepository( String id, String name, File location,
749 boolean blockRedeployments )
750 {
751 ManagedRepositoryConfiguration repo = new ManagedRepositoryConfiguration();
752 repo.setId( id );
753 repo.setName( name );
754 repo.setLocation( location.getAbsolutePath() );
755 repo.setBlockRedeployments( blockRedeployments );
756
757 return repo;
758 }
759
760 protected ManagedRepositoryConfiguration createManagedRepository( String id, String name, File location,
761 String layout, boolean blockRedeployments )
762 {
763 ManagedRepositoryConfiguration repo = createManagedRepository( id, name, location, blockRedeployments );
764 repo.setLayout( layout );
765 return repo;
766 }
767
768 protected RemoteRepositoryConfiguration createRemoteRepository( String id, String name, String url )
769 {
770 RemoteRepositoryConfiguration repo = new RemoteRepositoryConfiguration();
771 repo.setId( id );
772 repo.setName( name );
773 repo.setUrl( url );
774 return repo;
775 }
776
777 protected void saveConfiguration( ArchivaConfiguration archivaConfiguration )
778 throws Exception
779 {
780 archivaConfiguration.save( archivaConfiguration.getConfiguration() );
781 }
782
783
784 protected void setupCleanRepo( File repoRootDir )
785 throws IOException
786 {
787 FileUtils.deleteDirectory( repoRootDir );
788 if ( !repoRootDir.exists() )
789 {
790 repoRootDir.mkdirs();
791 }
792 }
793
794 protected void assertManagedFileNotExists( File repoRootInternal, String resourcePath )
795 {
796 File repoFile = new File( repoRootInternal, resourcePath );
797 assertFalse( "Managed Repository File <" + repoFile.getAbsolutePath() + "> should not exist.",
798 repoFile.exists() );
799 }
800
801 protected void setupCleanInternalRepo()
802 throws Exception
803 {
804 setupCleanRepo( repoRootInternal );
805 }
806
807 protected File populateRepo( File repoRootManaged, String path, String contents )
808 throws Exception
809 {
810 File destFile = new File( repoRootManaged, path );
811 destFile.getParentFile().mkdirs();
812 FileUtils.writeStringToFile( destFile, contents, Charset.defaultCharset() );
813 return destFile;
814 }
815 }