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.ByteArrayInputStream;
23  import java.io.ByteArrayOutputStream;
24  import java.io.File;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.text.SimpleDateFormat;
29  import java.util.Collection;
30  import java.util.Date;
31  import java.util.Properties;
32  import java.util.Set;
33  
34  import org.apache.lucene.index.Term;
35  import org.apache.lucene.search.Query;
36  import org.apache.lucene.search.TermQuery;
37  import org.apache.lucene.store.Directory;
38  import org.apache.lucene.store.RAMDirectory;
39  import org.apache.maven.index.ArtifactInfo;
40  import org.apache.maven.index.FlatSearchRequest;
41  import org.apache.maven.index.FlatSearchResponse;
42  import org.apache.maven.index.MAVEN;
43  import org.apache.maven.index.SearchType;
44  import org.apache.maven.index.context.IndexUtils;
45  import org.apache.maven.index.context.IndexingContext;
46  import org.codehaus.plexus.util.IOUtil;
47  import org.jmock.Expectations;
48  import org.jmock.Mockery;
49  import org.jmock.api.Invocation;
50  import org.jmock.lib.action.ReturnValueAction;
51  import org.jmock.lib.action.VoidAction;
52  
53  /**
54   * @author Eugene Kuleshov
55   */
56  public class DefaultIndexUpdaterTest
57      extends AbstractIndexUpdaterTest
58  {
59  
60      SimpleDateFormat df = new SimpleDateFormat( "yyyyMMddHHmmss.SSS Z" );
61  
62      public void testReplaceIndex()
63          throws Exception
64      {
65          indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
66              context );
67  
68          Query q = indexer.constructQuery( MAVEN.ARTIFACT_ID, "commons-lang", SearchType.SCORED );
69  
70          FlatSearchResponse response1 = indexer.searchFlat( new FlatSearchRequest( q ) );
71          Collection<ArtifactInfo> content1 = response1.getResults();
72  
73          assertEquals( content1.toString(), 1, content1.size() );
74  
75          // updated index
76  
77          Directory tempIndexDirectory = new RAMDirectory();
78  
79          IndexingContext tempContext =
80              indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory, repositoryUrl,
81                  null, MIN_CREATORS );
82  
83          indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ),
84              tempContext );
85  
86          indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ),
87              tempContext );
88  
89          FlatSearchResponse response2 = indexer.searchFlat( new FlatSearchRequest( q, tempContext ) );
90          Collection<ArtifactInfo> tempContent = response2.getResults();
91          assertEquals( tempContent.toString(), 2, tempContent.size() );
92  
93          // RAMDirectory is closed with context, forcing timestamp update
94          tempContext.updateTimestamp( true );
95  
96          // A change in RAMDirectory and Directory behavior in general: it will copy the Index files ONLY
97          // So we must make sure that timestamp file is transferred correctly.
98          RAMDirectory tempDir2 = new RAMDirectory();
99          IndexUtils.copyDirectory( tempContext.getIndexDirectory(), tempDir2 );
100 
101         Date newIndexTimestamp = tempContext.getTimestamp();
102 
103         indexer.removeIndexingContext( tempContext, false );
104 
105         context.replace( tempDir2 );
106 
107         assertEquals( newIndexTimestamp, context.getTimestamp() );
108 
109         FlatSearchResponse response3 = indexer.searchFlat( new FlatSearchRequest( q ) );
110         Collection<ArtifactInfo> content2 = response3.getResults();
111         assertEquals( content2.toString(), 2, content2.size() );
112     }
113 
114     public void testMergeIndex()
115         throws Exception
116     {
117         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
118             context );
119 
120         Query q = indexer.constructQuery( MAVEN.ARTIFACT_ID, "commons-lang", SearchType.SCORED );
121 
122         {
123             FlatSearchResponse response1 = indexer.searchFlat( new FlatSearchRequest( q ) );
124             Collection<ArtifactInfo> content1 = response1.getResults();
125 
126             assertEquals( content1.toString(), 1, content1.size() );
127         }
128 
129         // updated index
130 
131         {
132             Directory tempIndexDirectory = new RAMDirectory();
133 
134             IndexingContext tempContext =
135                 indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory,
136                     repositoryUrl, null, MIN_CREATORS );
137 
138             // indexer.addArtifactToIndex(
139             // createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
140             // tempContext );
141 
142             indexer.addArtifactToIndex(
143                 createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ), tempContext );
144 
145             indexer.addArtifactToIndex(
146                 createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext );
147 
148             FlatSearchResponse tempResponse = indexer.searchFlat( new FlatSearchRequest( q ) );
149             Collection<ArtifactInfo> tempContent = tempResponse.getResults();
150             assertEquals( tempContent.toString(), 3, tempContent.size() );
151 
152             RAMDirectory tempDir2 = new RAMDirectory( tempContext.getIndexDirectory() );
153 
154             indexer.removeIndexingContext( tempContext, false );
155 
156             context.merge( tempDir2 );
157 
158             FlatSearchResponse response2 = indexer.searchFlat( new FlatSearchRequest( q ) );
159             Collection<ArtifactInfo> content2 = response2.getResults();
160             assertEquals( content2.toString(), 3, content2.size() );
161         }
162     }
163 
164     public void testMergeIndexDeletes()
165         throws Exception
166     {
167         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
168             context );
169 
170         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.3", null ),
171             context );
172 
173         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ),
174             context );
175 
176         {
177             Directory tempIndexDirectory = new RAMDirectory();
178 
179             IndexingContext tempContext =
180                 indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory,
181                     repositoryUrl, null, MIN_CREATORS );
182 
183             indexer.addArtifactToIndex(
184                 createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext );
185 
186             indexer.addArtifactToIndex(
187                 createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), tempContext );
188 
189             indexer.deleteArtifactFromIndex(
190                 createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ), tempContext );
191 
192             indexer.deleteArtifactFromIndex(
193                 createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext );
194 
195             RAMDirectory tempDir2 = new RAMDirectory( tempContext.getIndexDirectory() );
196 
197             indexer.removeIndexingContext( tempContext, false );
198 
199             context.merge( tempDir2 );
200         }
201 
202         Query q = indexer.constructQuery( MAVEN.ARTIFACT_ID, "commons-lang", SearchType.SCORED );
203 
204         FlatSearchResponse response = indexer.searchFlat( new FlatSearchRequest( q ) );
205         Collection<ArtifactInfo> content2 = response.getResults();
206 
207         assertEquals( content2.toString(), 1, content2.size() );
208     }
209 
210     public void testMergeSearch()
211         throws Exception
212     {
213         File repo1 = new File( getBasedir(), "src/test/nexus-658" );
214         Directory indexDir1 = new RAMDirectory();
215 
216         IndexingContext context1 =
217             indexer.addIndexingContext( "nexus-658", "nexus-658", repo1, indexDir1, null, null, DEFAULT_CREATORS );
218         indexer.scan( context1 );
219 
220         File repo2 = new File( getBasedir(), "src/test/nexus-13" );
221         Directory indexDir2 = new RAMDirectory();
222 
223         IndexingContext context2 =
224             indexer.addIndexingContext( "nexus-13", "nexus-13", repo2, indexDir2, null, null, DEFAULT_CREATORS );
225         indexer.scan( context2 );
226 
227         context1.merge( indexDir2 );
228 
229         Query q = new TermQuery( new Term( ArtifactInfo.SHA1, "b5e9d009320d11b9859c15d3ad3603b455fa1c85" ) );
230         FlatSearchRequest request = new FlatSearchRequest( q, context1 );
231         FlatSearchResponse response = indexer.searchFlat( request );
232 
233         Set<ArtifactInfo> results = response.getResults();
234         ArtifactInfo artifactInfo = results.iterator().next();
235         assertEquals( artifactInfo.artifactId, "dma.integration.tests" );
236     }
237 
238     public void testMergeGroups()
239         throws Exception
240     {
241         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.2", null ),
242             context );
243 
244         indexer.addArtifactToIndex(
245             createArtifactContext( repositoryId, "commons-collections", "commons-collections", "1.0", null ), context );
246 
247         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "org.slf4j", "slf4j-api", "1.4.2", null ),
248             context );
249 
250         indexer.addArtifactToIndex( createArtifactContext( repositoryId, "org.slf4j", "slf4j-log4j12", "1.4.2", null ),
251             context );
252 
253         {
254             Directory tempIndexDirectory = new RAMDirectory();
255 
256             IndexingContext tempContext =
257                 indexer.addIndexingContext( repositoryId + "temp", repositoryId, null, tempIndexDirectory,
258                     repositoryUrl, null, MIN_CREATORS );
259 
260             indexer.addArtifactToIndex(
261                 createArtifactContext( repositoryId, "commons-lang", "commons-lang", "2.4", null ), tempContext );
262 
263             indexer.addArtifactToIndex( createArtifactContext( repositoryId, "junit", "junit", "3.8", null ),
264                 tempContext );
265 
266             indexer.addArtifactToIndex(
267                 createArtifactContext( repositoryId, "org.slf4j.foo", "jcl104-over-slf4j", "1.4.2", null ), context );
268 
269             RAMDirectory tempDir2 = new RAMDirectory( tempContext.getIndexDirectory() );
270 
271             indexer.removeIndexingContext( tempContext, false );
272 
273             context.merge( tempDir2 );
274         }
275 
276         Set<String> rootGroups = context.getRootGroups();
277 
278         assertEquals( rootGroups.toString(), 4, rootGroups.size() );
279 
280         Set<String> allGroups = context.getAllGroups();
281 
282         assertEquals( allGroups.toString(), 5, allGroups.size() );
283     }
284 
285     public void testNoIndexUpdate()
286         throws Exception
287     {
288         Mockery mockery = new Mockery();
289 
290         final String indexUrl = repositoryUrl + ".index";
291         final Date contextTimestamp = df.parse( "20081125010000.000 -0600" );
292 
293         final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class );
294 
295         final IndexingContext tempContext = mockery.mock( IndexingContext.class );
296 
297         final Properties localProps = new Properties();
298         localProps.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "1" );
299         localProps.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" );
300         localProps.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081125010000.000 -0600" );
301 
302         mockery.checking( new Expectations()
303         {
304             {
305                 allowing( tempContext ).getIndexDirectoryFile();
306                 will( new IndexDirectoryFileAction( localProps, testBasedir ) );
307 
308                 allowing( tempContext ).getTimestamp();
309                 will( returnValue( contextTimestamp ) );
310 
311                 allowing( tempContext ).getId();
312                 will( returnValue( repositoryId ) );
313 
314                 allowing( tempContext ).commit();
315 
316                 allowing( tempContext ).getIndexUpdateUrl();
317                 will( returnValue( indexUrl ) );
318 
319                 allowing( tempContext ).getIndexCreators();
320                 will( returnValue( DEFAULT_CREATORS ) );
321 
322                 oneOf( mockFetcher ).connect( repositoryId, indexUrl );
323 
324                 oneOf( mockFetcher ).retrieve( //
325                     with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) );
326                 will( new PropertiesAction()
327                 {
328                     @Override
329                     Properties getProperties()
330                     {
331                         Properties properties = new Properties();
332                         properties.setProperty( IndexingContext.INDEX_ID, "central" );
333                         properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081125010000.000 -0600" );
334                         return properties;
335                     }
336                 } );
337 
338                 allowing( tempContext ).getIndexDirectoryFile();
339 
340                 oneOf( mockFetcher ).disconnect();
341             }
342         } );
343 
344         // tempContext.updateTimestamp( true, contextTimestamp );
345 
346         IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher );
347 
348         updater.fetchAndUpdateIndex( updateRequest );
349 
350         mockery.assertIsSatisfied();
351     }
352 
353     public void testFullIndexUpdate()
354         throws Exception
355     {
356         Mockery mockery = new Mockery();
357 
358         final String indexUrl = repositoryUrl + ".index";
359         final Date contextTimestamp = df.parse( "20081125010000.000 -0600" );
360 
361         final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class );
362 
363         final IndexingContext tempContext = mockery.mock( IndexingContext.class );
364 
365         mockery.checking( new Expectations()
366         {
367             {
368                 allowing( tempContext ).getIndexDirectoryFile();
369                 will( new ReturnValueAction( testBasedir ) );
370 
371                 allowing( tempContext ).getTimestamp();
372                 will( returnValue( contextTimestamp ) );
373 
374                 allowing( tempContext ).getId();
375                 will( returnValue( repositoryId ) );
376 
377                 allowing( tempContext ).getIndexUpdateUrl();
378                 will( returnValue( indexUrl ) );
379 
380                 allowing( tempContext ).commit();
381 
382                 allowing( tempContext ).getIndexCreators();
383                 will( returnValue( DEFAULT_CREATORS ) );
384 
385                 allowing( tempContext ).commit();
386 
387                 oneOf( mockFetcher ).connect( repositoryId, indexUrl );
388 
389                 oneOf( mockFetcher ).retrieve( //
390                     with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) );
391                 will( new PropertiesAction()
392                 {
393                     @Override
394                     Properties getProperties()
395                     {
396                         Properties properties = new Properties();
397                         properties.setProperty( IndexingContext.INDEX_ID, "central" );
398                         properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081126010000.000 -0600" );
399                         return properties;
400                     }
401                 } );
402 
403                 allowing( tempContext ).getIndexDirectoryFile();
404 
405                 oneOf( mockFetcher ).retrieve( //
406                     with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) );
407                 will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) );
408 
409                 oneOf( tempContext ).replace( with( any( Directory.class ) ) );
410 
411                 oneOf( mockFetcher ).disconnect();
412             }
413         } );
414 
415         // tempContext.updateTimestamp( true, contextTimestamp );
416 
417         IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher );
418 
419         updater.fetchAndUpdateIndex( updateRequest );
420 
421         mockery.assertIsSatisfied();
422     }
423 
424     public void testIncrementalIndexUpdate()
425         throws Exception
426     {
427         Mockery mockery = new Mockery();
428 
429         final String indexUrl = repositoryUrl + ".index";
430         final Date contextTimestamp = df.parse( "20081128000000.000 -0600" );
431 
432         final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class );
433 
434         final IndexingContext tempContext = mockery.mock( IndexingContext.class );
435 
436         final Properties localProps = new Properties();
437         localProps.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "1" );
438         localProps.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" );
439 
440         mockery.checking( new Expectations()
441         {
442             {
443                 allowing( tempContext ).getTimestamp();
444                 will( returnValue( contextTimestamp ) );
445 
446                 allowing( tempContext ).getId();
447                 will( returnValue( repositoryId ) );
448 
449                 allowing( tempContext ).getIndexUpdateUrl();
450                 will( returnValue( indexUrl ) );
451 
452                 allowing( tempContext ).commit();
453 
454                 allowing( tempContext ).getIndexCreators();
455                 will( returnValue( DEFAULT_CREATORS ) );
456 
457                 oneOf( mockFetcher ).connect( repositoryId, indexUrl );
458 
459                 oneOf( mockFetcher ).retrieve( //
460                     with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) );
461                 will( new PropertiesAction()
462                 {
463                     @Override
464                     Properties getProperties()
465                     {
466                         Properties properties = new Properties();
467                         properties.setProperty( IndexingContext.INDEX_ID, "central" );
468                         properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" );
469                         properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" );
470                         properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" );
471                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" );
472                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" );
473                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" );
474                         return properties;
475                     }
476                 } );
477 
478                 allowing( tempContext ).getIndexDirectoryFile();
479                 will( new IndexDirectoryFileAction( localProps, testBasedir ) );
480 
481                 oneOf( mockFetcher ).retrieve( //
482                     with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) );
483                 will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) );
484                 oneOf( mockFetcher ).retrieve( //
485                     with( IndexingContext.INDEX_FILE_PREFIX + ".3.gz" ) );
486                 will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) );
487                 // could create index archive there and verify that it is merged correctly
488 
489                 oneOf( tempContext ).merge( with( any( Directory.class ) ) );
490 
491                 oneOf( tempContext ).merge( with( any( Directory.class ) ) );
492 
493                 oneOf( mockFetcher ).disconnect();
494             }
495         } );
496 
497         // tempContext.updateTimestamp( true, contextTimestamp );
498 
499         IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher );
500 
501         updater.fetchAndUpdateIndex( updateRequest );
502 
503         mockery.assertIsSatisfied();
504     }
505 
506     public void testIncrementalIndexUpdateNoCounter()
507         throws Exception
508     {
509         Mockery mockery = new Mockery();
510 
511         final String indexUrl = repositoryUrl + ".index";
512         final Date contextTimestamp = df.parse( "20081128000000.000 -0600" );
513 
514         final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class );
515 
516         final IndexingContext tempContext = mockery.mock( IndexingContext.class );
517 
518         mockery.checking( new Expectations()
519         {
520             {
521                 allowing( tempContext ).getIndexDirectoryFile();
522                 will( new ReturnValueAction( testBasedir ) );
523 
524                 allowing( tempContext ).getTimestamp();
525                 will( returnValue( contextTimestamp ) );
526 
527                 allowing( tempContext ).getId();
528                 will( returnValue( repositoryId ) );
529 
530                 allowing( tempContext ).getIndexUpdateUrl();
531                 will( returnValue( indexUrl ) );
532 
533                 allowing( tempContext ).commit();
534 
535                 allowing( tempContext ).getIndexCreators();
536                 will( returnValue( DEFAULT_CREATORS ) );
537 
538                 oneOf( mockFetcher ).connect( repositoryId, indexUrl );
539 
540                 oneOf( mockFetcher ).retrieve( //
541                     with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) );
542                 will( new PropertiesAction()
543                 {
544                     @Override
545                     Properties getProperties()
546                     {
547                         Properties properties = new Properties();
548                         properties.setProperty( IndexingContext.INDEX_ID, "central" );
549                         properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" );
550                         properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" );
551                         properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" );
552                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" );
553                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" );
554                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" );
555                         return properties;
556                     }
557                 } );
558 
559                 oneOf( mockFetcher ).retrieve( //
560                     with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) );
561                 will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) );
562                 // could create index archive there and verify that it is merged correctly
563 
564                 oneOf( tempContext ).replace( with( any( Directory.class ) ) );
565 
566                 never( mockFetcher ).retrieve( //
567                     with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) );
568 
569                 never( tempContext ).merge( with( any( Directory.class ) ) );
570 
571                 oneOf( mockFetcher ).disconnect();
572             }
573         } );
574 
575         // tempContext.updateTimestamp( true, contextTimestamp );
576 
577         IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher );
578 
579         updater.fetchAndUpdateIndex( updateRequest );
580 
581         mockery.assertIsSatisfied();
582     }
583 
584     public void testIncrementalIndexUpdateNoUpdateNecessary()
585         throws Exception
586     {
587         Mockery mockery = new Mockery();
588 
589         final String indexUrl = repositoryUrl + ".index";
590         final Date contextTimestamp = df.parse( "20081128000000.000 -0600" );
591 
592         final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class );
593 
594         final IndexingContext tempContext = mockery.mock( IndexingContext.class );
595 
596         final Properties localProps = new Properties();
597         localProps.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" );
598         localProps.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" );
599 
600         mockery.checking( new Expectations()
601         {
602             {
603                 allowing( tempContext ).getTimestamp();
604                 will( returnValue( contextTimestamp ) );
605 
606                 allowing( tempContext ).getId();
607                 will( returnValue( repositoryId ) );
608 
609                 allowing( tempContext ).getIndexUpdateUrl();
610                 will( returnValue( indexUrl ) );
611 
612                 allowing( tempContext ).getIndexCreators();
613                 will( returnValue( DEFAULT_CREATORS ) );
614 
615                 allowing( tempContext ).commit();
616 
617                 oneOf( mockFetcher ).connect( repositoryId, indexUrl );
618 
619                 oneOf( mockFetcher ).retrieve( //
620                     with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) );
621                 will( new PropertiesAction()
622                 {
623                     @Override
624                     Properties getProperties()
625                     {
626                         Properties properties = new Properties();
627                         properties.setProperty( IndexingContext.INDEX_ID, "central" );
628                         properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" );
629                         properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" );
630                         properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" );
631                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" );
632                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" );
633                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" );
634                         return properties;
635                     }
636                 } );
637 
638                 allowing( tempContext ).getIndexDirectoryFile();
639                 will( new IndexDirectoryFileAction( localProps, testBasedir ) );
640 
641                 never( mockFetcher ).retrieve( //
642                     with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) );
643                 // could create index archive there and verify that it is merged correctly
644 
645                 never( mockFetcher ).retrieve( //
646                     with( IndexingContext.INDEX_FILE_PREFIX + ".1.gz" ) );
647 
648                 never( mockFetcher ).retrieve( //
649                     with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) );
650 
651                 never( mockFetcher ).retrieve( //
652                     with( IndexingContext.INDEX_FILE_PREFIX + ".3.gz" ) );
653 
654                 never( tempContext ).merge( with( any( Directory.class ) ) );
655 
656                 never( tempContext ).replace( with( any( Directory.class ) ) );
657 
658                 oneOf( mockFetcher ).disconnect();
659             }
660         } );
661 
662         // tempContext.updateTimestamp( true, contextTimestamp );
663 
664         IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher );
665 
666         updater.fetchAndUpdateIndex( updateRequest );
667 
668         mockery.assertIsSatisfied();
669     }
670 
671     public void testUpdateForceFullUpdate()
672         throws Exception
673     {
674         Mockery mockery = new Mockery();
675 
676         final String indexUrl = repositoryUrl + ".index";
677         final Date contextTimestamp = df.parse( "20081128000000.000 -0600" );
678 
679         final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class );
680 
681         final IndexingContext tempContext = mockery.mock( IndexingContext.class );
682 
683         mockery.checking( new Expectations()
684         {
685             {
686                 allowing( tempContext ).getIndexDirectoryFile();
687                 will( new ReturnValueAction( testBasedir ) );
688 
689                 allowing( tempContext ).getTimestamp();
690                 will( returnValue( contextTimestamp ) );
691 
692                 allowing( tempContext ).getId();
693                 will( returnValue( repositoryId ) );
694 
695                 allowing( tempContext ).getIndexUpdateUrl();
696                 will( returnValue( indexUrl ) );
697 
698                 allowing( tempContext ).commit();
699 
700                 allowing( tempContext ).getIndexCreators();
701                 will( returnValue( DEFAULT_CREATORS ) );
702 
703                 oneOf( mockFetcher ).connect( repositoryId, indexUrl );
704 
705                 oneOf( mockFetcher ).retrieve( //
706                     with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) );
707                 will( new PropertiesAction()
708                 {
709                     @Override
710                     Properties getProperties()
711                     {
712                         Properties properties = new Properties();
713                         properties.setProperty( IndexingContext.INDEX_ID, "central" );
714                         properties.setProperty( IndexingContext.INDEX_TIMESTAMP, "20081129174241.859 -0600" );
715                         properties.setProperty( IndexingContext.INDEX_CHUNK_COUNTER, "3" );
716                         properties.setProperty( IndexingContext.INDEX_CHAIN_ID, "someid" );
717                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "0", "3" );
718                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "1", "2" );
719                         properties.setProperty( IndexingContext.INDEX_CHUNK_PREFIX + "2", "1" );
720                         return properties;
721                     }
722                 } );
723 
724                 never( tempContext ).getIndexDirectoryFile();
725 
726                 never( mockFetcher ).retrieve( //
727                     with( IndexingContext.INDEX_FILE_PREFIX + ".1.gz" ) );
728 
729                 never( mockFetcher ).retrieve( //
730                     with( IndexingContext.INDEX_FILE_PREFIX + ".2.gz" ) );
731 
732                 never( mockFetcher ).retrieve( //
733                     with( IndexingContext.INDEX_FILE_PREFIX + ".3.gz" ) );
734 
735                 oneOf( mockFetcher ).retrieve( with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) );
736                 will( returnValue( newInputStream( "/index-updater/server-root/nexus-maven-repository-index.gz" ) ) );
737 
738                 never( tempContext ).merge( with( any( Directory.class ) ) );
739 
740                 never( tempContext ).merge( with( any( Directory.class ) ) );
741 
742                 oneOf( tempContext ).replace( with( any( Directory.class ) ) );
743 
744                 oneOf( mockFetcher ).disconnect();
745             }
746         } );
747 
748         // tempContext.updateTimestamp( true, contextTimestamp );
749 
750         IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher );
751 
752         updateRequest.setForceFullUpdate( true );
753 
754         updater.fetchAndUpdateIndex( updateRequest );
755 
756         mockery.assertIsSatisfied();
757     }
758 
759     public void testUpdateForceFullUpdateNoGZ()
760         throws Exception
761     {
762         Mockery mockery = new Mockery();
763 
764         final String indexUrl = repositoryUrl + ".index";
765         final Date contextTimestamp = df.parse( "20081128000000.000 -0600" );
766 
767         final ResourceFetcher mockFetcher = mockery.mock( ResourceFetcher.class );
768 
769         final IndexingContext tempContext = mockery.mock( IndexingContext.class );
770 
771         mockery.checking( new Expectations()
772         {
773             {
774                 allowing( tempContext ).getIndexDirectoryFile();
775                 will( new ReturnValueAction( testBasedir ) );
776 
777                 allowing( tempContext ).getTimestamp();
778                 will( returnValue( contextTimestamp ) );
779 
780                 allowing( tempContext ).commit();
781 
782                 allowing( tempContext ).getId();
783                 will( returnValue( repositoryId ) );
784 
785                 allowing( tempContext ).getIndexUpdateUrl();
786                 will( returnValue( indexUrl ) );
787 
788                 allowing( tempContext ).getIndexCreators();
789                 will( returnValue( DEFAULT_CREATORS ) );
790 
791                 oneOf( mockFetcher ).connect( repositoryId, indexUrl );
792 
793                 oneOf( mockFetcher ).retrieve( //
794                     with( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ) );
795                 will( new PropertiesAction()
796                 {
797                     @Override
798                     Properties getProperties()
799                     {
800                         Properties properties = new Properties();
801                         properties.setProperty( IndexingContext.INDEX_ID, "central" );
802                         properties.setProperty( IndexingContext.INDEX_LEGACY_TIMESTAMP, "20081129174241.859 -0600" );
803                         return properties;
804                     }
805                 } );
806 
807                 never( tempContext ).getIndexDirectoryFile();
808 
809                 oneOf( mockFetcher ).retrieve( with( IndexingContext.INDEX_FILE_PREFIX + ".gz" ) );
810 
811                 will( throwException( new IOException() ) );
812 
813                 oneOf( mockFetcher ).retrieve( with( IndexingContext.INDEX_FILE_PREFIX + ".zip" ) );
814 
815                 will( returnValue( newInputStream( "/index-updater/server-root/legacy/nexus-maven-repository-index.zip" ) ) );
816 
817                 never( tempContext ).merge( with( any( Directory.class ) ) );
818 
819                 never( tempContext ).merge( with( any( Directory.class ) ) );
820 
821                 oneOf( tempContext ).replace( with( any( Directory.class ) ) );
822 
823                 oneOf( mockFetcher ).disconnect();
824             }
825         } );
826 
827         // tempContext.updateTimestamp( true, contextTimestamp );
828 
829         IndexUpdateRequest updateRequest = new IndexUpdateRequest( tempContext, mockFetcher );
830 
831         updateRequest.setForceFullUpdate( true );
832 
833         updater.fetchAndUpdateIndex( updateRequest );
834 
835         mockery.assertIsSatisfied();
836     }
837 
838     protected InputStream newInputStream( String path )
839     {
840         return getResourceAsStream( path );
841     }
842 
843     abstract static class PropertiesAction
844         extends VoidAction
845     {
846         @Override
847         public Object invoke( Invocation invocation )
848             throws Throwable
849         {
850             Properties properties = getProperties();
851 
852             ByteArrayOutputStream buf = new ByteArrayOutputStream();
853             try
854             {
855                 properties.store( buf, null );
856                 buf.flush();
857             }
858             finally
859             {
860                 IOUtil.close( buf );
861             }
862 
863             return new ByteArrayInputStream( buf.toByteArray() );
864         }
865 
866         abstract Properties getProperties();
867     }
868 
869     private static class IndexDirectoryFileAction
870         extends VoidAction
871     {
872         File file = null;
873 
874         public IndexDirectoryFileAction( Properties properties, File basedir )
875             throws Exception
876         {
877             basedir.mkdirs();
878 
879             this.file = new File( basedir, IndexingContext.INDEX_UPDATER_PROPERTIES_FILE );
880 
881             FileOutputStream fos = null;
882             try
883             {
884                 fos = new FileOutputStream( this.file );
885 
886                 properties.store( fos, "" );
887             }
888             finally
889             {
890                 IOUtil.close( fos );
891             }
892         }
893 
894         @Override
895         public Object invoke( Invocation invocation )
896             throws Throwable
897         {
898             return this.file.getParentFile();
899         }
900     }
901 }