1 package org.apache.maven.it;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import junit.framework.TestCase;
23 import org.apache.maven.artifact.versioning.ArtifactVersion;
24 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
25 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
26 import org.apache.maven.artifact.versioning.VersionRange;
27 import org.apache.maven.shared.utils.io.FileUtils;
28
29 import java.io.File;
30 import java.io.IOException;
31 import java.io.PrintStream;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.nio.file.Paths;
35 import java.text.DecimalFormat;
36 import java.text.DecimalFormatSymbols;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Locale;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
42
43
44
45
46
47 public abstract class AbstractMavenIntegrationTestCase
48 extends TestCase
49 {
50
51
52
53 private static PrintStream out = System.out;
54
55
56
57
58 private static final DecimalFormat SECS_FORMAT =
59 new DecimalFormat( "(0.0 s)", new DecimalFormatSymbols( Locale.ENGLISH ) );
60
61
62
63
64 private static final int RESULT_COLUMN = 60;
65
66 private boolean skip;
67
68 private BrokenMavenVersionException invert;
69
70 private static ArtifactVersion javaVersion;
71
72 private ArtifactVersion mavenVersion;
73
74 private VersionRange versionRange;
75
76 private String matchPattern;
77
78 private static final String DEFAULT_MATCH_PATTERN = "(.*?)-(RC[0-9]+|SNAPSHOT|RC[0-9]+-SNAPSHOT)";
79
80 protected static final String ALL_MAVEN_VERSIONS = "[2.0,)";
81
82 protected AbstractMavenIntegrationTestCase( String versionRangeStr )
83 {
84 this( versionRangeStr, DEFAULT_MATCH_PATTERN );
85 }
86
87 protected AbstractMavenIntegrationTestCase( String versionRangeStr, String matchPattern )
88 {
89 this.matchPattern = matchPattern;
90
91 try
92 {
93 versionRange = VersionRange.createFromVersionSpec( versionRangeStr );
94 }
95 catch ( InvalidVersionSpecificationException e )
96 {
97 throw (RuntimeException) new IllegalArgumentException( "Invalid version range: " + versionRangeStr, e );
98 }
99
100 ArtifactVersion version = getMavenVersion();
101 if ( version != null )
102 {
103 skip = !versionRange.containsVersion( removePattern( version ) );
104 }
105 else
106 {
107 out.println( "WARNING: " + getITName() + ": version range '" + versionRange
108 + "' supplied but no Maven version - not skipping test." );
109 }
110 }
111
112
113
114
115
116
117 private ArtifactVersion getJavaVersion()
118 {
119 if ( javaVersion == null )
120 {
121 String version = System.getProperty( "java.version" );
122 version = version.replaceAll( "[_-]", "." );
123 Matcher matcher = Pattern.compile( "(?s).*?(([0-9]+\\.[0-9]+)(\\.[0-9]+)?).*" ).matcher( version );
124 if ( matcher.matches() )
125 {
126 version = matcher.group( 1 );
127 }
128 javaVersion = new DefaultArtifactVersion( version );
129 }
130 return javaVersion;
131 }
132
133
134
135
136
137
138 protected final ArtifactVersion getMavenVersion()
139 {
140 if ( mavenVersion == null )
141 {
142 String version = System.getProperty( "maven.version", "" );
143
144 if ( version.length() <= 0 || version.startsWith( "${" ) )
145 {
146 try
147 {
148 Verifier verifier = new Verifier( "" );
149 try
150 {
151 version = verifier.getMavenVersion();
152 System.setProperty( "maven.version", version );
153 }
154 finally
155 {
156 verifier.resetStreams();
157 }
158 }
159 catch ( VerificationException e )
160 {
161 e.printStackTrace();
162 }
163 }
164
165
166 if ( version != null && version.length() > 0 && !version.startsWith( "${" ) )
167 {
168 mavenVersion = new DefaultArtifactVersion( version );
169 }
170 }
171 return mavenVersion;
172 }
173
174
175
176
177
178
179 protected boolean matchesVersionRange( String versionRangeStr )
180 {
181 VersionRange versionRange;
182 try
183 {
184 versionRange = VersionRange.createFromVersionSpec( versionRangeStr );
185 }
186 catch ( InvalidVersionSpecificationException e )
187 {
188 throw (RuntimeException) new IllegalArgumentException( "Invalid version range: " + versionRangeStr, e );
189 }
190
191 ArtifactVersion version = getMavenVersion();
192 if ( version != null )
193 {
194 return versionRange.containsVersion( removePattern( version ) );
195 }
196 else
197 {
198 out.println( "WARNING: " + getITName() + ": version range '" + versionRange
199 + "' supplied but no Maven version found - returning true for match check." );
200
201 return true;
202 }
203 }
204
205
206
207
208
209
210 protected final boolean isSkipped()
211 {
212 return skip;
213 }
214
215 protected void runTest()
216 throws Throwable
217 {
218 String testName = getTestName();
219
220 if ( testName.startsWith( "mng" ) || Character.isDigit( testName.charAt( 0 ) ) )
221 {
222 int mng = 4;
223 while ( Character.isDigit( testName.charAt( mng ) ) )
224 {
225 mng++;
226 }
227 out.print( AnsiSupport.bold( testName.substring( 0, mng ) ) );
228 out.print( ' ' );
229 out.print( testName.substring( mng ) );
230 }
231 else
232 {
233 int index = testName.indexOf( ' ' );
234 if ( index == -1 )
235 {
236 out.print( testName );
237 }
238 else
239 {
240 out.print( AnsiSupport.bold( testName.substring( 0, index ) ) );
241 out.print( testName.substring( index ) );
242 }
243 out.print( '.' );
244 }
245
246 out.print( pad( RESULT_COLUMN - testName.length() ) );
247 out.print( ' ' );
248
249 if ( skip )
250 {
251 out.println( AnsiSupport.warning( "SKIPPED" ) + " - Maven version " + getMavenVersion() + " not in range "
252 + versionRange );
253 return;
254 }
255
256 if ( "true".equals( System.getProperty( "useEmptyLocalRepository", "false" ) ) )
257 {
258 setupLocalRepo();
259 }
260
261 invert = null;
262 long milliseconds = System.currentTimeMillis();
263 try
264 {
265 super.runTest();
266 milliseconds = System.currentTimeMillis() - milliseconds;
267 if ( invert != null )
268 {
269 throw invert;
270 }
271 out.println( AnsiSupport.success( "OK" ) + " " + formatTime( milliseconds ) );
272 }
273 catch ( UnsupportedJavaVersionException e )
274 {
275 out.println( AnsiSupport.warning( "SKIPPED" ) + " - Java version " + e.javaVersion + " not in range "
276 + e.supportedRange );
277 return;
278 }
279 catch ( UnsupportedMavenVersionException e )
280 {
281 out.println( AnsiSupport.warning( "SKIPPED" ) + " - Maven version " + e.mavenVersion + " not in range "
282 + e.supportedRange );
283 return;
284 }
285 catch ( BrokenMavenVersionException e )
286 {
287 out.println( AnsiSupport.error( "UNEXPECTED OK" ) + " - Maven version " + e.mavenVersion
288 + " expected to fail " + formatTime( milliseconds ) );
289 fail( "Expected failure when with Maven version " + e.mavenVersion );
290 }
291 catch ( Throwable t )
292 {
293 milliseconds = System.currentTimeMillis() - milliseconds;
294 if ( invert != null )
295 {
296 out.println( AnsiSupport.success( "EXPECTED FAIL" ) + " - Maven version " + invert.mavenVersion
297 + " expected to fail " + formatTime( milliseconds ) );
298 }
299 else
300 {
301 out.println( AnsiSupport.error( "FAILURE" ) + " " + formatTime( milliseconds ) );
302 throw t;
303 }
304 }
305 }
306
307
308
309
310
311
312
313
314
315 protected void requiresJavaVersion( String versionRange )
316 {
317 VersionRange range;
318 try
319 {
320 range = VersionRange.createFromVersionSpec( versionRange );
321 }
322 catch ( InvalidVersionSpecificationException e )
323 {
324 throw (RuntimeException) new IllegalArgumentException( "Invalid version range: " + versionRange, e );
325 }
326
327 ArtifactVersion version = getJavaVersion();
328 if ( !range.containsVersion( version ) )
329 {
330 throw new UnsupportedJavaVersionException( version, range );
331 }
332 }
333
334
335
336
337
338
339
340
341
342 protected void requiresMavenVersion( String versionRange )
343 {
344 VersionRange range;
345 try
346 {
347 range = VersionRange.createFromVersionSpec( versionRange );
348 }
349 catch ( InvalidVersionSpecificationException e )
350 {
351 throw (RuntimeException) new IllegalArgumentException( "Invalid version range: " + versionRange, e );
352 }
353
354 ArtifactVersion version = getMavenVersion();
355 if ( version != null )
356 {
357 if ( !range.containsVersion( removePattern( version ) ) )
358 {
359 throw new UnsupportedMavenVersionException( version, range );
360 }
361 }
362 else
363 {
364 out.println( "WARNING: " + getITName() + ": version range '" + versionRange
365 + "' supplied but no Maven version found - not skipping test." );
366 }
367 }
368
369
370
371
372
373
374
375
376
377 protected void failingMavenVersions( String versionRange )
378 {
379 assertNull( "Only call failingMavenVersions at most once per test", invert );
380 VersionRange range;
381 try
382 {
383 range = VersionRange.createFromVersionSpec( versionRange );
384 }
385 catch ( InvalidVersionSpecificationException e )
386 {
387 throw (RuntimeException) new IllegalArgumentException( "Invalid version range: " + versionRange, e );
388 }
389
390 ArtifactVersion version = getMavenVersion();
391 if ( version != null )
392 {
393 if ( range.containsVersion( removePattern( version ) ) )
394 {
395 invert = new BrokenMavenVersionException( version, range );
396 }
397 }
398 else
399 {
400 out.println( "WARNING: " + getITName() + ": version range '" + versionRange
401 + "' supplied but no Maven version found - not marking test as expected to fail." );
402 }
403 }
404
405 private class UnsupportedJavaVersionException
406 extends RuntimeException
407 {
408 @SuppressWarnings( "checkstyle:visibilitymodifier" )
409 public ArtifactVersion javaVersion;
410
411 @SuppressWarnings( "checkstyle:visibilitymodifier" )
412 public VersionRange supportedRange;
413
414 private UnsupportedJavaVersionException( ArtifactVersion javaVersion, VersionRange supportedRange )
415 {
416 this.javaVersion = javaVersion;
417 this.supportedRange = supportedRange;
418 }
419
420 }
421
422 private class UnsupportedMavenVersionException
423 extends RuntimeException
424 {
425 @SuppressWarnings( "checkstyle:visibilitymodifier" )
426 public ArtifactVersion mavenVersion;
427
428 @SuppressWarnings( "checkstyle:visibilitymodifier" )
429 public VersionRange supportedRange;
430
431 private UnsupportedMavenVersionException( ArtifactVersion mavenVersion, VersionRange supportedRange )
432 {
433 this.mavenVersion = mavenVersion;
434 this.supportedRange = supportedRange;
435 }
436
437 }
438
439 private class BrokenMavenVersionException
440 extends RuntimeException
441 {
442 @SuppressWarnings( "checkstyle:visibilitymodifier" )
443 public ArtifactVersion mavenVersion;
444
445 @SuppressWarnings( "checkstyle:visibilitymodifier" )
446 public VersionRange supportedRange;
447
448 private BrokenMavenVersionException( ArtifactVersion mavenVersion, VersionRange supportedRange )
449 {
450 this.mavenVersion = mavenVersion;
451 this.supportedRange = supportedRange;
452 }
453
454 }
455
456 private String getITName()
457 {
458 String simpleName = getClass().getName();
459 int idx = simpleName.lastIndexOf( '.' );
460 simpleName = idx >= 0 ? simpleName.substring( idx + 1 ) : simpleName;
461 simpleName = simpleName.startsWith( "MavenIT" ) ? simpleName.substring( "MavenIT".length() ) : simpleName;
462 simpleName = simpleName.endsWith( "Test" ) ? simpleName.substring( 0, simpleName.length() - 4 ) : simpleName;
463 return simpleName;
464 }
465
466 private String getTestName()
467 {
468 String className = getITName();
469 String methodName = getName();
470 if ( methodName.startsWith( "test" ) )
471 {
472 methodName = methodName.substring( 4 );
473 }
474 return className + '.' + methodName + "()";
475 }
476
477 private String pad( int chars )
478 {
479 StringBuilder buffer = new StringBuilder( 128 );
480 for ( int i = 0; i < chars; i++ )
481 {
482 buffer.append( '.' );
483 }
484 return buffer.toString();
485 }
486
487 private String formatTime( long milliseconds )
488 {
489 return SECS_FORMAT.format( milliseconds / 1000.0 );
490 }
491
492 protected File setupLocalRepo()
493 throws IOException
494 {
495 String tempDirPath = System.getProperty( "maven.it.tmpdir", System.getProperty( "java.io.tmpdir" ) );
496 File localRepo = new File( tempDirPath, "local-repository/" + getITName() );
497 if ( localRepo.isDirectory() )
498 {
499 FileUtils.deleteDirectory( localRepo );
500 }
501
502 System.setProperty( "maven.repo.local", localRepo.getAbsolutePath() );
503
504 return localRepo;
505 }
506
507 ArtifactVersion removePattern( ArtifactVersion version )
508 {
509 String v = version.toString();
510
511 Matcher m = Pattern.compile( matchPattern ).matcher( v );
512
513 if ( m.matches() )
514 {
515 return new DefaultArtifactVersion( m.group( 1 ) );
516 }
517 return version;
518 }
519
520 protected Verifier newVerifier( String basedir )
521 throws VerificationException
522 {
523 return newVerifier( basedir, false );
524 }
525
526 protected Verifier newVerifier( String basedir, String settings )
527 throws VerificationException
528 {
529 return newVerifier( basedir, settings, false );
530 }
531
532 protected Verifier newVerifier( String basedir, boolean debug )
533 throws VerificationException
534 {
535 return newVerifier( basedir, "", debug );
536 }
537
538 protected Verifier newVerifier( String basedir, String settings, boolean debug )
539 throws VerificationException
540 {
541 Verifier verifier = new Verifier( basedir, debug );
542
543 verifier.setAutoclean( false );
544
545 if ( settings != null )
546 {
547 File settingsFile;
548 if ( settings.length() > 0 )
549 {
550 settingsFile = new File( "settings-" + settings + ".xml" );
551 }
552 else
553 {
554 settingsFile = new File( "settings.xml" );
555 }
556
557 if ( !settingsFile.isAbsolute() )
558 {
559 String settingsDir = System.getProperty( "maven.it.global-settings.dir", "" );
560 if ( settingsDir.length() > 0 )
561 {
562 settingsFile = new File( settingsDir, settingsFile.getPath() );
563 }
564 else
565 {
566
567
568
569
570 settingsFile = new File( "target/test-classes", settingsFile.getPath() );
571 }
572 }
573
574 String path = settingsFile.getAbsolutePath();
575
576
577 if ( matchesVersionRange( "[2.1.0,)" ) )
578 {
579 verifier.getCliOptions().add( "--global-settings" );
580 if ( path.indexOf( ' ' ) < 0 )
581 {
582 verifier.getCliOptions().add( path );
583 }
584 else
585 {
586 verifier.getCliOptions().add( '"' + path + '"' );
587 }
588 }
589 else
590 {
591 verifier.getSystemProperties().put( "org.apache.maven.global-settings", path );
592 }
593 }
594
595 if ( matchesVersionRange( "(3.2.5,)" ) )
596 {
597 String multiModuleProjectDirectory = findMultiModuleProjectDirectory( basedir );
598 verifier.getSystemProperties().put( "maven.multiModuleProjectDirectory", multiModuleProjectDirectory );
599 }
600
601 try
602 {
603
604
605 if ( VersionRange.createFromVersionSpec( "[9,12)" ).containsVersion( getJavaVersion() ) )
606 {
607 verifier.getSystemProperties().put( "maven.compiler.source", "1.7" );
608 verifier.getSystemProperties().put( "maven.compiler.target", "1.7" );
609 verifier.getSystemProperties().put( "maven.compiler.release", "7" );
610 }
611
612 if ( VersionRange.createFromVersionSpec( "[12,)" ).containsVersion( getJavaVersion() ) )
613 {
614 verifier.getSystemProperties().put( "maven.compiler.source", "7" );
615 verifier.getSystemProperties().put( "maven.compiler.target", "7" );
616 verifier.getSystemProperties().put( "maven.compiler.release", "7" );
617 }
618 }
619 catch ( InvalidVersionSpecificationException e )
620 {
621
622 }
623
624 return verifier;
625 }
626
627 private boolean hasDotMvnSubDirectory( Path path )
628 {
629 final Path probablySubDirectory = path.resolve( ".mvn" );
630 return Files.exists( probablySubDirectory ) && Files.isDirectory( probablySubDirectory );
631 }
632
633 private String findMultiModuleProjectDirectory( String basedir )
634 {
635 Path path = Paths.get( basedir );
636 Path result = path;
637
638 Collection<Path> fileSystemRoots = new ArrayList<>();
639 for ( Path root : path.getFileSystem().getRootDirectories() )
640 {
641 fileSystemRoots.add( root );
642 }
643
644 while ( !fileSystemRoots.contains( path ) )
645 {
646 if ( hasDotMvnSubDirectory( path ) )
647 {
648 result = path;
649 break;
650 }
651 path = path.getParent();
652 }
653
654 return result.toString();
655 }
656
657 public static void assertCanonicalFileEquals( String message, File expected, File actual )
658 throws IOException
659 {
660 assertEquals( message, expected.getCanonicalFile(), actual.getCanonicalFile() );
661 }
662
663 public static void assertCanonicalFileEquals( File expected, File actual )
664 throws IOException
665 {
666 assertCanonicalFileEquals( null, expected, actual );
667 }
668
669 public static void assertCanonicalFileEquals( String message, String expected, String actual )
670 throws IOException
671 {
672 assertCanonicalFileEquals( message, new File( expected ), new File( actual ) );
673 }
674
675 public static void assertCanonicalFileEquals( String expected, String actual )
676 throws IOException
677 {
678 assertCanonicalFileEquals( null, new File( expected ), new File( actual ) );
679 }
680 }