/** * Copyright (c) 2008-2011 Sonatype, Inc. * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions. * * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General * Public License Version 3 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License Version 3 * for more details. * * You should have received a copy of the GNU Affero General Public License Version 3 along with this program. If not, see * http://www.gnu.org/licenses. * * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation. * All other trademarks are the property of their respective owners. */ package org.sonatype.nexus.proxy.mapping; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.makeThreadSafe; import static org.easymock.EasyMock.replay; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.sonatype.nexus.configuration.model.CLocalStorage; import org.sonatype.nexus.configuration.model.CRepository; import org.sonatype.nexus.configuration.model.DefaultCRepository; import org.sonatype.nexus.proxy.AbstractNexusTestEnvironment; import org.sonatype.nexus.proxy.ResourceStoreRequest; import org.sonatype.nexus.proxy.mapping.RepositoryPathMapping.MappingType; import org.sonatype.nexus.proxy.maven.maven2.M2GroupRepository; import org.sonatype.nexus.proxy.maven.maven2.M2GroupRepositoryConfiguration; import org.sonatype.nexus.proxy.maven.maven2.Maven2ContentClass; import org.sonatype.nexus.proxy.registry.RepositoryRegistry; import org.sonatype.nexus.proxy.repository.DefaultRepositoryKind; import org.sonatype.nexus.proxy.repository.GroupRepository; import org.sonatype.nexus.proxy.repository.HostedRepository; import org.sonatype.nexus.proxy.repository.ProxyRepository; import org.sonatype.nexus.proxy.repository.Repository; public class PathBasedRequestRepositoryMapperTest extends AbstractNexusTestEnvironment { private RepositoryRegistry registry; private Repository repoA; private Repository repoB; private Repository repoC; private Repository repoD; private Repository repoE; private Repository repoF; private GroupRepository groupRepo; private RequestRepositoryMapper requestRepositoryMapper; protected RequestRepositoryMapper prepare( Map<String, String[]> inclusions, Map<String, String[]> exclusions, Map<String, String[]> blockings ) throws Exception { requestRepositoryMapper = lookup( RequestRepositoryMapper.class ); // clear it for ( String id : requestRepositoryMapper.getMappings().keySet() ) { requestRepositoryMapper.removeMapping( id ); } requestRepositoryMapper.commitChanges(); registry = lookup( RepositoryRegistry.class ); // clean this up? repoA = createMock( Repository.class ); makeThreadSafe( repoA, true ); expect( repoA.getId() ).andReturn( "repoA" ).anyTimes(); expect( repoA.getProviderRole() ).andReturn( Repository.class.getName() ).anyTimes(); expect( repoA.getProviderHint() ).andReturn( "maven2" ).anyTimes(); expect( repoA.isUserManaged() ).andReturn( true ).anyTimes(); expect( repoA.adaptToFacet( ProxyRepository.class ) ).andReturn( null ).anyTimes(); repoB = createMock( Repository.class ); makeThreadSafe( repoB, true ); expect( repoB.getId() ).andReturn( "repoB" ).anyTimes(); expect( repoB.getProviderRole() ).andReturn( Repository.class.getName() ).anyTimes(); expect( repoB.getProviderHint() ).andReturn( "maven2" ).anyTimes(); expect( repoB.isUserManaged() ).andReturn( true ).anyTimes(); expect( repoB.adaptToFacet( ProxyRepository.class ) ).andReturn( null ).anyTimes(); repoC = createMock( Repository.class ); makeThreadSafe( repoC, true ); expect( repoC.getId() ).andReturn( "repoC" ).anyTimes(); expect( repoC.getProviderRole() ).andReturn( Repository.class.getName() ).anyTimes(); expect( repoC.getProviderHint() ).andReturn( "maven2" ).anyTimes(); expect( repoC.isUserManaged() ).andReturn( true ).anyTimes(); expect( repoC.adaptToFacet( ProxyRepository.class ) ).andReturn( null ).anyTimes(); repoD = createMock( Repository.class ); makeThreadSafe( repoD, true ); expect( repoD.getId() ).andReturn( "repoD" ).anyTimes(); expect( repoD.getProviderRole() ).andReturn( Repository.class.getName() ).anyTimes(); expect( repoD.getProviderHint() ).andReturn( "maven2" ).anyTimes(); expect( repoD.isUserManaged() ).andReturn( true ).anyTimes(); expect( repoD.adaptToFacet( ProxyRepository.class ) ).andReturn( null ).anyTimes(); repoE = createMock( Repository.class ); makeThreadSafe( repoE, true ); expect( repoE.getId() ).andReturn( "repoE" ).anyTimes(); expect( repoE.getProviderRole() ).andReturn( Repository.class.getName() ).anyTimes(); expect( repoE.getProviderHint() ).andReturn( "maven2" ).anyTimes(); expect( repoE.isUserManaged() ).andReturn( true ).anyTimes(); expect( repoE.adaptToFacet( ProxyRepository.class ) ).andReturn( null ).anyTimes(); repoF = createMock( Repository.class ); makeThreadSafe( repoF, true ); expect( repoF.getId() ).andReturn( "repoF" ).anyTimes(); expect( repoF.getProviderRole() ).andReturn( Repository.class.getName() ).anyTimes(); expect( repoF.getProviderHint() ).andReturn( "maven2" ).anyTimes(); expect( repoF.isUserManaged() ).andReturn( true ).anyTimes(); expect( repoF.adaptToFacet( ProxyRepository.class ) ).andReturn( null ).anyTimes(); expect( repoA.getRepositoryContentClass() ).andReturn( new Maven2ContentClass() ).anyTimes(); expect( repoB.getRepositoryContentClass() ).andReturn( new Maven2ContentClass() ).anyTimes(); expect( repoC.getRepositoryContentClass() ).andReturn( new Maven2ContentClass() ).anyTimes(); expect( repoD.getRepositoryContentClass() ).andReturn( new Maven2ContentClass() ).anyTimes(); expect( repoE.getRepositoryContentClass() ).andReturn( new Maven2ContentClass() ).anyTimes(); expect( repoF.getRepositoryContentClass() ).andReturn( new Maven2ContentClass() ).anyTimes(); expect( repoA.getRepositoryKind() ).andReturn( new DefaultRepositoryKind( HostedRepository.class, null ) ) .anyTimes(); expect( repoB.getRepositoryKind() ).andReturn( new DefaultRepositoryKind( HostedRepository.class, null ) ) .anyTimes(); expect( repoC.getRepositoryKind() ).andReturn( new DefaultRepositoryKind( HostedRepository.class, null ) ) .anyTimes(); expect( repoD.getRepositoryKind() ).andReturn( new DefaultRepositoryKind( HostedRepository.class, null ) ) .anyTimes(); expect( repoE.getRepositoryKind() ).andReturn( new DefaultRepositoryKind( HostedRepository.class, null ) ) .anyTimes(); expect( repoF.getRepositoryKind() ).andReturn( new DefaultRepositoryKind( HostedRepository.class, null ) ) .anyTimes(); replay( repoA, repoB, repoC, repoD, repoE, repoF ); registry.addRepository( repoA ); registry.addRepository( repoB ); registry.addRepository( repoC ); registry.addRepository( repoD ); registry.addRepository( repoE ); registry.addRepository( repoF ); ArrayList<String> testgroup = new ArrayList<String>(); testgroup.add( repoA.getId() ); testgroup.add( repoB.getId() ); testgroup.add( repoC.getId() ); testgroup.add( repoD.getId() ); testgroup.add( repoE.getId() ); testgroup.add( repoF.getId() ); groupRepo = (M2GroupRepository) getContainer().lookup( GroupRepository.class, "maven2" ); CRepository repoGroupConf = new DefaultCRepository(); repoGroupConf.setProviderRole( GroupRepository.class.getName() ); repoGroupConf.setProviderHint( "maven2" ); repoGroupConf.setId( "test" ); repoGroupConf.setLocalStorage( new CLocalStorage() ); repoGroupConf.getLocalStorage().setProvider( "file" ); Xpp3Dom exGroupRepo = new Xpp3Dom( "externalConfiguration" ); repoGroupConf.setExternalConfiguration( exGroupRepo ); M2GroupRepositoryConfiguration exGroupRepoConf = new M2GroupRepositoryConfiguration( exGroupRepo ); exGroupRepoConf.setMemberRepositoryIds( testgroup ); exGroupRepoConf.setMergeMetadata( true ); groupRepo.configure( repoGroupConf ); registry.addRepository( groupRepo ); if ( inclusions != null ) { for ( String key : inclusions.keySet() ) { RepositoryPathMapping item = new RepositoryPathMapping( "I" + key, MappingType.INCLUSION, "*", Arrays .asList( new String[] { key } ), Arrays.asList( inclusions.get( key ) ) ); requestRepositoryMapper.addMapping( item ); } } if ( exclusions != null ) { for ( String key : exclusions.keySet() ) { RepositoryPathMapping item = new RepositoryPathMapping( "E" + key, MappingType.EXCLUSION, "*", Arrays .asList( new String[] { key } ), Arrays.asList( exclusions.get( key ) ) ); requestRepositoryMapper.addMapping( item ); } } if ( blockings != null ) { for ( String key : blockings.keySet() ) { RepositoryPathMapping item = new RepositoryPathMapping( "B" + key, MappingType.BLOCKING, "*", Arrays .asList( new String[] { key } ), Arrays.asList( blockings.get( key ) ) ); requestRepositoryMapper.addMapping( item ); } } requestRepositoryMapper.commitChanges(); return requestRepositoryMapper; } public void testInclusionAndExclusion() throws Exception { HashMap<String, String[]> inclusions = new HashMap<String, String[]>(); inclusions.put( "/a/b/.*", new String[] { "repoA", "repoB" } ); inclusions.put( "/c/d/.*", new String[] { "repoC", "repoD" } ); inclusions.put( "/all/.*", new String[] { "*" } ); HashMap<String, String[]> exclusions = new HashMap<String, String[]>(); exclusions.put( "/e/f/.*", new String[] { "*" } ); RequestRepositoryMapper pm = prepare( inclusions, exclusions, null ); // using group to guarantee proper ordering List<Repository> resolvedRepositories = new ArrayList<Repository>(); resolvedRepositories.addAll( registry.getRepositoryWithFacet( "test", GroupRepository.class ) .getMemberRepositories() ); List<Repository> mappedRepositories; ResourceStoreRequest request; request = new ResourceStoreRequest( "/a/b/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 2, mappedRepositories.size() ); assertTrue( mappedRepositories.get( 0 ).equals( repoA ) ); assertTrue( mappedRepositories.get( 1 ).equals( repoB ) ); request = new ResourceStoreRequest( "/e/f/should/not/return/any/repo", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 0, mappedRepositories.size() ); request = new ResourceStoreRequest( "/all/should/be/servicing", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); } public void testInclusionAndExclusionKeepsGroupOrdering() throws Exception { HashMap<String, String[]> inclusions = new HashMap<String, String[]>(); inclusions.put( "/a/b/.*", new String[] { "repoB", "repoA" } ); inclusions.put( "/c/d/.*", new String[] { "repoD", "repoC" } ); inclusions.put( "/all/.*", new String[] { "*" } ); HashMap<String, String[]> exclusions = new HashMap<String, String[]>(); exclusions.put( "/e/f/.*", new String[] { "repoE", "repoF" } ); exclusions.put( "/e/f/all/.*", new String[] { "*" } ); RequestRepositoryMapper pm = prepare( inclusions, exclusions, null ); // using group to guarantee proper ordering List<Repository> resolvedRepositories = new ArrayList<Repository>(); resolvedRepositories.addAll( registry.getRepositoryWithFacet( "test", GroupRepository.class ) .getMemberRepositories() ); List<Repository> mappedRepositories; ResourceStoreRequest request; // /a/b inclusion hit, needed order: A, B request = new ResourceStoreRequest( "/a/b/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 2, mappedRepositories.size() ); assertTrue( mappedRepositories.get( 0 ).equals( repoA ) ); assertTrue( mappedRepositories.get( 1 ).equals( repoB ) ); // /e/f exclusion hit, needed order: A, B, C, D request = new ResourceStoreRequest( "/e/f/should/not/return/any/repo", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 4, mappedRepositories.size() ); assertTrue( mappedRepositories.get( 0 ).equals( repoA ) ); assertTrue( mappedRepositories.get( 1 ).equals( repoB ) ); assertTrue( mappedRepositories.get( 2 ).equals( repoC ) ); assertTrue( mappedRepositories.get( 3 ).equals( repoD ) ); request = new ResourceStoreRequest( "/all/should/be/servicing", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); } /** * Empty rules are invalid, they are spitted out by validator anyway. This test is bad, and hence is turned off, but * it is left here for reference. (added 'dont' at the start) * * @throws Exception */ public void dontTestEmptyRules() throws Exception { HashMap<String, String[]> inclusions = new HashMap<String, String[]>(); inclusions.put( "/empty/1/.*", new String[] { "" } ); inclusions.put( "/empty/2/.*", new String[] { null } ); inclusions.put( "/empty/5/.*", new String[] { null } ); HashMap<String, String[]> exclusions = new HashMap<String, String[]>(); exclusions.put( "/empty/5/.*", new String[] { "" } ); exclusions.put( "/empty/6/.*", new String[] { "" } ); exclusions.put( "/empty/7/.*", new String[] { null } ); RequestRepositoryMapper pm = prepare( inclusions, exclusions, null ); // using group to guarantee proper ordering List<Repository> resolvedRepositories = new ArrayList<Repository>(); resolvedRepositories.addAll( registry.getRepositoryWithFacet( "test", GroupRepository.class ) .getMemberRepositories() ); List<Repository> mappedRepositories; ResourceStoreRequest request; // empty inclusion, it should don't be acted upon request = new ResourceStoreRequest( "/empty/1/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); // null inclusion, it should don't be acted upon request = new ResourceStoreRequest( "/empty/2/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); request = new ResourceStoreRequest( "/empty/5/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); request = new ResourceStoreRequest( "/empty/5/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); request = new ResourceStoreRequest( "/empty/5/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); } public void testBlockingRules() throws Exception { HashMap<String, String[]> blockings = new HashMap<String, String[]>(); blockings.put( "/blocked/1/.*", new String[] { "" } ); RequestRepositoryMapper pm = prepare( null, null, blockings ); // using group to guarantee proper ordering List<Repository> resolvedRepositories = new ArrayList<Repository>(); resolvedRepositories.addAll( registry.getRepositoryWithFacet( "test", GroupRepository.class ) .getMemberRepositories() ); List<Repository> mappedRepositories; ResourceStoreRequest request; // empty inclusion, it should don't be acted upon request = new ResourceStoreRequest( "/blocked/1/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 0, mappedRepositories.size() ); // null inclusion, it should don't be acted upon request = new ResourceStoreRequest( "/dummy/2/something", true ); mappedRepositories = pm.getMappedRepositories( groupRepo, request, resolvedRepositories ); assertEquals( 6, mappedRepositories.size() ); } }