View Javadoc
1   package org.eclipse.aether.connector.basic;
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 static org.junit.Assert.*;
23  
24  import java.io.File;
25  import java.io.IOException;
26  import java.net.URI;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.HashMap;
30  import java.util.LinkedHashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  import org.eclipse.aether.internal.test.util.TestFileProcessor;
35  import org.eclipse.aether.internal.test.util.TestFileUtils;
36  import org.eclipse.aether.internal.test.util.TestLoggerFactory;
37  import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
38  import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
39  import org.eclipse.aether.transfer.ChecksumFailureException;
40  import org.junit.Before;
41  import org.junit.Test;
42  
43  public class ChecksumValidatorTest
44  {
45  
46      private static class StubChecksumPolicy
47          implements ChecksumPolicy
48      {
49  
50          boolean inspectAll;
51  
52          boolean tolerateFailure;
53  
54          private List<String> callbacks = new ArrayList<String>();
55  
56          private Object conclusion;
57  
58          public boolean onChecksumMatch( String algorithm, int kind )
59          {
60              callbacks.add( String.format( "match(%s, %04x)", algorithm, kind ) );
61              if ( inspectAll )
62              {
63                  if ( conclusion == null )
64                  {
65                      conclusion = true;
66                  }
67                  return false;
68              }
69              return true;
70          }
71  
72          public void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception )
73              throws ChecksumFailureException
74          {
75              callbacks.add( String.format( "mismatch(%s, %04x)", algorithm, kind ) );
76              if ( inspectAll )
77              {
78                  conclusion = exception;
79                  return;
80              }
81              throw exception;
82          }
83  
84          public void onChecksumError( String algorithm, int kind, ChecksumFailureException exception )
85              throws ChecksumFailureException
86          {
87              callbacks.add( String.format( "error(%s, %04x, %s)", algorithm, kind, exception.getCause().getMessage() ) );
88          }
89  
90          public void onNoMoreChecksums()
91              throws ChecksumFailureException
92          {
93              callbacks.add( String.format( "noMore()" ) );
94              if ( conclusion instanceof ChecksumFailureException )
95              {
96                  throw (ChecksumFailureException) conclusion;
97              }
98              else if ( !Boolean.TRUE.equals( conclusion ) )
99              {
100                 throw new ChecksumFailureException( "no checksums" );
101             }
102         }
103 
104         public void onTransferRetry()
105         {
106             callbacks.add( String.format( "retry()" ) );
107         }
108 
109         public boolean onTransferChecksumFailure( ChecksumFailureException exception )
110         {
111             callbacks.add( String.format( "fail(%s)", exception.getMessage() ) );
112             return tolerateFailure;
113         }
114 
115         void assertCallbacks( String... callbacks )
116         {
117             assertEquals( Arrays.asList( callbacks ), this.callbacks );
118         }
119 
120     }
121 
122     private static class StubChecksumFetcher
123         implements ChecksumValidator.ChecksumFetcher
124     {
125 
126         Map<URI, Object> checksums = new HashMap<URI, Object>();
127 
128         List<File> checksumFiles = new ArrayList<File>();
129 
130         private List<URI> fetchedFiles = new ArrayList<URI>();
131 
132         public boolean fetchChecksum( URI remote, File local )
133             throws Exception
134         {
135             fetchedFiles.add( remote );
136             Object checksum = checksums.get( remote );
137             if ( checksum == null )
138             {
139                 return false;
140             }
141             if ( checksum instanceof Exception )
142             {
143                 throw (Exception) checksum;
144             }
145             TestFileUtils.writeString( local, checksum.toString() );
146             checksumFiles.add( local );
147             return true;
148         }
149 
150         void mock( String algo, Object value )
151         {
152             checksums.put( toUri( algo ), value );
153         }
154 
155         void assertFetchedFiles( String... algos )
156         {
157             List<URI> expected = new ArrayList<URI>();
158             for ( String algo : algos )
159             {
160                 expected.add( toUri( algo ) );
161             }
162             assertEquals( expected, fetchedFiles );
163         }
164 
165         private static URI toUri( String algo )
166         {
167             return newChecksum( algo ).getLocation();
168         }
169 
170     }
171 
172     private static final String SHA1 = "SHA-1";
173 
174     private static final String MD5 = "MD5";
175 
176     private StubChecksumPolicy policy;
177 
178     private StubChecksumFetcher fetcher;
179 
180     private File dataFile;
181 
182     private static RepositoryLayout.Checksum newChecksum( String algo )
183     {
184         return RepositoryLayout.Checksum.forLocation( URI.create( "file" ), algo );
185     }
186 
187     private List<RepositoryLayout.Checksum> newChecksums( String... algos )
188     {
189         List<RepositoryLayout.Checksum> checksums = new ArrayList<RepositoryLayout.Checksum>();
190         for ( String algo : algos )
191         {
192             checksums.add( newChecksum( algo ) );
193         }
194         return checksums;
195     }
196 
197     private ChecksumValidator newValidator( String... algos )
198     {
199         return new ChecksumValidator( new TestLoggerFactory().getLogger( "" ), dataFile, new TestFileProcessor(),
200                                       fetcher, policy, newChecksums( algos ) );
201     }
202 
203     private Map<String, ?> checksums( String... algoDigestPairs )
204     {
205         Map<String, Object> checksums = new LinkedHashMap<String, Object>();
206         for ( int i = 0; i < algoDigestPairs.length; i += 2 )
207         {
208             String algo = algoDigestPairs[i];
209             String digest = algoDigestPairs[i + 1];
210             if ( digest == null )
211             {
212                 checksums.put( algo, new IOException( "error" ) );
213             }
214             else
215             {
216                 checksums.put( algo, digest );
217             }
218         }
219         return checksums;
220     }
221 
222     @Before
223     public void init()
224         throws Exception
225     {
226         dataFile = TestFileUtils.createTempFile( "" );
227         dataFile.delete();
228         policy = new StubChecksumPolicy();
229         fetcher = new StubChecksumFetcher();
230     }
231 
232     @Test
233     public void testValidate_NullPolicy()
234         throws Exception
235     {
236         policy = null;
237         ChecksumValidator validator = newValidator( SHA1 );
238         validator.validate( checksums( SHA1, "ignored" ), null );
239         fetcher.assertFetchedFiles();
240     }
241 
242     @Test
243     public void testValidate_AcceptOnFirstMatch()
244         throws Exception
245     {
246         ChecksumValidator validator = newValidator( SHA1 );
247         fetcher.mock( SHA1, "foo" );
248         validator.validate( checksums( SHA1, "foo" ), null );
249         fetcher.assertFetchedFiles( SHA1 );
250         policy.assertCallbacks( "match(SHA-1, 0000)" );
251     }
252 
253     @Test
254     public void testValidate_FailOnFirstMismatch()
255         throws Exception
256     {
257         ChecksumValidator validator = newValidator( SHA1 );
258         fetcher.mock( SHA1, "foo" );
259         try
260         {
261             validator.validate( checksums( SHA1, "not-foo" ), null );
262             fail( "expected exception" );
263         }
264         catch ( ChecksumFailureException e )
265         {
266             assertEquals( "foo", e.getExpected() );
267             assertEquals( "not-foo", e.getActual() );
268             assertTrue( e.isRetryWorthy() );
269         }
270         fetcher.assertFetchedFiles( SHA1 );
271         policy.assertCallbacks( "mismatch(SHA-1, 0000)" );
272     }
273 
274     @Test
275     public void testValidate_AcceptOnEnd()
276         throws Exception
277     {
278         policy.inspectAll = true;
279         ChecksumValidator validator = newValidator( SHA1, MD5 );
280         fetcher.mock( SHA1, "foo" );
281         fetcher.mock( MD5, "bar" );
282         validator.validate( checksums( SHA1, "foo", MD5, "bar" ), null );
283         fetcher.assertFetchedFiles( SHA1, MD5 );
284         policy.assertCallbacks( "match(SHA-1, 0000)", "match(MD5, 0000)", "noMore()" );
285     }
286 
287     @Test
288     public void testValidate_FailOnEnd()
289         throws Exception
290     {
291         policy.inspectAll = true;
292         ChecksumValidator validator = newValidator( SHA1, MD5 );
293         fetcher.mock( SHA1, "foo" );
294         fetcher.mock( MD5, "bar" );
295         try
296         {
297             validator.validate( checksums( SHA1, "not-foo", MD5, "bar" ), null );
298             fail( "expected exception" );
299         }
300         catch ( ChecksumFailureException e )
301         {
302             assertEquals( "foo", e.getExpected() );
303             assertEquals( "not-foo", e.getActual() );
304             assertTrue( e.isRetryWorthy() );
305         }
306         fetcher.assertFetchedFiles( SHA1, MD5 );
307         policy.assertCallbacks( "mismatch(SHA-1, 0000)", "match(MD5, 0000)", "noMore()" );
308     }
309 
310     @Test
311     public void testValidate_InlinedBeforeExternal()
312         throws Exception
313     {
314         policy.inspectAll = true;
315         ChecksumValidator validator = newValidator( SHA1, MD5 );
316         fetcher.mock( SHA1, "foo" );
317         fetcher.mock( MD5, "bar" );
318         validator.validate( checksums( SHA1, "foo", MD5, "bar" ), checksums( SHA1, "foo", MD5, "bar" ) );
319         fetcher.assertFetchedFiles( SHA1, MD5 );
320         policy.assertCallbacks( "match(SHA-1, 0001)", "match(MD5, 0001)", "match(SHA-1, 0000)", "match(MD5, 0000)",
321                                 "noMore()" );
322     }
323 
324     @Test
325     public void testValidate_CaseInsensitive()
326         throws Exception
327     {
328         policy.inspectAll = true;
329         ChecksumValidator validator = newValidator( SHA1 );
330         fetcher.mock( SHA1, "FOO" );
331         validator.validate( checksums( SHA1, "foo" ), checksums( SHA1, "foo" ) );
332         policy.assertCallbacks( "match(SHA-1, 0001)", "match(SHA-1, 0000)", "noMore()" );
333     }
334 
335     @Test
336     public void testValidate_MissingRemoteChecksum()
337         throws Exception
338     {
339         ChecksumValidator validator = newValidator( SHA1, MD5 );
340         fetcher.mock( MD5, "bar" );
341         validator.validate( checksums( MD5, "bar" ), null );
342         fetcher.assertFetchedFiles( SHA1, MD5 );
343         policy.assertCallbacks( "match(MD5, 0000)" );
344     }
345 
346     @Test
347     public void testValidate_InaccessibleRemoteChecksum()
348         throws Exception
349     {
350         ChecksumValidator validator = newValidator( SHA1, MD5 );
351         fetcher.mock( SHA1, new IOException( "inaccessible" ) );
352         fetcher.mock( MD5, "bar" );
353         validator.validate( checksums( MD5, "bar" ), null );
354         fetcher.assertFetchedFiles( SHA1, MD5 );
355         policy.assertCallbacks( "error(SHA-1, 0000, inaccessible)", "match(MD5, 0000)" );
356     }
357 
358     @Test
359     public void testValidate_InaccessibleLocalChecksum()
360         throws Exception
361     {
362         ChecksumValidator validator = newValidator( SHA1, MD5 );
363         fetcher.mock( SHA1, "foo" );
364         fetcher.mock( MD5, "bar" );
365         validator.validate( checksums( SHA1, null, MD5, "bar" ), null );
366         fetcher.assertFetchedFiles( MD5 );
367         policy.assertCallbacks( "error(SHA-1, 0000, error)", "match(MD5, 0000)" );
368     }
369 
370     @Test
371     public void testHandle_Accept()
372         throws Exception
373     {
374         policy.tolerateFailure = true;
375         ChecksumValidator validator = newValidator( SHA1 );
376         assertEquals( true, validator.handle( new ChecksumFailureException( "accept" ) ) );
377         policy.assertCallbacks( "fail(accept)" );
378     }
379 
380     @Test
381     public void testHandle_Reject()
382         throws Exception
383     {
384         policy.tolerateFailure = false;
385         ChecksumValidator validator = newValidator( SHA1 );
386         assertEquals( false, validator.handle( new ChecksumFailureException( "reject" ) ) );
387         policy.assertCallbacks( "fail(reject)" );
388     }
389 
390     @Test
391     public void testRetry_ResetPolicy()
392         throws Exception
393     {
394         ChecksumValidator validator = newValidator( SHA1 );
395         validator.retry();
396         policy.assertCallbacks( "retry()" );
397     }
398 
399     @Test
400     public void testRetry_RemoveTempFiles()
401         throws Exception
402     {
403         ChecksumValidator validator = newValidator( SHA1 );
404         fetcher.mock( SHA1, "foo" );
405         validator.validate( checksums( SHA1, "foo" ), null );
406         fetcher.assertFetchedFiles( SHA1 );
407         assertEquals( 1, fetcher.checksumFiles.size() );
408         for ( File file : fetcher.checksumFiles )
409         {
410             assertTrue( file.getAbsolutePath(), file.isFile() );
411         }
412         validator.retry();
413         for ( File file : fetcher.checksumFiles )
414         {
415             assertFalse( file.getAbsolutePath(), file.exists() );
416         }
417     }
418 
419     @Test
420     public void testCommit_SaveChecksumFiles()
421         throws Exception
422     {
423         policy.inspectAll = true;
424         ChecksumValidator validator = newValidator( SHA1, MD5 );
425         fetcher.mock( MD5, "bar" );
426         validator.validate( checksums( SHA1, "foo", MD5, "bar" ), checksums( SHA1, "foo" ) );
427         assertEquals( 1, fetcher.checksumFiles.size() );
428         for ( File file : fetcher.checksumFiles )
429         {
430             assertTrue( file.getAbsolutePath(), file.isFile() );
431         }
432         validator.commit();
433         File checksumFile = new File( dataFile.getPath() + ".sha1" );
434         assertTrue( checksumFile.getAbsolutePath(), checksumFile.isFile() );
435         assertEquals( "foo", TestFileUtils.readString( checksumFile ) );
436         checksumFile = new File( dataFile.getPath() + ".md5" );
437         assertTrue( checksumFile.getAbsolutePath(), checksumFile.isFile() );
438         assertEquals( "bar", TestFileUtils.readString( checksumFile ) );
439         for ( File file : fetcher.checksumFiles )
440         {
441             assertFalse( file.getAbsolutePath(), file.exists() );
442         }
443     }
444 
445     @Test
446     public void testClose_RemoveTempFiles()
447         throws Exception
448     {
449         ChecksumValidator validator = newValidator( SHA1 );
450         fetcher.mock( SHA1, "foo" );
451         validator.validate( checksums( SHA1, "foo" ), null );
452         fetcher.assertFetchedFiles( SHA1 );
453         assertEquals( 1, fetcher.checksumFiles.size() );
454         for ( File file : fetcher.checksumFiles )
455         {
456             assertTrue( file.getAbsolutePath(), file.isFile() );
457         }
458         validator.close();
459         for ( File file : fetcher.checksumFiles )
460         {
461             assertFalse( file.getAbsolutePath(), file.exists() );
462         }
463     }
464 
465 }