1 package org.eclipse.aether.connector.basic;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 }