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