1 package org.apache.archiva.rest.services;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
22 import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
23 import org.apache.archiva.admin.model.beans.ManagedRepository;
24 import org.apache.archiva.redback.rest.api.services.RedbackServiceException;
25 import org.apache.archiva.redback.rest.services.AbstractRestServicesTest;
26 import org.apache.archiva.rest.api.services.ArchivaAdministrationService;
27 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
28 import org.apache.archiva.rest.api.services.BrowseService;
29 import org.apache.archiva.rest.api.services.CommonServices;
30 import org.apache.archiva.rest.api.services.ManagedRepositoriesService;
31 import org.apache.archiva.rest.api.services.MergeRepositoriesService;
32 import org.apache.archiva.rest.api.services.NetworkProxyService;
33 import org.apache.archiva.rest.api.services.PingService;
34 import org.apache.archiva.rest.api.services.PluginsService;
35 import org.apache.archiva.rest.api.services.ProxyConnectorRuleService;
36 import org.apache.archiva.rest.api.services.ProxyConnectorService;
37 import org.apache.archiva.rest.api.services.RedbackRuntimeConfigurationService;
38 import org.apache.archiva.rest.api.services.RemoteRepositoriesService;
39 import org.apache.archiva.rest.api.services.RepositoriesService;
40 import org.apache.archiva.rest.api.services.RepositoryGroupService;
41 import org.apache.archiva.rest.api.services.SearchService;
42 import org.apache.archiva.security.common.ArchivaRoleConstants;
43 import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
44 import org.apache.commons.io.FileUtils;
45 import org.apache.commons.lang.StringUtils;
46 import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
47 import org.apache.cxf.jaxrs.client.WebClient;
48 import org.junit.After;
49 import org.junit.Assume;
50 import org.junit.Before;
51 import org.junit.BeforeClass;
52 import org.junit.runner.RunWith;
53 import org.slf4j.LoggerFactory;
55 import javax.ws.rs.core.MediaType;
56 import java.io.IOException;
57 import java.nio.file.Files;
58 import java.nio.file.Path;
59 import java.nio.file.Paths;
60 import java.time.LocalTime;
61 import java.util.Collections;
62 import java.util.Date;
63 import java.util.Locale;
64 import java.util.concurrent.atomic.AtomicReference;
65 import java.util.function.Function;
68 * @author Olivier Lamy
70 @RunWith(ArchivaBlockJUnit4ClassRunner.class)
71 public abstract class AbstractArchivaRestTest
72 extends AbstractRestServicesTest
74 private AtomicReference<Path> projectDir = new AtomicReference<>();
75 private AtomicReference<Path> appServerBase = new AtomicReference<>( );
76 private AtomicReference<Path> basePath = new AtomicReference<>( );
78 private boolean reuseServer = true;
81 protected void setReuseServer(boolean value) {
82 this.reuseServer = value;
85 protected boolean isReuseServer() {
86 return this.reuseServer;
90 * Used by tryAssert to allow to throw exceptions in the lambda expression.
93 protected interface AssertFunction
95 void accept( ) throws Exception;
98 protected void tryAssert( AssertFunction func ) throws Exception
100 tryAssert( func, 10, 500 );
104 * Runs the assert method until the assert is successful or the number of retries
105 * is reached. This is needed because the JCR Oak index update is asynchronous, so updates
106 * may not be visible immediately after the modification.
108 private void tryAssert( AssertFunction func, int retries, int sleepMillis ) throws Exception
112 while ( retry-- > 0 )
119 catch ( Exception | AssertionError e )
122 Thread.currentThread( ).sleep( sleepMillis );
123 log.warn( "Retrying assert {}: {}", retry, e.getMessage( ) );
126 log.warn( "Retries: {}, Exception: {}", retry, t.getMessage( ) );
127 if ( retry <= 0 && t != null )
129 if ( t instanceof RuntimeException )
131 throw (RuntimeException) t;
133 else if ( t instanceof Exception )
137 else if ( t instanceof Error )
144 // START SNIPPET: authz-header
145 // guest with an empty password
146 public static String guestAuthzHeader =
147 "Basic " + org.apache.cxf.common.util.Base64Utility.encode( ( "guest" + ":" ).getBytes() );
149 // with an other login/password
150 //public String authzHeader =
151 // "Basic " + org.apache.cxf.common.util.Base64Utility.encode( ( "login" + ":password" ).getBytes() );
153 // END SNIPPET: authz-header
155 Path getAppserverBase() {
156 if (appServerBase.get()==null) {
157 String basePath = System.getProperty( "appserver.base" );
158 final Path appserverPath;
159 if (StringUtils.isNotEmpty( basePath )) {
160 appserverPath = Paths.get( basePath ).toAbsolutePath( );
162 appserverPath = getBasedir( ).resolve( "target" ).resolve( "appserver-base-" + LocalTime.now( ).toSecondOfDay( ) );
164 appServerBase.compareAndSet( null, appserverPath );
166 return appServerBase.get();
170 public static void checkRepo()
172 Assume.assumeFalse("Test is ignored, because path to appserver contains whitespace characters!", System.getProperty( "appserver.base" ).contains( " " ) );
173 // skygo: was not possible to fix path in this particular module
174 // Skip test if not in proper folder , otherwise test are not fair coz repository
175 // cannot have space in their name.
180 public void startServer()
183 if ( (!isReuseServer()) || (isReuseServer() && !isServerRunning())) {
184 log.info("Starting new server reuse={}, running={}, instance={}, server={}", isReuseServer(), isServerRunning(), this.hashCode(), getServer()==null ? "" : getServer().hashCode());
185 Path appServerBase = getAppserverBase( );
187 removeAppsubFolder(appServerBase, "jcr");
188 removeAppsubFolder(appServerBase, "conf");
189 removeAppsubFolder(appServerBase, "data");
192 log.info("Reusing running server instance reuse={}, running={}", isReuseServer(), isServerRunning());
198 public void stopServer()
201 if ( !isReuseServer() )
203 log.info("Stopping server reuse={}, running={}, instance={}, server={}", isReuseServer(), isServerRunning(), this.hashCode(), getServer()==null ? "" : getServer().hashCode());
206 log.info("Server not stopping reuse={}, running={}", isReuseServer(), isServerRunning());
211 private void removeAppsubFolder( Path appServerBase, String folder )
214 Path directory = appServerBase.resolve( folder );
215 if ( Files.exists(directory) )
217 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
222 protected String getSpringConfigLocation()
224 return "classpath*:META-INF/spring-context.xml,classpath:META-INF/spring-context-test.xml";
228 protected String getRestServicesPath()
230 return "restServices";
233 protected RepositoriesService getRepositoriesService()
235 return getRepositoriesService( null );
238 protected <T> T getService( Class<T> clazz, String authzHeader )
240 T service = JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/", clazz,
241 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
243 if ( authzHeader != null )
245 WebClient.client( service ).header( "Authorization", authzHeader );
247 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
248 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 100000000 );
249 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
250 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
254 protected ProxyConnectorRuleService getProxyConnectorRuleService( String authzHeader )
256 return getService( ProxyConnectorRuleService.class, authzHeader );
259 protected MergeRepositoriesService getMergeRepositoriesService( String authzHeader )
261 return getService( MergeRepositoriesService.class, authzHeader );
264 protected RepositoriesService getRepositoriesService( String authzHeader )
266 return getService( RepositoriesService.class, authzHeader );
270 protected ManagedRepositoriesService getManagedRepositoriesService( String authzHeader )
272 return getService( ManagedRepositoriesService.class, authzHeader );
275 protected PingService getPingService()
277 return getService( PingService.class, null );
280 protected PluginsService getPluginsService()
282 PluginsService service = getService( PluginsService.class, null );
283 WebClient.client( service ).accept( MediaType.TEXT_PLAIN );
284 WebClient.client( service ).type( MediaType.TEXT_PLAIN );
288 protected RemoteRepositoriesService getRemoteRepositoriesService()
290 return getService( RemoteRepositoriesService.class, null );
295 protected RepositoryGroupService getRepositoryGroupService()
297 return JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
298 RepositoryGroupService.class,
299 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
302 protected ProxyConnectorService getProxyConnectorService()
304 ProxyConnectorService service =
305 JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
306 ProxyConnectorService.class,
307 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
309 WebClient.client( service ).header( "Authorization", authorizationHeader );
310 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
311 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000 );
312 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
313 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
317 protected NetworkProxyService getNetworkProxyService()
319 NetworkProxyService service =
320 JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
321 NetworkProxyService.class,
322 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
324 WebClient.client( service ).header( "Authorization", authorizationHeader );
325 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
326 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000 );
327 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
328 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
332 protected ArchivaAdministrationService getArchivaAdministrationService()
334 ArchivaAdministrationService service =
335 JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
336 ArchivaAdministrationService.class,
337 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
339 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
340 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
342 WebClient.client( service ).header( "Authorization", authorizationHeader );
343 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
345 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000 );
349 protected RedbackRuntimeConfigurationService getRedbackRuntimeConfigurationService()
351 RedbackRuntimeConfigurationService service =
352 JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
353 RedbackRuntimeConfigurationService.class,
354 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
356 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
357 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
359 WebClient.client( service ).header( "Authorization", authorizationHeader );
360 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
361 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000 );
365 protected BrowseService getBrowseService( String authzHeader, boolean useXml )
367 // START SNIPPET: cxf-browseservice-creation
368 BrowseService service =
369 JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
371 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
372 // to add authentification
373 if ( authzHeader != null )
375 WebClient.client( service ).header( "Authorization", authzHeader );
377 // Set the Referer header to your archiva server url
378 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
380 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 100000000 );
383 WebClient.client( service ).accept( MediaType.APPLICATION_XML_TYPE );
384 WebClient.client( service ).type( MediaType.APPLICATION_XML_TYPE );
388 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
389 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
392 // END SNIPPET: cxf-browseservice-creation
396 protected SearchService getSearchService( String authzHeader )
398 // START SNIPPET: cxf-searchservice-creation
399 SearchService service =
400 JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
402 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
403 // to add authentification
404 if ( authzHeader != null )
406 WebClient.client( service ).header( "Authorization", authzHeader );
408 // Set the Referer header to your archiva server url
409 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
410 // to configure read timeout
411 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 100000000 );
412 // if you want to use json as exchange format xml is supported too
413 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
414 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
416 // END SNIPPET: cxf-searchservice-creation
420 protected CommonServices getCommonServices( String authzHeader )
422 CommonServices service =
423 JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
424 CommonServices.class,
425 Collections.singletonList( new JacksonJaxbJsonProvider() ) );
427 if ( authzHeader != null )
429 WebClient.client( service ).header( "Authorization", authzHeader );
431 WebClient.client(service).header("Referer","http://localhost:"+getServerPort());
432 WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 100000000 );
433 WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE );
434 WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE );
438 protected ManagedRepository getTestManagedRepository()
440 String location = getAppserverBase().resolve( "data/repositories/test-repo" ).toAbsolutePath().toString();
441 return new ManagedRepository( Locale.getDefault(), "TEST", "test", location, "default", true, true, false, "2 * * * * ?", null,
442 false, 2, 3, true, false, "my nice repo", false );
446 protected String getBaseUrl()
448 String baseUrlSysProps = System.getProperty( "archiva.baseRestUrl" );
449 return StringUtils.isBlank( baseUrlSysProps ) ? "http://localhost:" + getServerPort() : baseUrlSysProps;
452 protected Path getProjectDirectory() {
453 if ( projectDir.get()==null) {
454 String propVal = System.getProperty("mvn.project.base.dir");
456 if (StringUtils.isEmpty(propVal)) {
457 newVal = Paths.get("").toAbsolutePath();
459 newVal = Paths.get(propVal).toAbsolutePath();
461 projectDir.compareAndSet(null, newVal);
463 return projectDir.get();
466 //-----------------------------------------------------
467 // utilities to create repos for testing
468 //-----------------------------------------------------
470 static final String TARGET_REPO_ID = "test-copy-target";
472 static final String SOURCE_REPO_ID = "test-origin-repo";
474 protected void initSourceTargetRepo()
477 Path targetRepo = getAppserverBase().resolve("data/repositories/test-repo-copy" );
478 if ( Files.exists(targetRepo) )
480 org.apache.archiva.common.utils.FileUtils.deleteDirectory( targetRepo );
482 assertFalse( Files.exists(targetRepo) );
483 Files.createDirectories( targetRepo );
485 if ( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( TARGET_REPO_ID ) != null )
487 getManagedRepositoriesService( authorizationHeader ).deleteManagedRepository( TARGET_REPO_ID, true );
488 assertNull( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( TARGET_REPO_ID ) );
490 ManagedRepository managedRepository = getTestManagedRepository();
491 managedRepository.setId( TARGET_REPO_ID );
492 managedRepository.setLocation( targetRepo.toAbsolutePath().toString() );
493 managedRepository.setCronExpression( "* * * * * ?" );
494 getManagedRepositoriesService( authorizationHeader ).addManagedRepository( managedRepository );
495 assertNotNull( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( TARGET_REPO_ID ) );
497 Path originRepo = getAppserverBase().resolve( "data/repositories/test-origin-repo" );
498 if ( Files.exists(originRepo) )
500 org.apache.archiva.common.utils.FileUtils.deleteDirectory( originRepo );
502 assertFalse( Files.exists(originRepo) );
503 FileUtils.copyDirectory( getProjectDirectory().resolve("src/test/repo-with-osgi" ).toAbsolutePath().toFile(), originRepo.toAbsolutePath().toFile() );
505 if ( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( SOURCE_REPO_ID ) != null )
507 getManagedRepositoriesService( authorizationHeader ).deleteManagedRepository( SOURCE_REPO_ID, true );
508 assertNull( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( SOURCE_REPO_ID ) );
511 managedRepository = getTestManagedRepository();
512 managedRepository.setId( SOURCE_REPO_ID );
513 managedRepository.setLocation( originRepo.toAbsolutePath().toString() );
515 getManagedRepositoriesService( authorizationHeader ).addManagedRepository( managedRepository );
516 assertNotNull( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( SOURCE_REPO_ID ) );
518 getArchivaAdministrationService().enabledKnownContentConsumer( "create-missing-checksums" );
519 getArchivaAdministrationService().enabledKnownContentConsumer( "metadata-updater" );
523 protected void cleanRepos()
527 if ( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( TARGET_REPO_ID ) != null )
531 getManagedRepositoriesService( authorizationHeader ).deleteManagedRepository( TARGET_REPO_ID, true );
533 getManagedRepositoriesService( authorizationHeader ).getManagedRepository( TARGET_REPO_ID ) );
535 catch ( Exception e )
537 log.warn( "skip issue while cleaning test repository: this can cause test failure", e );
540 if ( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( SOURCE_REPO_ID ) != null )
544 getManagedRepositoriesService( authorizationHeader ).deleteManagedRepository( SOURCE_REPO_ID, true );
546 getManagedRepositoriesService( authorizationHeader ).getManagedRepository( SOURCE_REPO_ID ) );
548 catch ( Exception e )
550 log.warn( "skip issue while cleaning test repository: this can cause test failure", e );
556 protected void createAndIndexRepo( String testRepoId, Path srcRepoPath, boolean stageNeeded )
557 throws ArchivaRestServiceException, IOException, RedbackServiceException
559 if ( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( testRepoId ) != null )
561 getManagedRepositoriesService( authorizationHeader ).deleteManagedRepository( testRepoId, false );
564 ManagedRepository managedRepository = new ManagedRepository(Locale.getDefault());
565 managedRepository.setId( testRepoId );
566 managedRepository.setName( "test repo" );
568 Path badContent = srcRepoPath.resolve( "target" );
569 if ( Files.exists(badContent) )
571 org.apache.archiva.common.utils.FileUtils.deleteDirectory( badContent );
574 Path repoPath = getAppserverBase().resolve( "data" ).resolve( "repositories" ).resolve( testRepoId);
576 FileUtils.deleteQuietly(repoPath.toFile());
577 FileUtils.copyDirectory(srcRepoPath.toFile(), repoPath.toFile());
579 managedRepository.setLocation( repoPath.toAbsolutePath().toString() );
580 String suffix = Long.toString( new Date().getTime() );
581 Path baseDir = Files.createTempDirectory( "archiva-test-index" ).toAbsolutePath();
582 managedRepository.setIndexDirectory(
583 baseDir.resolve( ".indexer-" + suffix ).toString());
584 managedRepository.setPackedIndexDirectory(baseDir.resolve(".index-" + suffix).toString());
586 managedRepository.setStageRepoNeeded( stageNeeded );
587 managedRepository.setSnapshots( true );
589 //managedRepository.setScanned( scanned );
591 ManagedRepositoriesService service = getManagedRepositoriesService( authorizationHeader );
592 service.addManagedRepository( managedRepository );
594 getRoleManagementService( authorizationHeader ).assignTemplatedRole(
595 ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, testRepoId, "admin" );
597 getRoleManagementService( authorizationHeader ).assignTemplatedRole(
598 ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, testRepoId, "guest" );
601 protected void scanRepo( String testRepoId )
602 throws ArchivaRestServiceException
604 getRepositoriesService( authorizationHeader ).scanRepositoryNow( testRepoId, true );
607 protected void createAndIndexRepo( String testRepoId, Path srcRepoPath )
610 createAndIndexRepo( testRepoId, srcRepoPath, false );
611 scanRepo( testRepoId );
614 protected void createStagedNeededRepo( String testRepoId, Path srcRepoPath, boolean scan )
617 createAndIndexRepo( testRepoId, srcRepoPath, true );
620 scanRepo( testRepoId );
623 RepositoriesService repositoriesService = getRepositoriesService( authorizationHeader );
624 repositoriesService.scanRepositoryDirectoriesNow( testRepoId );
627 repositoriesService.scanRepositoryNow( testRepoId + "-stage", true );
628 repositoriesService.scanRepositoryDirectoriesNow( testRepoId + "-stage" );
633 protected void deleteTestRepo( String id )
636 if ( getManagedRepositoriesService( authorizationHeader ).getManagedRepository( id ) != null )
638 getManagedRepositoriesService( authorizationHeader ).deleteManagedRepository( id, false );
642 public Path getBasedir()
644 if (basePath.get()==null) {
645 String baseDir = System.getProperty( "basedir" );
646 final Path baseDirPath;
647 if (StringUtils.isNotEmpty( baseDir )) {
648 baseDirPath = Paths.get( baseDir );
650 baseDirPath = getProjectDirectory( );
652 basePath.compareAndSet( null, baseDirPath );
654 return basePath.get( );
657 protected void waitForScanToComplete( String repoId )
658 throws ArchivaRestServiceException, InterruptedException
660 while ( getRepositoriesService( authorizationHeader ).alreadyScanning( repoId ) ) {
661 // Would be better to cancel, if we had that capacity