package org.apache.maven.index.updater; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import org.apache.lucene.index.Term; import org.apache.lucene.search.TermQuery; import org.apache.maven.index.ArtifactInfo; import org.apache.maven.index.FlatSearchRequest; import org.apache.maven.index.FlatSearchResponse; import org.apache.maven.index.context.IndexingContext; import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException; import org.apache.maven.index.fs.Locker; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.IOUtil; public class LocalIndexCacheTest extends AbstractIndexUpdaterTest { private File remoteRepo; private File localCacheDir; private File indexDir; private IndexingContext tempContext; @Override protected void setUp() throws Exception { super.setUp(); remoteRepo = new File( "target/localcache/remoterepo" ).getCanonicalFile(); FileUtils.deleteDirectory( remoteRepo ); remoteRepo.mkdirs(); localCacheDir = new File( "target/localcache/cache" ).getCanonicalFile(); FileUtils.deleteDirectory( localCacheDir ); localCacheDir.mkdirs(); indexDir = new File( "target/localcache/index" ).getCanonicalFile(); FileUtils.deleteDirectory( indexDir ); indexDir.mkdirs(); } @Override protected void tearDown() throws Exception { removeTempContext(); super.tearDown(); } private IndexingContext getNewTempContext() throws IOException, UnsupportedExistingLuceneIndexException { removeTempContext(); tempContext = indexer.addIndexingContext( repositoryId + "temp", repositoryId, repoDir, indexDir, repositoryUrl, null, MIN_CREATORS ); return tempContext; } private void removeTempContext() throws IOException { if ( tempContext != null ) { indexer.removeIndexingContext( tempContext, true ); tempContext = null; FileUtils.cleanDirectory( indexDir ); } } public void testBasic() throws Exception { // create initial remote repo index indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); packIndex( remoteRepo, context ); // TrackingFetcher fetcher; IndexUpdateRequest updateRequest; IndexingContext testContext; // initial index download (expected: full index download) testContext = getNewTempContext(); fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); assertEquals( 2, fetcher.getRetrievedResources().size() ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() ); assertGroupCount( 1, "commons-lang", testContext ); // update the same index (expected: no index download) fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); assertEquals( 1, fetcher.getRetrievedResources().size() ); assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) ); assertGroupCount( 1, "commons-lang", testContext ); // nuke index but keep the cache (expected: no index download) testContext = getNewTempContext(); fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); assertEquals( 1, fetcher.getRetrievedResources().size() ); assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) ); assertGroupCount( 1, "commons-lang", testContext ); // incremental remote update indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ), context ); packIndex( remoteRepo, context ); // update via cache (expected: incremental chunk download) fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); assertEquals( 2, fetcher.getRetrievedResources().size() ); assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) ); assertEquals( "nexus-maven-repository-index.1.gz", fetcher.getRetrievedResources().get( 1 ) ); assertGroupCount( 2, "commons-lang", testContext ); // nuke index but keep the cache (expected: no index download, index contains both initial and delta chunks) testContext = getNewTempContext(); fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); assertEquals( 1, fetcher.getRetrievedResources().size() ); assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) ); assertGroupCount( 2, "commons-lang", testContext ); // kill the cache, but keep the index (expected: full index download) // TODO how to assert if merge==false internally? FileUtils.deleteDirectory( localCacheDir ); fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); assertEquals( 2, fetcher.getRetrievedResources().size() ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() ); assertGroupCount( 2, "commons-lang", testContext ); } private void assertGroupCount( int expectedCount, String groupId, IndexingContext context ) throws IOException { TermQuery query = new TermQuery( new Term( ArtifactInfo.GROUP_ID, groupId ) ); FlatSearchResponse response = indexer.searchFlat( new FlatSearchRequest( query, context ) ); assertEquals( expectedCount, response.getTotalHits() ); } public void testForceIndexDownload() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); packIndex( remoteRepo, context ); // TrackingFetcher fetcher; IndexUpdateRequest updateRequest; // initial index download (expected: no index download) fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); // corrupt local cache IOUtil.copy( "corrupted", new FileOutputStream( new File( localCacheDir, "nexus-maven-repository-index.gz" ) ) ); // try download again (it would have failed if force did not update local cache) removeTempContext(); fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updateRequest.setForceFullUpdate( true ); updater.fetchAndUpdateIndex( updateRequest ); } public void testInitialForcedFullDownload() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); packIndex( remoteRepo, context ); // TrackingFetcher fetcher; IndexUpdateRequest updateRequest; // initial forced full index download (expected: successfull download) fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updateRequest.setForceFullUpdate( true ); updater.fetchAndUpdateIndex( updateRequest ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() ); } public void testFailedIndexDownload() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); packIndex( remoteRepo, context ); // TrackingFetcher fetcher; IndexUpdateRequest updateRequest; // failed download fetcher = new TrackingFetcher( remoteRepo ) { public InputStream retrieve( String name ) throws IOException, java.io.FileNotFoundException { if ( name.equals( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) || name.equals( IndexingContext.INDEX_FILE_PREFIX + ".zip" ) ) { throw new IOException(); } return super.retrieve( name ); }; }; updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); try { updater.fetchAndUpdateIndex( updateRequest ); fail(); } catch ( IOException e ) { // expected } // try successful download fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() ); assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() ); } public void testCleanCacheDirectory() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); packIndex( remoteRepo, context ); // TrackingFetcher fetcher; IndexUpdateRequest updateRequest; // initial index download (expected: successfull download) fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); // new remote index delta indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ), context ); packIndex( remoteRepo, context ); // delta index download (expected: successfull download) fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); // sanity check assertTrue( new File( localCacheDir, "nexus-maven-repository-index.1.gz" ).canRead() ); // .lock files are expected to be preserved File lockFile = new File( localCacheDir, Locker.LOCK_FILE ); IOUtil.copy( "", new FileOutputStream( lockFile ) ); assertTrue( lockFile.canRead() ); // all unknown files and directories are expected to be removed File unknownFile = new File( localCacheDir, "unknownFile" ); IOUtil.copy( "", new FileOutputStream( unknownFile ) ); File unknownDirectory = new File( localCacheDir, "unknownDirectory" ); unknownDirectory.mkdirs(); assertTrue( unknownFile.canRead() ); assertTrue( unknownDirectory.isDirectory() ); // forced full update fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updateRequest.setForceFullUpdate( true ); updater.fetchAndUpdateIndex( updateRequest ); assertTrue( lockFile.canRead() ); assertFalse( new File( localCacheDir, "nexus-maven-repository-index.1.gz" ).canRead() ); assertFalse( unknownFile.canRead() ); assertFalse( unknownDirectory.isDirectory() ); } public void testOffline() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); packIndex( remoteRepo, context ); // TrackingFetcher fetcher; IndexUpdateRequest updateRequest; // initial index download (expected: successfull download) fetcher = new TrackingFetcher( remoteRepo ); IndexingContext testContext = getNewTempContext(); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updater.fetchAndUpdateIndex( updateRequest ); // recreate local index from the cache without remote access (and NULL fetcher) // fetcher is null, so we no way to assert that updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updateRequest.setOffline( true ); updater.fetchAndUpdateIndex( updateRequest ); assertGroupCount( 1, "commons-lang", testContext ); // recreate local index from the cache without remote access (and NOT NULL fetcher) fetcher = new TrackingFetcher( remoteRepo ); updateRequest = new IndexUpdateRequest( testContext, fetcher ); updateRequest.setLocalIndexCacheDir( localCacheDir ); updateRequest.setOffline( true ); updater.fetchAndUpdateIndex( updateRequest ); assertEquals( 0, fetcher.getRetrievedResources().size() ); assertGroupCount( 1, "commons-lang", testContext ); } }