View Javadoc
1   package org.apache.maven.index.updater;
2   
3   /*
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
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0    
13   *
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
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  
27  import org.apache.lucene.index.Term;
28  import org.apache.lucene.search.TermQuery;
29  import org.apache.maven.index.ArtifactInfo;
30  import org.apache.maven.index.FlatSearchRequest;
31  import org.apache.maven.index.FlatSearchResponse;
32  import org.apache.maven.index.context.IndexingContext;
33  import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException;
34  import org.apache.maven.index.fs.Locker;
35  import org.codehaus.plexus.util.FileUtils;
36  import org.codehaus.plexus.util.IOUtil;
37  import org.junit.Test;
38  
39  import static org.junit.Assert.assertEquals;
40  import static org.junit.Assert.assertFalse;
41  import static org.junit.Assert.assertTrue;
42  import static org.junit.Assert.fail;
43  
44  public class LocalIndexCacheTest
45      extends AbstractIndexUpdaterTest
46  {
47      private File remoteRepo;
48  
49      private File localCacheDir;
50  
51      private File indexDir;
52  
53      private IndexingContext tempContext;
54  
55      @Override
56      public void setUp()
57          throws Exception
58      {
59          super.setUp();
60  
61          remoteRepo = new File( "target/localcache/remoterepo" ).getCanonicalFile();
62          FileUtils.deleteDirectory( remoteRepo );
63          remoteRepo.mkdirs();
64  
65          localCacheDir = new File( "target/localcache/cache" ).getCanonicalFile();
66          FileUtils.deleteDirectory( localCacheDir );
67          localCacheDir.mkdirs();
68  
69          indexDir = new File( "target/localcache/index" ).getCanonicalFile();
70          FileUtils.deleteDirectory( indexDir );
71          indexDir.mkdirs();
72      }
73  
74      @Override
75      public void tearDown()
76          throws Exception
77      {
78          removeTempContext();
79  
80          super.tearDown();
81      }
82  
83      private IndexingContext getNewTempContext()
84          throws IOException, UnsupportedExistingLuceneIndexException
85      {
86          removeTempContext();
87  
88          tempContext =
89              indexer.addIndexingContext( repositoryId + "temp", repositoryId, repoDir, indexDir, repositoryUrl, null,
90                  MIN_CREATORS );
91  
92          return tempContext;
93      }
94  
95      private void removeTempContext()
96          throws IOException
97      {
98          if ( tempContext != null )
99          {
100             indexer.removeIndexingContext( tempContext, true );
101             tempContext = null;
102             FileUtils.cleanDirectory( indexDir );
103         }
104     }
105 
106     @Test
107     public void testBasic()
108         throws Exception
109     {
110         // create initial remote repo index
111         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
112             context );
113         packIndex( remoteRepo, context );
114 
115         //
116         TrackingFetcher fetcher;
117         IndexUpdateRequest updateRequest;
118         IndexingContext testContext;
119 
120         // initial index download (expected: full index download)
121         testContext = getNewTempContext();
122         fetcher = new TrackingFetcher( remoteRepo );
123         updateRequest = new IndexUpdateRequest( testContext, fetcher );
124         updateRequest.setLocalIndexCacheDir( localCacheDir );
125         updater.fetchAndUpdateIndex( updateRequest );
126         assertEquals( 2, fetcher.getRetrievedResources().size() );
127         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() );
128         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() );
129         assertGroupCount( 1, "commons-lang", testContext );
130 
131         // update the same index (expected: no index download)
132         fetcher = new TrackingFetcher( remoteRepo );
133         updateRequest = new IndexUpdateRequest( testContext, fetcher );
134         updateRequest.setLocalIndexCacheDir( localCacheDir );
135         updater.fetchAndUpdateIndex( updateRequest );
136         assertEquals( 1, fetcher.getRetrievedResources().size() );
137         assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) );
138         assertGroupCount( 1, "commons-lang", testContext );
139 
140         // nuke index but keep the cache (expected: no index download)
141         testContext = getNewTempContext();
142         fetcher = new TrackingFetcher( remoteRepo );
143         updateRequest = new IndexUpdateRequest( testContext, fetcher );
144         updateRequest.setLocalIndexCacheDir( localCacheDir );
145         updater.fetchAndUpdateIndex( updateRequest );
146         assertEquals( 1, fetcher.getRetrievedResources().size() );
147         assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) );
148         assertGroupCount( 1, "commons-lang", testContext );
149 
150         // incremental remote update
151         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ),
152             context );
153         packIndex( remoteRepo, context );
154 
155         // update via cache (expected: incremental chunk download)
156         fetcher = new TrackingFetcher( remoteRepo );
157         updateRequest = new IndexUpdateRequest( testContext, fetcher );
158         updateRequest.setLocalIndexCacheDir( localCacheDir );
159         updater.fetchAndUpdateIndex( updateRequest );
160         assertEquals( 2, fetcher.getRetrievedResources().size() );
161         assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) );
162         assertEquals( "nexus-maven-repository-index.1.gz", fetcher.getRetrievedResources().get( 1 ) );
163         assertGroupCount( 2, "commons-lang", testContext );
164 
165         // nuke index but keep the cache (expected: no index download, index contains both initial and delta chunks)
166         testContext = getNewTempContext();
167         fetcher = new TrackingFetcher( remoteRepo );
168         updateRequest = new IndexUpdateRequest( testContext, fetcher );
169         updateRequest.setLocalIndexCacheDir( localCacheDir );
170         updater.fetchAndUpdateIndex( updateRequest );
171         assertEquals( 1, fetcher.getRetrievedResources().size() );
172         assertEquals( "nexus-maven-repository-index.properties", fetcher.getRetrievedResources().get( 0 ) );
173         assertGroupCount( 2, "commons-lang", testContext );
174 
175         // kill the cache, but keep the index (expected: full index download)
176         // TODO how to assert if merge==false internally?
177         FileUtils.deleteDirectory( localCacheDir );
178         fetcher = new TrackingFetcher( remoteRepo );
179         updateRequest = new IndexUpdateRequest( testContext, fetcher );
180         updateRequest.setLocalIndexCacheDir( localCacheDir );
181         updater.fetchAndUpdateIndex( updateRequest );
182         assertEquals( 2, fetcher.getRetrievedResources().size() );
183         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() );
184         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() );
185         assertGroupCount( 2, "commons-lang", testContext );
186     }
187 
188     private void assertGroupCount( int expectedCount, String groupId, IndexingContext context )
189         throws IOException
190     {
191         TermQuery query = new TermQuery( new Term( ArtifactInfo.GROUP_ID, groupId ) );
192         FlatSearchResponse response = indexer.searchFlat( new FlatSearchRequest( query, context ) );
193         assertEquals( expectedCount, response.getTotalHits() );
194     }
195 
196     @Test
197     public void testForceIndexDownload()
198         throws Exception
199     {
200         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
201             context );
202         packIndex( remoteRepo, context );
203 
204         //
205         TrackingFetcher fetcher;
206         IndexUpdateRequest updateRequest;
207 
208         // initial index download (expected: no index download)
209         fetcher = new TrackingFetcher( remoteRepo );
210         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
211         updateRequest.setLocalIndexCacheDir( localCacheDir );
212         updater.fetchAndUpdateIndex( updateRequest );
213 
214         // corrupt local cache
215         try ( FileOutputStream fos = new FileOutputStream( new File( localCacheDir, "nexus-maven-repository-index.gz" ) ) )
216         {
217             IOUtil.copy( "corrupted", fos );
218         }
219 
220         // try download again (it would have failed if force did not update local cache)
221         removeTempContext();
222         fetcher = new TrackingFetcher( remoteRepo );
223         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
224         updateRequest.setLocalIndexCacheDir( localCacheDir );
225         updateRequest.setForceFullUpdate( true );
226         updater.fetchAndUpdateIndex( updateRequest );
227     }
228 
229     @Test
230     public void testInitialForcedFullDownload()
231         throws Exception
232     {
233         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
234             context );
235         packIndex( remoteRepo, context );
236 
237         //
238         TrackingFetcher fetcher;
239         IndexUpdateRequest updateRequest;
240 
241         // initial forced full index download (expected: successfull download)
242         fetcher = new TrackingFetcher( remoteRepo );
243         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
244         updateRequest.setLocalIndexCacheDir( localCacheDir );
245         updateRequest.setForceFullUpdate( true );
246         updater.fetchAndUpdateIndex( updateRequest );
247         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() );
248         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() );
249     }
250 
251     @Test
252     public void testFailedIndexDownload()
253         throws Exception
254     {
255         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
256             context );
257         packIndex( remoteRepo, context );
258 
259         //
260         TrackingFetcher fetcher;
261         IndexUpdateRequest updateRequest;
262 
263         // failed download
264         fetcher = new TrackingFetcher( remoteRepo )
265         {
266             public InputStream retrieve( String name )
267                 throws IOException, java.io.FileNotFoundException
268             {
269                 if ( name.equals( IndexingContext.INDEX_FILE_PREFIX + ".gz" )
270                     || name.equals( IndexingContext.INDEX_FILE_PREFIX + ".zip" ) )
271                 {
272                     throw new IOException();
273                 }
274                 return super.retrieve( name );
275             }
276         };
277         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
278         updateRequest.setLocalIndexCacheDir( localCacheDir );
279         try
280         {
281             updater.fetchAndUpdateIndex( updateRequest );
282             fail();
283         }
284         catch ( IOException e )
285         {
286             // expected
287         }
288 
289         // try successful download
290         fetcher = new TrackingFetcher( remoteRepo );
291         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
292         updateRequest.setLocalIndexCacheDir( localCacheDir );
293         updater.fetchAndUpdateIndex( updateRequest );
294         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.gz" ).exists() );
295         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.properties" ).exists() );
296     }
297 
298     @Test
299     public void testCleanCacheDirectory()
300         throws Exception
301     {
302         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
303             context );
304         packIndex( remoteRepo, context );
305 
306         //
307         TrackingFetcher fetcher;
308         IndexUpdateRequest updateRequest;
309 
310         // initial index download (expected: successfull download)
311         fetcher = new TrackingFetcher( remoteRepo );
312         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
313         updateRequest.setLocalIndexCacheDir( localCacheDir );
314         updater.fetchAndUpdateIndex( updateRequest );
315 
316         // new remote index delta
317         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ),
318             context );
319         packIndex( remoteRepo, context );
320 
321         // delta index download (expected: successfull download)
322         fetcher = new TrackingFetcher( remoteRepo );
323         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
324         updateRequest.setLocalIndexCacheDir( localCacheDir );
325         updater.fetchAndUpdateIndex( updateRequest );
326 
327         // sanity check
328         assertTrue( new File( localCacheDir, "nexus-maven-repository-index.1.gz" ).canRead() );
329 
330         // .lock files are expected to be preserved
331         File lockFile = new File( localCacheDir, Locker.LOCK_FILE );
332         try ( FileOutputStream lockFileOutput = new FileOutputStream( lockFile ) )
333         {
334             IOUtil.copy( "", lockFileOutput );
335         }
336         assertTrue( lockFile.canRead() );
337 
338         // all unknown files and directories are expected to be removed
339         File unknownFile = new File( localCacheDir, "unknownFile" );
340         try ( FileOutputStream fileOutputStream = new FileOutputStream( unknownFile ) )
341         {
342             IOUtil.copy( "", fileOutputStream );
343         }
344 
345         File unknownDirectory = new File( localCacheDir, "unknownDirectory" );
346         unknownDirectory.mkdirs();
347         assertTrue( unknownFile.canRead() );
348         assertTrue( unknownDirectory.isDirectory() );
349 
350         // forced full update
351         fetcher = new TrackingFetcher( remoteRepo );
352         updateRequest = new IndexUpdateRequest( getNewTempContext(), fetcher );
353         updateRequest.setLocalIndexCacheDir( localCacheDir );
354         updateRequest.setForceFullUpdate( true );
355         updater.fetchAndUpdateIndex( updateRequest );
356 
357         assertTrue( lockFile.canRead() );
358         assertFalse( new File( localCacheDir, "nexus-maven-repository-index.1.gz" ).canRead() );
359         assertFalse( unknownFile.canRead() );
360         assertFalse( unknownDirectory.isDirectory() );
361     }
362 
363     @Test
364     public void testOffline()
365         throws Exception
366     {
367         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
368             context );
369         packIndex( remoteRepo, context );
370 
371         //
372         TrackingFetcher fetcher;
373         IndexUpdateRequest updateRequest;
374 
375         // initial index download (expected: successfull download)
376         fetcher = new TrackingFetcher( remoteRepo );
377         IndexingContext testContext = getNewTempContext();
378         updateRequest = new IndexUpdateRequest( testContext, fetcher );
379         updateRequest.setLocalIndexCacheDir( localCacheDir );
380         updater.fetchAndUpdateIndex( updateRequest );
381 
382         // recreate local index from the cache without remote access (and NULL fetcher)
383         // fetcher is null, so we no way to assert that
384         updateRequest = new IndexUpdateRequest( testContext, fetcher );
385         updateRequest.setLocalIndexCacheDir( localCacheDir );
386         updateRequest.setOffline( true );
387         updater.fetchAndUpdateIndex( updateRequest );
388         assertGroupCount( 1, "commons-lang", testContext );
389 
390         // recreate local index from the cache without remote access (and NOT NULL fetcher)
391         fetcher = new TrackingFetcher( remoteRepo );
392         updateRequest = new IndexUpdateRequest( testContext, fetcher );
393         updateRequest.setLocalIndexCacheDir( localCacheDir );
394         updateRequest.setOffline( true );
395         updater.fetchAndUpdateIndex( updateRequest );
396         assertEquals( 0, fetcher.getRetrievedResources().size() );
397         assertGroupCount( 1, "commons-lang", testContext );
398     }
399 
400 }