1 package org.apache.archiva.webdav;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
22 import com.gargoylesoftware.htmlunit.*;
23 import junit.framework.TestCase;
24 import net.sf.ehcache.CacheManager;
25 import org.apache.archiva.configuration.ArchivaConfiguration;
26 import org.apache.archiva.configuration.Configuration;
27 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
28 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
29 import org.apache.archiva.indexer.ArchivaIndexingContext;
30 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
31 import org.apache.archiva.repository.ManagedRepository;
32 import org.apache.archiva.repository.RepositoryType;
33 import org.apache.archiva.repository.base.RepositoryGroupHandler;
34 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
35 import org.apache.archiva.webdav.httpunit.MkColMethodWebRequest;
36 import org.apache.commons.io.FileUtils;
37 import org.apache.commons.io.IOUtils;
38 import org.apache.commons.lang3.StringUtils;
39 import org.junit.After;
40 import org.junit.Assert;
41 import org.junit.Before;
42 import org.junit.runner.RunWith;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.beans.BeansException;
46 import org.springframework.beans.factory.BeanFactory;
47 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
48 import org.springframework.beans.factory.ObjectProvider;
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;
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.IOException;
70 import java.io.InputStream;
71 import java.io.UnsupportedEncodingException;
72 import java.lang.annotation.Annotation;
74 import java.nio.charset.Charset;
75 import java.nio.file.Files;
76 import java.nio.file.Path;
77 import java.nio.file.Paths;
78 import java.util.Locale;
80 import java.util.concurrent.atomic.AtomicReference;
83 * AbstractRepositoryServletTestCase
85 @RunWith( ArchivaSpringJUnit4ClassRunner.class )
86 @ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:spring-context.xml",
87 "classpath*:/repository-servlet-simple.xml" } )
88 public abstract class AbstractRepositoryServletTestCase
91 protected static final String REPOID_INTERNAL = "internal";
93 protected Path repoRootInternal;
95 protected Path repoRootLegacy;
98 protected ArchivaConfiguration archivaConfiguration;
101 protected ApplicationContext applicationContext;
103 @SuppressWarnings( "unused" )
105 RepositoryGroupHandler repositoryGroupHandler;
108 ArchivaRepositoryRegistry repositoryRegistry;
110 protected Logger log = LoggerFactory.getLogger( getClass() );
112 private AtomicReference<Path> projectBase = new AtomicReference<>( );
113 private AtomicReference<Path> appserverBase = new AtomicReference<>( );
116 public Path getProjectBase() {
117 if (this.projectBase.get()==null) {
118 String pathVal = System.getProperty("mvn.project.base.dir");
120 if (StringUtils.isEmpty(pathVal)) {
121 baseDir= Paths.get("").toAbsolutePath();
123 baseDir = Paths.get(pathVal).toAbsolutePath();
125 this.projectBase.compareAndSet(null, baseDir);
127 return this.projectBase.get();
130 public Path getAppserverBase() {
131 if (appserverBase.get()==null)
133 String pathVal = System.getProperty( "appserver.base" );
135 if ( StringUtils.isNotEmpty( pathVal ) )
137 basePath = Paths.get( pathVal );
141 log.warn("Using relative path to working directory, appserver.base was not set!");
142 basePath = Paths.get( "target/appserver-base" );
144 appserverBase.set( basePath );
146 return appserverBase.get();
149 protected void saveConfiguration()
152 repositoryRegistry.setArchivaConfiguration(archivaConfiguration);
153 repositoryRegistry.reload();
154 saveConfiguration( archivaConfiguration );
166 System.setProperty( "appserver.base", getAppserverBase().toAbsolutePath().toString());
167 log.info("setUp appserverBase={}, projectBase={}, workingDir={}", getAppserverBase(), getProjectBase(), Paths.get("").toString());
169 repositoryRegistry.getRepositories().stream().forEach(r -> r.close());
171 org.apache.archiva.common.utils.FileUtils.deleteDirectory( getAppserverBase() );
173 Path testConf = getProjectBase().resolve( "src/test/resources/repository-archiva.xml" );
174 Path testConfDest = getAppserverBase().resolve("conf/archiva.xml" );
175 if ( Files.exists(testConfDest) )
177 org.apache.archiva.common.utils.FileUtils.deleteQuietly( testConfDest );
179 FileUtils.copyFile( testConf.toFile(), testConfDest.toFile() );
181 repoRootInternal = getAppserverBase().resolve("data/repositories/internal" );
182 repoRootLegacy = getAppserverBase().resolve( "data/repositories/legacy" );
183 Configuration config = archivaConfiguration.getConfiguration();
185 config.getManagedRepositories().clear();
187 config.addManagedRepository(
188 createManagedRepository( REPOID_INTERNAL, "Internal Test Repo", repoRootInternal, true ) );
189 config.getProxyConnectors().clear();
191 config.getRemoteRepositories().clear();
193 saveConfiguration( archivaConfiguration );
195 ArchivaIndexingContext ctx = repositoryRegistry.getManagedRepository( REPOID_INTERNAL ).getIndexingContext( );
198 if (repositoryRegistry.getIndexManager(RepositoryType.MAVEN)!=null) {
199 repositoryRegistry.getIndexManager(RepositoryType.MAVEN).pack(ctx);
209 CacheManager.getInstance().clearAll();
214 protected UnauthenticatedRepositoryServlet unauthenticatedRepositoryServlet =
215 new UnauthenticatedRepositoryServlet();
217 protected void startRepository()
221 final MockServletContext mockServletContext = new MockServletContext();
223 WebApplicationContext webApplicationContext =
224 new TestWebapplicationContext( applicationContext, mockServletContext );
226 mockServletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
227 webApplicationContext );
229 MockServletConfig mockServletConfig = new MockServletConfig()
232 public ServletContext getServletContext()
234 return mockServletContext;
238 unauthenticatedRepositoryServlet.init( mockServletConfig );
242 protected String createVersionMetadata(String groupId, String artifactId, String version) {
243 return createVersionMetadata(groupId, artifactId, version, null, null, null);
246 protected String createVersionMetadata(String groupId, String artifactId, String version, String timestamp, String buildNumber, String lastUpdated) {
247 StringBuilder buf = new StringBuilder();
248 buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
249 buf.append("<metadata>\n");
250 buf.append(" <groupId>").append(groupId).append("</groupId>\n");
251 buf.append(" <artifactId>").append(artifactId).append("</artifactId>\n");
252 buf.append(" <version>").append(version).append("</version>\n");
253 boolean hasSnapshot = StringUtils.isNotBlank(timestamp) || StringUtils.isNotBlank(buildNumber);
254 boolean hasLastUpdated = StringUtils.isNotBlank(lastUpdated);
255 if (hasSnapshot || hasLastUpdated) {
256 buf.append(" <versioning>\n");
258 buf.append(" <snapshot>\n");
259 buf.append(" <buildNumber>").append(buildNumber).append("</buildNumber>\n");
260 buf.append(" <timestamp>").append(timestamp).append("</timestamp>\n");
261 buf.append(" </snapshot>\n");
263 if (hasLastUpdated) {
264 buf.append(" <lastUpdated>").append(lastUpdated).append("</lastUpdated>\n");
266 buf.append(" </versioning>\n");
268 buf.append("</metadata>");
269 return buf.toString();
273 public static class TestWebapplicationContext
274 implements WebApplicationContext
276 private ApplicationContext applicationContext;
278 private ServletContext servletContext;
280 TestWebapplicationContext( ApplicationContext applicationContext, ServletContext servletContext )
282 this.applicationContext = applicationContext;
286 public ServletContext getServletContext()
288 return servletContext;
292 public String getId()
294 return applicationContext.getId();
298 public String getApplicationName()
300 return applicationContext.getApplicationName();
304 public String getDisplayName()
306 return applicationContext.getDisplayName();
310 public long getStartupDate()
312 return applicationContext.getStartupDate();
316 public ApplicationContext getParent()
318 return applicationContext.getParent();
322 public AutowireCapableBeanFactory getAutowireCapableBeanFactory()
323 throws IllegalStateException
325 return applicationContext.getAutowireCapableBeanFactory();
329 public void publishEvent( ApplicationEvent applicationEvent )
331 applicationContext.publishEvent( applicationEvent );
335 public Environment getEnvironment()
337 return applicationContext.getEnvironment();
341 public BeanFactory getParentBeanFactory()
343 return applicationContext.getParentBeanFactory();
347 public boolean containsLocalBean( String s )
349 return applicationContext.containsLocalBean( s );
353 public boolean containsBeanDefinition( String s )
355 return applicationContext.containsBeanDefinition( s );
359 public int getBeanDefinitionCount()
361 return applicationContext.getBeanDefinitionCount();
365 public String[] getBeanDefinitionNames()
367 return applicationContext.getBeanDefinitionNames();
371 public <T> ObjectProvider<T> getBeanProvider( Class<T> aClass, boolean b )
377 public <T> ObjectProvider<T> getBeanProvider( ResolvableType resolvableType, boolean b )
383 public String[] getBeanNamesForType( Class<?> aClass )
385 return applicationContext.getBeanNamesForType( aClass );
389 public String[] getBeanNamesForType( Class<?> aClass, boolean b, boolean b2 )
391 return applicationContext.getBeanNamesForType( aClass, b, b2 );
395 public <T> Map<String, T> getBeansOfType( Class<T> tClass )
396 throws BeansException
398 return applicationContext.getBeansOfType( tClass );
402 public <T> Map<String, T> getBeansOfType( Class<T> tClass, boolean b, boolean b2 )
403 throws BeansException
405 return applicationContext.getBeansOfType( tClass, b, b2 );
409 public String[] getBeanNamesForAnnotation( Class<? extends Annotation> aClass )
411 return applicationContext.getBeanNamesForAnnotation( aClass );
415 public Map<String, Object> getBeansWithAnnotation( Class<? extends Annotation> aClass )
416 throws BeansException
418 return applicationContext.getBeansWithAnnotation( aClass );
422 public <A extends Annotation> A findAnnotationOnBean( String s, Class<A> aClass )
423 throws NoSuchBeanDefinitionException
425 return applicationContext.findAnnotationOnBean( s, aClass );
429 public <T> T getBean( Class<T> aClass, Object... objects )
430 throws BeansException
432 return applicationContext.getBean( aClass, objects );
436 public <T> ObjectProvider<T> getBeanProvider( Class<T> aClass )
442 public <T> ObjectProvider<T> getBeanProvider( ResolvableType resolvableType )
448 public Object getBean( String s )
449 throws BeansException
451 return applicationContext.getBean( s );
455 public <T> T getBean( String s, Class<T> tClass )
456 throws BeansException
458 return applicationContext.getBean( s, tClass );
462 public <T> T getBean( Class<T> tClass )
463 throws BeansException
465 return applicationContext.getBean( tClass );
469 public Object getBean( String s, Object... objects )
470 throws BeansException
472 return applicationContext.getBean( s, objects );
476 public boolean containsBean( String s )
478 return applicationContext.containsBean( s );
482 public boolean isSingleton( String s )
483 throws NoSuchBeanDefinitionException
485 return applicationContext.isSingleton( s );
489 public boolean isPrototype( String s )
490 throws NoSuchBeanDefinitionException
492 return applicationContext.isPrototype( s );
496 public boolean isTypeMatch( String s, Class<?> aClass )
497 throws NoSuchBeanDefinitionException
499 return applicationContext.isTypeMatch( s, aClass );
503 public Class<?> getType( String s )
504 throws NoSuchBeanDefinitionException
506 return applicationContext.getType( s );
510 public Class<?> getType( String s, boolean b ) throws NoSuchBeanDefinitionException
516 public String[] getAliases( String s )
518 return applicationContext.getAliases( s );
522 public String getMessage( String s, Object[] objects, String s2, Locale locale )
524 return applicationContext.getMessage( s, objects, s2, locale );
528 public String getMessage( String s, Object[] objects, Locale locale )
529 throws NoSuchMessageException
531 return applicationContext.getMessage( s, objects, locale );
535 public String getMessage( MessageSourceResolvable messageSourceResolvable, Locale locale )
536 throws NoSuchMessageException
538 return applicationContext.getMessage( messageSourceResolvable, locale );
542 public Resource[] getResources( String s )
545 return applicationContext.getResources( s );
549 public void publishEvent( Object o )
555 public String[] getBeanNamesForType( ResolvableType resolvableType )
557 return new String[0];
561 public String[] getBeanNamesForType( ResolvableType resolvableType, boolean b, boolean b1 )
563 return new String[0];
567 public boolean isTypeMatch( String s, ResolvableType resolvableType )
568 throws NoSuchBeanDefinitionException
574 public Resource getResource( String s )
576 return applicationContext.getResource( s );
580 public ClassLoader getClassLoader()
582 return applicationContext.getClassLoader();
586 protected Servlet findServlet( String name )
589 return unauthenticatedRepositoryServlet;
593 protected String getSpringConfigLocation()
595 return "classpath*:/META-INF/spring-context.xml,classpath*:spring-context.xml";
599 protected static WebClient newClient()
601 final WebClient webClient = new WebClient();
602 webClient.getOptions().setJavaScriptEnabled( false );
603 webClient.getOptions().setCssEnabled( false );
604 webClient.getOptions().setAppletEnabled( false );
605 webClient.getOptions().setThrowExceptionOnFailingStatusCode( false );
606 webClient.setAjaxController( new NicelyResynchronizingAjaxController() );
611 protected WebResponse getWebResponse( String path )
614 return getWebResponse( new GetMethodWebRequest( "http://localhost" + path ) );//, false );
617 protected WebResponse getWebResponse( WebRequest webRequest ) //, boolean followRedirect )
621 MockHttpServletRequest request = new MockHttpServletRequest();
622 request.setRequestURI( webRequest.getUrl().getPath() );
623 request.addHeader( "User-Agent", "Apache Archiva unit test" );
625 request.setMethod( webRequest.getHttpMethod().name() );
627 if ( webRequest.getHttpMethod() == HttpMethod.PUT )
629 PutMethodWebRequest putRequest = PutMethodWebRequest.class.cast( webRequest );
630 request.setContentType( putRequest.contentType );
631 request.setContent( IOUtils.toByteArray( putRequest.inputStream ) );
634 if ( webRequest instanceof MkColMethodWebRequest )
636 request.setMethod( "MKCOL" );
639 final MockHttpServletResponse response = execute( request );
641 if ( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY
642 || response.getStatus() == HttpServletResponse.SC_MOVED_TEMPORARILY )
644 String location = response.getHeader( "Location" );
645 log.debug( "follow redirect to {}", location );
646 return getWebResponse( new GetMethodWebRequest( location ) );
649 return new WebResponse( null, null, 1 )
652 public String getContentAsString()
656 return response.getContentAsString();
658 catch ( UnsupportedEncodingException e )
660 throw new RuntimeException( e.getMessage(), e );
665 public int getStatusCode()
667 return response.getStatus();
671 public String getResponseHeaderValue( String headerName )
673 return response.getHeader( headerName );
678 protected MockHttpServletResponse execute( HttpServletRequest request )
681 MockHttpServletResponse response = new MockHttpServletResponse()
684 public String getContentAsString()
685 throws UnsupportedEncodingException
687 String errorMessage = getErrorMessage();
688 return ( errorMessage != null ) ? errorMessage : super.getContentAsString();
691 this.unauthenticatedRepositoryServlet.service( request, response );
695 public static class GetMethodWebRequest
700 public GetMethodWebRequest( String url )
703 super( new URL( url ) );
709 public static class PutMethodWebRequest
714 InputStream inputStream;
718 public PutMethodWebRequest( String url, InputStream inputStream, String contentType )
721 super( new URL( url ), HttpMethod.PUT );
723 this.inputStream = inputStream;
724 this.contentType = contentType;
730 public static class ServletUnitClient
733 AbstractRepositoryServletTestCase abstractRepositoryServletTestCase;
735 public ServletUnitClient( AbstractRepositoryServletTestCase abstractRepositoryServletTestCase )
737 this.abstractRepositoryServletTestCase = abstractRepositoryServletTestCase;
740 public WebResponse getResponse( WebRequest request )
743 return getResponse( request, false );
746 public WebResponse getResponse( WebRequest request, boolean followRedirect )
749 // alwasy following redirect as it's normal
750 return abstractRepositoryServletTestCase.getWebResponse( request );//, followRedirect );
753 public WebResponse getResource( WebRequest request )
756 return getResponse( request );
760 public ServletUnitClient getServletUnitClient()
762 return new ServletUnitClient( this );
767 public void tearDown()
770 repositoryRegistry.getRepositories().stream().forEach(r -> r.close());
772 if ( Files.exists(repoRootInternal) )
774 org.apache.archiva.common.utils.FileUtils.deleteQuietly( repoRootInternal );
777 if ( Files.exists(repoRootLegacy) )
779 org.apache.archiva.common.utils.FileUtils.deleteQuietly( repoRootLegacy );
782 String appserverBase = System.getProperty( "appserver.base" );
783 if ( StringUtils.isNotEmpty( appserverBase ) )
785 org.apache.archiva.common.utils.FileUtils.deleteQuietly( Paths.get( appserverBase ) );
791 protected void assertFileContents( String expectedContents, Path repoRoot, String subpath )
794 String path = Paths.get(subpath).isAbsolute() ? subpath.substring( 1,subpath.length() ) : subpath;
795 Path actualFile = repoRoot.resolve( path );
796 assertTrue( "File <" + actualFile.toAbsolutePath() + "> should exist.", Files.exists(actualFile) );
797 assertTrue( "File <" + actualFile.toAbsolutePath() + "> should be a file (not a dir/link/device/etc).",
798 Files.isRegularFile( actualFile ) );
800 String actualContents = org.apache.archiva.common.utils.FileUtils.readFileToString( actualFile, Charset.defaultCharset() );
801 assertEquals( "File Contents of <" + actualFile.toAbsolutePath() + ">", expectedContents, actualContents );
804 protected void assertRepositoryValid( RepositoryServlet servlet, String repoId )
807 ManagedRepository repository = servlet.getRepository( repoId );
808 assertNotNull( "Archiva Managed Repository id:<" + repoId + "> should exist.", repository );
809 Path repoRoot = Paths.get( repository.getLocation() );
810 assertTrue( "Archiva Managed Repository id:<" + repoId + "> should have a valid location on disk.",
811 Files.exists(repoRoot) && Files.isDirectory(repoRoot) );
814 protected void assertResponseOK( WebResponse response )
816 assertNotNull( "Should have recieved a response", response );
817 Assert.assertEquals( "Should have been an OK response code", //
818 HttpServletResponse.SC_OK, //
819 response.getStatusCode() );
822 protected void assertResponseOK( WebResponse response, String path )
824 assertNotNull( "Should have recieved a response", response );
825 Assert.assertEquals( "Should have been an OK response code for path: " + path, HttpServletResponse.SC_OK,
826 response.getStatusCode() );
829 protected void assertResponseNotFound( WebResponse response )
831 assertNotNull( "Should have recieved a response", response );
832 Assert.assertEquals( "Should have been an 404/Not Found response code.", HttpServletResponse.SC_NOT_FOUND,
833 response.getStatusCode() );
836 protected void assertResponseInternalServerError( WebResponse response )
838 assertNotNull( "Should have recieved a response", response );
839 Assert.assertEquals( "Should have been an 500/Internal Server Error response code.",
840 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatusCode() );
843 protected void assertResponseConflictError( WebResponse response )
845 assertNotNull( "Should have received a response", response );
846 Assert.assertEquals( "Should have been a 409/Conflict response code.", HttpServletResponse.SC_CONFLICT,
847 response.getStatusCode() );
850 protected ManagedRepositoryConfiguration createManagedRepository( String id, String name, Path location,
851 boolean blockRedeployments )
853 ManagedRepositoryConfiguration repo = new ManagedRepositoryConfiguration();
855 repo.setName( name );
856 repo.setLocation( location.toAbsolutePath().toString() );
857 repo.setBlockRedeployments( blockRedeployments );
858 repo.setType( "MAVEN" );
859 repo.setIndexDir(".indexer");
860 repo.setPackedIndexDir(".index");
865 protected ManagedRepositoryConfiguration createManagedRepository( String id, String name, Path location,
866 String layout, boolean blockRedeployments )
868 ManagedRepositoryConfiguration repo = createManagedRepository( id, name, location, blockRedeployments );
869 repo.setLayout( layout );
873 protected RemoteRepositoryConfiguration createRemoteRepository( String id, String name, String url )
875 RemoteRepositoryConfiguration repo = new RemoteRepositoryConfiguration();
877 repo.setName( name );
882 protected void saveConfiguration( ArchivaConfiguration archivaConfiguration )
885 repositoryRegistry.setArchivaConfiguration(archivaConfiguration);
886 // repositoryRegistry.reload();
887 archivaConfiguration.save( archivaConfiguration.getConfiguration() );
892 protected void setupCleanRepo( Path repoRootDir )
895 org.apache.archiva.common.utils.FileUtils.deleteDirectory( repoRootDir );
896 if ( !Files.exists(repoRootDir) )
898 Files.createDirectories( repoRootDir );
902 protected void assertManagedFileNotExists( Path repoRootInternal, String resourcePath )
904 Path repoFile = repoRootInternal.resolve( resourcePath );
905 assertFalse( "Managed Repository File <" + repoFile.toAbsolutePath() + "> should not exist.",
906 Files.exists(repoFile) );
909 protected void setupCleanInternalRepo()
912 setupCleanRepo( repoRootInternal );
915 protected Path populateRepo( Path repoRootManaged, String path, String contents )
918 Path destFile = repoRootManaged.resolve( path );
919 Files.createDirectories( destFile.getParent() );
920 org.apache.archiva.common.utils.FileUtils.writeStringToFile( destFile, Charset.defaultCharset(), contents );