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.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.Properties; import java.util.Set; import org.apache.lucene.index.Term; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IOContext; import org.apache.lucene.store.RAMDirectory; import org.apache.maven.index.ArtifactInfo; import org.apache.maven.index.FlatSearchRequest; import org.apache.maven.index.FlatSearchResponse; import org.apache.maven.index.MAVEN; import org.apache.maven.index.SearchType; import org.apache.maven.index.context.IndexUtils; import org.apache.maven.index.context.IndexingContext; import org.codehaus.plexus.util.IOUtil; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.api.Invocation; import org.jmock.lib.action.ReturnValueAction; import org.jmock.lib.action.VoidAction; import org.junit.Ignore; /** * @author Eugene Kuleshov */ public class DefaultIndexUpdaterTest extends AbstractIndexUpdaterTest { SimpleDateFormat df = new SimpleDateFormat( "yyyyMMddHHmmss.SSS Z" ); public void testReplaceIndex() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); Query q = indexer.constructQuery( MAVEN.ARTIFACT_ID, "commons-lang", SearchType.SCORED ); FlatSearchResponse response1 = indexer.searchFlat( new FlatSearchRequest( q ) ); Collection<ArtifactInfo> content1 = response1.getResults(); assertEquals( content1.toString(), 1, content1.size() ); // updated index Directory tempIndexDirectory = new RAMDirectory(); IndexingContext tempContext = indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory, repositoryUrl, null, MIN_CREATORS ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ), tempContext ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext ); FlatSearchResponse response2 = indexer.searchFlat( new FlatSearchRequest( q, tempContext ) ); Collection<ArtifactInfo> tempContent = response2.getResults(); assertEquals( tempContent.toString(), 2, tempContent.size() ); // RAMDirectory is closed with context, forcing timestamp update tempContext.updateTimestamp( true ); // A change in RAMDirectory and Directory behavior in general: it will copy the Index files ONLY // So we must make sure that timestamp file is transferred correctly. RAMDirectory tempDir2 = new RAMDirectory(); IndexUtils.copyDirectory( tempContext.getIndexDirectory(), tempDir2 ); Date newIndexTimestamp = tempContext.getTimestamp(); indexer.removeIndexingContext( tempContext, false ); context.replace( tempDir2 ); assertEquals( newIndexTimestamp, context.getTimestamp() ); FlatSearchResponse response3 = indexer.searchFlat( new FlatSearchRequest( q ) ); Collection<ArtifactInfo> content2 = response3.getResults(); assertEquals( content2.toString(), 2, content2.size() ); } public void testMergeIndex() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); Query q = indexer.constructQuery( MAVEN.ARTIFACT_ID, "commons-lang", SearchType.SCORED ); { FlatSearchResponse response1 = indexer.searchFlat( new FlatSearchRequest( q ) ); Collection<ArtifactInfo> content1 = response1.getResults(); assertEquals( content1.toString(), 1, content1.size() ); } // updated index { Directory tempIndexDirectory = new RAMDirectory(); IndexingContext tempContext = indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory, repositoryUrl, null, MIN_CREATORS ); // indexer.addArtifactToIndex( // createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), // tempContext ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ), tempContext ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext ); FlatSearchResponse tempResponse = indexer.searchFlat( new FlatSearchRequest( q ) ); Collection<ArtifactInfo> tempContent = tempResponse.getResults(); assertEquals( tempContent.toString(), 3, tempContent.size() ); RAMDirectory tempDir2 = new RAMDirectory(); for (String file : tempContext.getIndexDirectory().listAll()) { tempDir2.copyFrom(tempContext.getIndexDirectory(), file, file, IOContext.DEFAULT); } indexer.removeIndexingContext( tempContext, false ); context.merge( tempDir2 ); FlatSearchResponse response2 = indexer.searchFlat( new FlatSearchRequest( q ) ); Collection<ArtifactInfo> content2 = response2.getResults(); assertEquals( content2.toString(), 3, content2.size() ); } } public void testMergeIndexDeletes() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ), context ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), context ); { Directory tempIndexDirectory = new RAMDirectory(); IndexingContext tempContext = indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory, repositoryUrl, null, MIN_CREATORS ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), tempContext ); indexer.deleteArtifactFromIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), tempContext ); indexer.deleteArtifactFromIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext ); RAMDirectory tempDir2 = new RAMDirectory(); for (String file : tempContext.getIndexDirectory().listAll()) { tempDir2.copyFrom(tempContext.getIndexDirectory(), file, file, IOContext.DEFAULT); } indexer.removeIndexingContext( tempContext, false ); context.merge( tempDir2 ); } Query q = indexer.constructQuery( MAVEN.ARTIFACT_ID, "commons-lang", SearchType.SCORED ); FlatSearchResponse response = indexer.searchFlat( new FlatSearchRequest( q ) ); Collection<ArtifactInfo> content2 = response.getResults(); assertEquals( content2.toString(), 1, content2.size() ); } public void testMergeSearch() throws Exception { File repo1 = new File( getBasedir(), "src/test/nexus-658" ); Directory indexDir1 = new RAMDirectory(); IndexingContext context1 = indexer.addIndexingContext( "nexus-658", "nexus-658", repo1, indexDir1, null, null, DEFAULT_CREATORS ); indexer.scan( context1 ); File repo2 = new File( getBasedir(), "src/test/nexus-13" ); Directory indexDir2 = new RAMDirectory(); IndexingContext context2 = indexer.addIndexingContext( "nexus-13", "nexus-13", repo2, indexDir2, null, null, DEFAULT_CREATORS ); indexer.scan( context2 ); context1.merge( indexDir2 ); Query q = new TermQuery( new Term( ArtifactInfo.SHA1, "b5e9d009320d11b9859c15d3ad3603b455fa1c85" ) ); FlatSearchRequest request = new FlatSearchRequest( q, context1 ); FlatSearchResponse response = indexer.searchFlat( request ); Set<ArtifactInfo> results = response.getResults(); ArtifactInfo artifactInfo = results.iterator().next(); assertEquals( artifactInfo.getArtifactId(), "dma.integration.tests" ); } public void testMergeGroups() throws Exception { indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), context ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-collections", "commons-collections", "1.0", null ), context ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "org.slf4j", "slf4j-api", "1.4.2", null ), context ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "org.slf4j", "slf4j-log4j12", "1.4.2", null ), context ); { Directory tempIndexDirectory = new RAMDirectory(); IndexingContext tempContext = indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory, repositoryUrl, null, MIN_CREATORS ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "junit", "junit", "3.8", null ), tempContext ); indexer.addArtifactToIndex( createArtifactContext( repositoryId, "org.slf4j.foo", "jcl104-over-slf4j", "1.4.2", null ), context ); RAMDirectory tempDir2 = new RAMDirectory(); for (String file : tempContext.getIndexDirectory().listAll()) { tempDir2.copyFrom(tempContext.getIndexDirectory(), file, file, IOContext.DEFAULT); } indexer.removeIndexingContext( tempContext, false ); context.merge( tempDir2 ); } Set<String> rootGroups = context.getRootGroups(); assertEquals( rootGroups.toString(), 4, rootGroups.size() ); Set<String> allGroups = context.getAllGroups(); assertEquals( allGroups.toString(), 5, allGroups.size() ); } public void testNoIndexUpdate() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081125010000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); final Properties localProps = new Properties(); localProps.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "1" ); localProps.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); localProps.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081125010000.000 -0600" ); mockery.checking( new Expectations() { { allowing( tempContext ).getIndexDirectoryFile(); will( new IndexDirectoryFileAction( localProps, testBasedir ) ); allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).commit(); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081125010000.000 -0600" ); return properties; } } ); allowing( tempContext ).getIndexDirectoryFile(); oneOf( mockFetcher ).disconnect(); } } ); // tempContext.updateTimestamp( true, contextTimestamp ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateSucceeded(updateResult); } public void testFullIndexUpdate() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081125010000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); mockery.checking( new Expectations() { { allowing( tempContext ).getIndexDirectoryFile(); will( new ReturnValueAction( testBasedir ) ); allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).commit(); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); allowing( tempContext ).commit(); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081126010000.000 -0600" ); return properties; } } ); allowing( tempContext ).getIndexDirectoryFile(); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) ); will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) ); oneOf( tempContext ).replace( with( any( Directory.class ) ), with( any( Set.class ) ), with( any( Set.class ) ) ); oneOf( mockFetcher ).disconnect(); } } ); // tempContext.updateTimestamp( true, contextTimestamp ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateSucceeded(updateResult); } public void testIncrementalIndexUpdate() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081128000000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); final Properties localProps = new Properties(); localProps.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "1" ); localProps.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); mockery.checking( new Expectations() { { allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).commit(); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" ); properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" ); properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" ); return properties; } } ); allowing( tempContext ).getIndexDirectoryFile(); will( new IndexDirectoryFileAction( localProps, testBasedir ) ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) ); will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".3.gz" ) ); will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) ); // could create index archive there and verify that it is merged correctly oneOf( tempContext ).merge( with( any( Directory.class ) ) ); oneOf( tempContext ).merge( with( any( Directory.class ) ) ); oneOf( mockFetcher ).disconnect(); } } ); // tempContext.updateTimestamp( true, contextTimestamp ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); updateRequest.setIncrementalOnly(true); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateSucceeded(updateResult); } public void testIncrementalIndexUpdateNoCounter() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081128000000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); mockery.checking( new Expectations() { { allowing( tempContext ).getIndexDirectoryFile(); will( new ReturnValueAction( testBasedir ) ); allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).commit(); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" ); properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" ); properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" ); return properties; } } ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) ); will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) ); // could create index archive there and verify that it is merged correctly oneOf( tempContext ).replace( with( any( Directory.class ) ), with( any( Set.class ) ), with( any( Set.class ) ) ); never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) ); never( tempContext ).merge( with( any( Directory.class ) ) ); oneOf( mockFetcher ).disconnect(); } } ); // tempContext.updateTimestamp( true, contextTimestamp ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateSucceeded(updateResult); } public void testIncrementalOnlyIndexUpdateNoCounter() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081128000000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); mockery.checking( new Expectations() { { allowing( tempContext ).getIndexDirectoryFile(); will( new ReturnValueAction( testBasedir ) ); allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" ); properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" ); properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" ); return properties; } } ); oneOf( mockFetcher ).disconnect(); } } ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); updateRequest.setIncrementalOnly(true); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateFailed(updateResult); } public void testIncrementalIndexUpdateNoUpdateNecessary() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081128000000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); final Properties localProps = new Properties(); localProps.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" ); localProps.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); mockery.checking( new Expectations() { { allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); allowing( tempContext ).commit(); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" ); properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" ); properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" ); return properties; } } ); allowing( tempContext ).getIndexDirectoryFile(); will( new IndexDirectoryFileAction( localProps, testBasedir ) ); never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) ); // could create index archive there and verify that it is merged correctly never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".1.gz" ) ); never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) ); never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".3.gz" ) ); never( tempContext ).merge( with( any( Directory.class ) ) ); never( tempContext ).replace( with( any( Directory.class ) ) ); oneOf( mockFetcher ).disconnect(); } } ); // tempContext.updateTimestamp( true, contextTimestamp ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateSucceeded(updateResult); } public void testUpdateForceFullUpdate() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081128000000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); mockery.checking( new Expectations() { { allowing( tempContext ).getIndexDirectoryFile(); will( new ReturnValueAction( testBasedir ) ); allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).commit(); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" ); properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" ); properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" ); properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" ); return properties; } } ); never( tempContext ).getIndexDirectoryFile(); never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".1.gz" ) ); never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) ); never( mockFetcher ).retrieve( // with( IndexingContext.INDEX_FILE_PREFIX + ".3.gz" ) ); oneOf( mockFetcher ).retrieve( with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) ); will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) ); never( tempContext ).merge( with( any( Directory.class ) ) ); never( tempContext ).merge( with( any( Directory.class ) ) ); oneOf( tempContext ).replace( with( any( Directory.class ) ), with( any( Set.class ) ), with( any( Set.class ) ) ); oneOf( mockFetcher ).disconnect(); } } ); // tempContext.updateTimestamp( true, contextTimestamp ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); updateRequest.setForceFullUpdate( true ); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateSucceeded(updateResult); } @Ignore("Legacy format no longer supported with Lucene 4") public void ignoreTestUpdateForceFullUpdateNoGZ() throws Exception { Mockery mockery = new Mockery(); final String indexUrl = repositoryUrl + ".index"; final Date contextTimestamp = df.parse( "20081128000000.000 -0600" ); final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class ); final IndexingContext tempContext = mockery.mock( IndexingContext.class ); mockery.checking( new Expectations() { { allowing( tempContext ).getIndexDirectoryFile(); will( new ReturnValueAction( testBasedir ) ); allowing( tempContext ).getTimestamp(); will( returnValue( contextTimestamp ) ); allowing( tempContext ).commit(); allowing( tempContext ).getId(); will( returnValue( repositoryId ) ); allowing( tempContext ).getIndexUpdateUrl(); will( returnValue( indexUrl ) ); allowing( tempContext ).getIndexCreators(); will( returnValue( DEFAULT_CREATORS ) ); oneOf( mockFetcher ).connect( repositoryId, indexUrl ); oneOf( mockFetcher ).retrieve( // with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) ); will( new PropertiesAction() { @Override Properties getProperties() { Properties properties = new Properties(); properties.setProperty( IndexingContext.INDEX_ID, "central" ); properties.setProperty( IndexingContext.INDEX_LEGACY_TIMESTAMP, "20081129174241.859 -0600" ); return properties; } } ); never( tempContext ).getIndexDirectoryFile(); oneOf( mockFetcher ).retrieve( with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) ); will( throwException( new IOException() ) ); oneOf( mockFetcher ).retrieve( with( IndexingContext.INDEX_FILE_PREFIX + ".zip" ) ); will( returnValue( newInputStream( "/index-updater/server-root/legacy/nexus-maven-repository-index.zip" ) ) ); never( tempContext ).merge( with( any( Directory.class ) ) ); never( tempContext ).merge( with( any( Directory.class ) ) ); oneOf( tempContext ).replace( with( any( Directory.class ) ) ); oneOf( mockFetcher ).disconnect(); } } ); // tempContext.updateTimestamp( true, contextTimestamp ); IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher ); updateRequest.setForceFullUpdate( true ); IndexUpdateResult updateResult = updater.fetchAndUpdateIndex( updateRequest ); mockery.assertIsSatisfied(); assertIndexUpdateSucceeded(updateResult); } protected InputStream newInputStream( String path ) { return getResourceAsStream( path ); } abstract static class PropertiesAction extends VoidAction { @Override public Object invoke( Invocation invocation ) throws Throwable { Properties properties = getProperties(); try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { properties.store( buf, null ); buf.flush(); return new ByteArrayInputStream( buf.toByteArray() ); } } abstract Properties getProperties(); } private static class IndexDirectoryFileAction extends VoidAction { File file = null; public IndexDirectoryFileAction( Properties properties, File basedir ) throws Exception { basedir.mkdirs(); this.file = new File( basedir, IndexingContext.INDEX_UPDATER_PROPERTIES_FILE ); try ( FileOutputStream fos = new FileOutputStream( this.file )) { properties.store( fos, "" ); } } @Override public Object invoke( Invocation invocation ) throws Throwable { return this.file.getParentFile(); } } private void assertIndexUpdateSucceeded(IndexUpdateResult updateResult) { assertTrue("Index update should have succeeded, but says it failed", updateResult.isSuccessful()); } private void assertIndexUpdateFailed(IndexUpdateResult updateResult) { assertFalse("Index update should have failed, but says it succeeded", updateResult.isSuccessful()); } }