You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sj...@apache.org on 2022/01/27 19:11:54 UTC

[maven-invoker-plugin] branch master updated: [MINVOKER-295] Refactor for settings InvocationRequest in one place

This is an automated email from the ASF dual-hosted git repository.

sjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 45bf6b1  [MINVOKER-295] Refactor for settings InvocationRequest in one place
45bf6b1 is described below

commit 45bf6b1f1353786b447ce0486912b30f600e51ca
Author: Slawomir Jaranowski <s....@gmail.com>
AuthorDate: Fri Jan 7 17:50:13 2022 +0100

    [MINVOKER-295] Refactor for settings InvocationRequest in one place
---
 .../maven/plugins/invoker/AbstractInvokerMojo.java |  87 ++++----
 .../maven/plugins/invoker/InvokerProperties.java   | 221 ++++++++++++---------
 .../plugins/invoker/InvokerPropertiesTest.java     | 184 ++++++++++-------
 3 files changed, 288 insertions(+), 204 deletions(-)

diff --git a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
index 729659d..7e78147 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
@@ -492,32 +492,41 @@ public abstract class AbstractInvokerMojo
      * invoker.goals.2 = ${project.groupId}:${project.artifactId}:${project.version}:run
      *
      * # A comma or space separated list of profiles to activate
+     * # can be indexed
      * invoker.profiles = its,jdk15
      *
      * # The path to an alternative POM or base directory to invoke Maven on, defaults to the
      * # project that was originally specified in the plugin configuration
      * # Since plugin version 1.4
+     * # can be indexed
      * invoker.project = sub-module
      *
      * # The value for the environment variable MAVEN_OPTS
+     * # can be indexed
      * invoker.mavenOpts = -Dfile.encoding=UTF-16 -Xms32m -Xmx256m
      *
      * # Possible values are &quot;fail-fast&quot; (default), &quot;fail-at-end&quot; and &quot;fail-never&quot;
+     * # can be indexed
      * invoker.failureBehavior = fail-never
      *
      * # The expected result of the build, possible values are &quot;success&quot; (default) and &quot;failure&quot;
+     * # can be indexed
      * invoker.buildResult = failure
      *
      * # A boolean value controlling the aggregator mode of Maven, defaults to &quot;false&quot;
+     *
+     * # can be indexed
      * invoker.nonRecursive = true
      *
      * # A boolean value controlling the network behavior of Maven, defaults to &quot;false&quot;
      * # Since plugin version 1.4
+     * # can be indexed
      * invoker.offline = true
      *
      * # The path to the properties file from which to load system properties, defaults to the
      * # filename given by the plugin parameter testPropertiesFile
      * # Since plugin version 1.4
+     * # can be indexed
      * invoker.systemPropertiesFile = test.properties
      *
      * # An optional human friendly name for this build job to be included in the build reports.
@@ -556,10 +565,17 @@ public abstract class AbstractInvokerMojo
      *
      * # A boolean value controlling the debug logging level of Maven, , defaults to &quot;false&quot;
      * # Since plugin version 1.8
+     * # can be indexed
      * invoker.debug = true
      *
+     * The execution timeout in seconds.
+     * # Since plugin version 3.0.2
+     * # can be indexed
+     * invoker.timeoutInSeconds = 5
+     *
      * # Path to an alternate settings.xml to use for Maven invocation with this IT.
      * # Since plugin version 3.0.1
+     * # can be indexed
      * invoker.settingsFile = ../
      *
      * # An integer value to control run order of projects. sorted in the descending order of the ordinal.
@@ -1981,45 +1997,14 @@ public abstract class AbstractInvokerMojo
                 throw new RunFailureException( BuildJob.Result.FAILURE_PRE_HOOK, e );
             }
 
-            final InvocationRequest request = new DefaultInvocationRequest();
-
-            request.setLocalRepositoryDirectory( localRepositoryPath );
-
-            request.setBatchMode( true );
-
-            request.setShowErrors( showErrors );
-
-            request.setDebug( debug );
-
-            request.setShowVersion( showVersion );
-
-            setupLoggerForBuildJob( logger, request );
-
-            if ( mavenHome != null )
-            {
-                invoker.setMavenHome( mavenHome );
-                // FIXME: Should we really take care of M2_HOME?
-                request.addShellEnvironment( "M2_HOME", mavenHome.getAbsolutePath() );
-            }
+            // TODO - move to request
+            invoker.setMavenHome( mavenHome );
 
             if ( mavenExecutable != null )
             {
                 invoker.setMavenExecutable( new File( mavenExecutable ) );
             }
 
-            if ( actualJavaHome != null )
-            {
-                request.setJavaHome( actualJavaHome );
-            }
-
-            if ( environmentVariables != null )
-            {
-                for ( Map.Entry<String, String> variable : environmentVariables.entrySet() )
-                {
-                    request.addShellEnvironment( variable.getKey(), variable.getValue() );
-                }
-            }
-
             for ( int invocationIndex = 1;; invocationIndex++ )
             {
                 if ( invocationIndex > 1 && !invokerProperties.isInvocationDefined( invocationIndex ) )
@@ -2027,21 +2012,20 @@ public abstract class AbstractInvokerMojo
                     break;
                 }
 
-                request.setBaseDirectory( basedir );
-
-                request.setPomFile( pomFile );
-
-                request.setGoals( goals );
+                final InvocationRequest request = new DefaultInvocationRequest();
 
-                request.setProfiles( profiles );
+                request.setBatchMode( true );
 
-                request.setMavenOpts( mavenOpts );
+                // values only from Mojo configurations
+                request.setLocalRepositoryDirectory( localRepositoryPath );
+                request.setShowErrors( showErrors );
+                request.setShowVersion( showVersion );
+                request.setJavaHome( actualJavaHome );
 
-                request.setOffline( false );
+                setupLoggerForBuildJob( logger, request );
 
-                int timeOut = invokerProperties.getTimeoutInSeconds( invocationIndex );
-                // not set so we use the one at the mojo level
-                request.setTimeoutInSeconds( timeOut < 0 ? timeoutInSeconds : timeOut );
+                request.setBaseDirectory( basedir );
+                request.setPomFile( pomFile );
 
                 String customSettingsFile = invokerProperties.getSettingsFile( invocationIndex );
                 if ( customSettingsFile != null )
@@ -2137,7 +2121,6 @@ public abstract class AbstractInvokerMojo
         if ( logger != null )
         {
             request.setErrorHandler( logger );
-
             request.setOutputHandler( logger );
         }
     }
@@ -2639,7 +2622,19 @@ public abstract class AbstractInvokerMojo
             }
             props.setProperty( key, value );
         }
-        return new InvokerProperties( props );
+
+        InvokerProperties invokerProperties = new InvokerProperties( props );
+
+        // set default value for Invoker - it will be used if not present in properties
+        invokerProperties.setDefaultDebug( debug );
+        invokerProperties.setDefaultGoals( goals );
+        invokerProperties.setDefaultProfiles( profiles );
+        invokerProperties.setDefaultMavenOpts( mavenOpts );
+        invokerProperties.setDefaultTimeoutInSeconds( timeoutInSeconds );
+        invokerProperties.setDefaultEnvironmentVariables( environmentVariables );
+
+
+        return invokerProperties;
     }
 
     static class ToolchainPrivateManager
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
index b60227a..a057f8c 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
@@ -20,17 +20,19 @@ package org.apache.maven.plugins.invoker;
  */
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.Properties;
+import java.util.function.Consumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.maven.shared.invoker.InvocationRequest;
-import org.apache.maven.shared.invoker.InvocationRequest.ReactorFailureBehavior;
 import org.codehaus.plexus.util.StringUtils;
 
 /**
@@ -45,9 +47,18 @@ class InvokerProperties
     private static final Pattern ENVIRONMENT_VARIABLES_PATTERN =
             Pattern.compile( "invoker\\.environmentVariables\\.([A-Za-z][^.]+)(\\.([0-9]+))?" );
 
+    // default values from Mojo configuration
+    private Boolean defaultDebug;
+    private List<String> defaultGoals;
+    private List<String> defaultProfiles;
+    private String defaultMavenOpts;
+    private Integer defaultTimeoutInSeconds;
+    private Map<String, String> defaultEnvironmentVariables;
+
     private enum InvocationProperty
     {
         PROJECT( "invoker.project" ),
+        BUILD_RESULT( "invoker.buildResult" ),
         GOALS( "invoker.goals" ),
         PROFILES( "invoker.profiles" ),
         MAVEN_OPTS( "invoker.mavenOpts" ),
@@ -57,8 +68,7 @@ class InvokerProperties
         SYSTEM_PROPERTIES_FILE( "invoker.systemPropertiesFile" ),
         DEBUG( "invoker.debug" ),
         SETTINGS_FILE( "invoker.settingsFile" ),
-        TIMEOUT_IN_SECONDS( "invoker.timeoutInSeconds" ),
-        ORDINAL( "invoker.ordinal" );
+        TIMEOUT_IN_SECONDS( "invoker.timeoutInSeconds" );
 
         private final String key;
 
@@ -111,6 +121,60 @@ class InvokerProperties
     }
 
     /**
+     * Default value for debug
+     * @param defaultDebug a default value
+     */
+    public void setDefaultDebug( boolean defaultDebug )
+    {
+        this.defaultDebug = defaultDebug;
+    }
+
+    /**
+     * Default value for goals
+     * @param defaultGoals a default value
+     */
+    public void setDefaultGoals( List<String> defaultGoals )
+    {
+        this.defaultGoals = defaultGoals;
+    }
+
+    /**
+     * Default value for profiles
+     * @param defaultProfiles a default value
+     */
+    public void setDefaultProfiles( List<String> defaultProfiles )
+    {
+        this.defaultProfiles =  defaultProfiles;
+    }
+
+    /**
+     * Default value for mavenOpts
+     * @param defaultMavenOpts a default value
+     */
+    public void setDefaultMavenOpts( String defaultMavenOpts )
+    {
+        this.defaultMavenOpts = defaultMavenOpts;
+    }
+
+    /**
+     * Default value for timeoutInSeconds
+     * @param defaultTimeoutInSeconds a default value
+     */
+    public void setDefaultTimeoutInSeconds( int defaultTimeoutInSeconds )
+    {
+        this.defaultTimeoutInSeconds = defaultTimeoutInSeconds;
+    }
+
+    /**
+     * Default value for environmentVariables
+     * @param defaultEnvironmentVariables a default value
+     */
+    public void setDefaultEnvironmentVariables( Map<String, String> defaultEnvironmentVariables )
+    {
+        this.defaultEnvironmentVariables = defaultEnvironmentVariables;
+    }
+
+    /**
      * Gets the invoker properties being wrapped.
      *
      * @return The invoker properties being wrapped, never <code>null</code>.
@@ -294,14 +358,10 @@ class InvokerProperties
      */
     public boolean isInvocationDefined( int index )
     {
-        for ( InvocationProperty prop : InvocationProperty.values() )
-        {
-            if ( properties.getProperty( prop.toString() + '.' + index ) != null )
-            {
-                return true;
-            }
-        }
-        return false;
+        return Arrays.stream( InvocationProperty.values() )
+            .map( InvocationProperty::toString )
+            .map( v -> properties.getProperty( v + '.' + index ) )
+            .anyMatch( Objects::nonNull );
     }
 
     /**
@@ -313,14 +373,18 @@ class InvokerProperties
      */
     public boolean isSelectorDefined( int index )
     {
-        for ( SelectorProperty prop : SelectorProperty.values() )
+        return Arrays.stream( SelectorProperty.values() )
+            .map( v -> v.suffix )
+            .map( v -> properties.getProperty( SELECTOR_PREFIX + index + v ) )
+            .anyMatch( Objects::nonNull );
+    }
+
+    private <T> void setIfNotNull( Consumer<T> consumer,  T value )
+    {
+        if ( value != null )
         {
-            if ( properties.getProperty( SELECTOR_PREFIX + index + prop.suffix ) != null )
-            {
-                return true;
-            }
+            consumer.accept( value );
         }
-        return false;
     }
 
     /**
@@ -332,8 +396,7 @@ class InvokerProperties
      */
     public void configureInvocation( InvocationRequest request, int index )
     {
-        String project = get( InvocationProperty.PROJECT, index );
-        if ( project != null )
+        get( InvocationProperty.PROJECT, index ).ifPresent( project ->
         {
             File file = new File( request.getBaseDirectory(), project );
             if ( file.isFile() )
@@ -346,59 +409,48 @@ class InvokerProperties
                 request.setBaseDirectory( file );
                 request.setPomFile( null );
             }
-        }
+        } );
 
-        String goals = get( InvocationProperty.GOALS, index );
-        if ( goals != null )
-        {
-            request.setGoals( new ArrayList<>( Arrays.asList( StringUtils.split( goals, ", \t\n\r\f" ) ) ) );
-        }
+        setIfNotNull( request::setGoals,  get( InvocationProperty.GOALS, index )
+            .map( s -> StringUtils.split( s, ", \t\n\r\f" ) )
+            .map( Arrays::asList )
+            .filter( l -> !l.isEmpty() )
+            .orElse( defaultGoals ) );
 
-        String profiles = get( InvocationProperty.PROFILES, index );
-        if ( profiles != null )
-        {
-            // CHECKSTYLE_OFF: LineLength
-            request.setProfiles( new ArrayList<>( Arrays.asList( StringUtils.split( profiles,
-                                                                                          ", \t\n\r\f" ) ) ) );
-            // CHECKSTYLE_ON: LineLength
-        }
+        setIfNotNull( request::setProfiles, get( InvocationProperty.PROFILES, index )
+            .map( s -> StringUtils.split( s, ", \t\n\r\f" ) )
+            .map( Arrays::asList )
+            .filter( l -> !l.isEmpty() )
+            .orElse( defaultProfiles ) );
 
-        String mvnOpts = get( InvocationProperty.MAVEN_OPTS, index );
-        if ( mvnOpts != null )
-        {
-            request.setMavenOpts( mvnOpts );
-        }
+        setIfNotNull( request::setMavenOpts, get( InvocationProperty.MAVEN_OPTS, index ).orElse( defaultMavenOpts ) );
 
-        String failureBehavior = get( InvocationProperty.FAILURE_BEHAVIOR, index );
-        if ( failureBehavior != null )
-        {
-            ReactorFailureBehavior valueOf =
-                InvocationRequest.ReactorFailureBehavior.valueOfByLongOption( failureBehavior );
-            request.setReactorFailureBehavior( valueOf );
-        }
+        get( InvocationProperty.FAILURE_BEHAVIOR, index )
+            .map( InvocationRequest.ReactorFailureBehavior::valueOfByLongOption )
+            .ifPresent( request::setReactorFailureBehavior );
 
-        String nonRecursive = get( InvocationProperty.NON_RECURSIVE, index );
-        if ( nonRecursive != null )
-        {
-            request.setRecursive( !Boolean.parseBoolean( nonRecursive ) );
-        }
+        get( InvocationProperty.NON_RECURSIVE, index )
+            .map( Boolean::parseBoolean )
+            .map( b -> !b )
+            .ifPresent( request::setRecursive );
 
-        String offline = get( InvocationProperty.OFFLINE, index );
-        if ( offline != null )
-        {
-            request.setOffline( Boolean.parseBoolean( offline ) );
-        }
+        get( InvocationProperty.OFFLINE, index )
+            .map( Boolean::parseBoolean )
+            .ifPresent( request::setOffline );
 
-        String debug = get( InvocationProperty.DEBUG, index );
-        if ( debug != null )
-        {
-            request.setDebug( Boolean.parseBoolean( debug ) );
-        }
+        setIfNotNull( request::setDebug, get( InvocationProperty.DEBUG, index )
+            .map( Boolean::parseBoolean )
+            .orElse( defaultDebug ) );
 
-        for ( Map.Entry<String, String> envItem : getEnvironmentVariables( index ).entrySet() )
-        {
-            request.addShellEnvironment( envItem.getKey(), envItem.getValue() );
-        }
+        setIfNotNull( request::setTimeoutInSeconds, get( InvocationProperty.TIMEOUT_IN_SECONDS, index )
+            .map( Integer::parseInt )
+            .orElse( defaultTimeoutInSeconds ) );
+
+        Optional.ofNullable( defaultEnvironmentVariables )
+                .ifPresent( evn -> evn.forEach( request::addShellEnvironment ) );
+
+        getEnvironmentVariables( index )
+            .forEach( request::addShellEnvironment );
     }
 
     /**
@@ -411,7 +463,8 @@ class InvokerProperties
      */
     public boolean isExpectedResult( int exitCode, int index )
     {
-        boolean nonZeroExit = "failure".equalsIgnoreCase( get( "invoker.buildResult", index ) );
+        boolean nonZeroExit = "failure".equalsIgnoreCase(
+            get( InvocationProperty.BUILD_RESULT, index ).orElse( null ) );
         return ( exitCode != 0 ) == nonZeroExit;
     }
 
@@ -423,7 +476,7 @@ class InvokerProperties
      */
     public String getSystemPropertiesFile( int index )
     {
-        return get( InvocationProperty.SYSTEM_PROPERTIES_FILE, index );
+        return get( InvocationProperty.SYSTEM_PROPERTIES_FILE, index ).orElse( null );
     }
 
     /**
@@ -434,25 +487,10 @@ class InvokerProperties
      */
     public String getSettingsFile( int index )
     {
-        return get( InvocationProperty.SETTINGS_FILE, index );
+        return get( InvocationProperty.SETTINGS_FILE, index ).orElse( null );
     }
 
     /**
-     * Get timeout to execute the project
-     * @param index index The index of the invocation, must not be negative.
-     * @return the value for the timeout or -1
-     */
-    public int getTimeoutInSeconds( int index )
-    {
-        String timeoutInSecondsStr = get( InvocationProperty.TIMEOUT_IN_SECONDS, index );
-        if ( StringUtils.isEmpty( timeoutInSecondsStr ) )
-        {
-            return -1;
-        }
-        // catch NumberFormatException? well we assume users knows what they do :-)
-        return Integer.parseInt( timeoutInSecondsStr );
-    }
-    /**
      * Gets a value from the invoker properties. The invoker properties are intended to describe the invocation settings
      * for multiple builds of the same project. For this reason, the properties are indexed. First, a property named
      * <code>key.index</code> will be queried. If this property does not exist, the value of the property named
@@ -462,22 +500,23 @@ class InvokerProperties
      * @param index The index of the invocation for which to retrieve the value, must not be negative.
      * @return The value for the requested invoker property or <code>null</code> if not defined.
      */
-    String get( String key, int index )
+    Optional<String> get( String key, int index )
     {
         if ( index < 0 )
         {
             throw new IllegalArgumentException( "invalid invocation index: " + index );
         }
 
-        String value = properties.getProperty( key + '.' + index );
-        if ( value == null )
-        {
-            value = properties.getProperty( key );
-        }
-        return value;
+        // lookup in properties
+        String value = Optional.ofNullable( properties.getProperty( key + '.' + index ) )
+            .orElseGet( () -> properties.getProperty( key ) );
+
+        return Optional.ofNullable( value )
+            .map( String::trim )
+            .filter( s -> !s.isEmpty() );
     }
 
-    private String get( InvocationProperty prop, int index )
+    private Optional<String> get( InvocationProperty prop, int index )
     {
         return get( prop.toString(), index );
     }
diff --git a/src/test/java/org/apache/maven/plugins/invoker/InvokerPropertiesTest.java b/src/test/java/org/apache/maven/plugins/invoker/InvokerPropertiesTest.java
index afd9990..c380e20 100644
--- a/src/test/java/org/apache/maven/plugins/invoker/InvokerPropertiesTest.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/InvokerPropertiesTest.java
@@ -32,13 +32,12 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -60,7 +59,7 @@ public class InvokerPropertiesTest
     public void testConstructorNullSafe()
     {
         InvokerProperties facade = new InvokerProperties( null );
-        assertNotNull( facade.getProperties() );
+        assertThat( facade.getProperties() ).isNotNull();
     }
 
     @Test
@@ -69,14 +68,14 @@ public class InvokerPropertiesTest
         Properties props = new Properties();
         InvokerProperties facade = new InvokerProperties( props );
 
-        assertNull( facade.get( "undefined-key", 0 ) );
+        assertThat( facade.get( "undefined-key", 0 ) ).isEmpty();
 
         props.setProperty( "key", "value" );
-        assertEquals( "value", facade.get( "key", 1 ) );
+        assertThat( facade.get( "key", 1 ) ).hasValue( "value" );
 
         props.setProperty( "key.1", "another-value" );
-        assertEquals( "another-value", facade.get( "key", 1 ) );
-        assertEquals( "value", facade.get( "key", 2 ) );
+        assertThat( facade.get( "key", 1 ) ).hasValue( "another-value" );
+        assertThat( facade.get( "key", 2 ) ).hasValue( "value" );
     }
 
     @Test
@@ -87,7 +86,7 @@ public class InvokerPropertiesTest
         props.put( "invoker.name", jobName );
         InvokerProperties facade = new InvokerProperties( props );
 
-        assertEquals( jobName, facade.getJobName() );
+        assertThat( facade.getJobName() ).isEqualTo( jobName );
     }
 
     @Test
@@ -96,16 +95,16 @@ public class InvokerPropertiesTest
         Properties props = new Properties();
         InvokerProperties facade = new InvokerProperties( props );
 
-        assertTrue( facade.isExpectedResult( 0, 0 ) );
-        assertFalse( facade.isExpectedResult( 1, 0 ) );
+        assertThat( facade.isExpectedResult( 0, 0 ) ).isTrue();
+        assertThat( facade.isExpectedResult( 1, 0 ) ).isFalse();
 
         props.setProperty( "invoker.buildResult", "success" );
-        assertTrue( facade.isExpectedResult( 0, 0 ) );
-        assertFalse( facade.isExpectedResult( 1, 0 ) );
+        assertThat( facade.isExpectedResult( 0, 0 ) ).isTrue();
+        assertThat( facade.isExpectedResult( 1, 0 ) ).isFalse();
 
         props.setProperty( "invoker.buildResult", "failure" );
-        assertFalse( facade.isExpectedResult( 0, 0 ) );
-        assertTrue( facade.isExpectedResult( 1, 0 ) );
+        assertThat( facade.isExpectedResult( 0, 0 ) ).isFalse();
+        assertThat( facade.isExpectedResult( 1, 0 ) ).isTrue();
     }
 
     @Test
@@ -126,25 +125,33 @@ public class InvokerPropertiesTest
 
         props.setProperty( "invoker.goals", "verify" );
         facade.configureInvocation( request, 0 );
-        verify( request ).setGoals( eq( Collections.singletonList( "verify" ) ) );
+        verify( request ).setGoals( Collections.singletonList( "verify" ) );
         verifyNoMoreInteractions( request );
         clearInvocations( request );
 
         props.setProperty( "invoker.goals", "   " );
         facade.configureInvocation( request, 0 );
-        verify( request ).setGoals( eq( Collections.emptyList() ) );
+        verify( request, never() ).setGoals( anyList() );
         verifyNoMoreInteractions( request );
         clearInvocations( request );
 
         props.setProperty( "invoker.goals", "" );
         facade.configureInvocation( request, 0 );
-        verify( request ).setGoals( eq( Collections.emptyList() ) );
+        verify( request, never() ).setGoals( anyList() );
         verifyNoMoreInteractions( request );
         clearInvocations( request );
 
         props.setProperty( "invoker.goals", "  clean , test   verify " );
         facade.configureInvocation( request, 0 );
-        verify( request ).setGoals( eq( Arrays.asList( "clean", "test", "verify" ) ) );
+        verify( request ).setGoals( Arrays.asList( "clean", "test", "verify" ) );
+        verifyNoMoreInteractions( request );
+        clearInvocations( request );
+
+        props.clear();
+
+        facade.setDefaultGoals( Arrays.asList( "clean", "test" ) );
+        facade.configureInvocation( request, 0 );
+        verify( request ).setGoals( Arrays.asList( "clean", "test" ) );
         verifyNoMoreInteractions( request );
     }
 
@@ -156,26 +163,34 @@ public class InvokerPropertiesTest
 
         props.setProperty( "invoker.profiles", "verify" );
         facade.configureInvocation( request, 0 );
-        verify( request ).setProfiles( eq( Collections.singletonList( "verify" ) ) );
+        verify( request ).setProfiles( Collections.singletonList( "verify" )  );
         verifyNoMoreInteractions( request );
         clearInvocations( request );
 
         props.setProperty( "invoker.profiles", "   " );
         facade.configureInvocation( request, 0 );
-        verify( request ).setProfiles( eq( Collections.emptyList() ) );
+        verify( request, never() ).setProfiles( anyList()  );
         verifyNoMoreInteractions( request );
         clearInvocations( request );
 
         props.setProperty( "invoker.profiles", "" );
         facade.configureInvocation( request, 0 );
-        verify( request ).setProfiles( eq( Collections.emptyList() ) );
+        verify( request, never() ).setProfiles( anyList() );
         verifyNoMoreInteractions( request );
         clearInvocations( request );
 
         props.setProperty( "invoker.profiles", "  clean , test   verify  ," );
         facade.configureInvocation( request, 0 );
-        verify( request ).setProfiles( eq( Arrays.asList( "clean", "test", "verify" ) ) );
+        verify( request ).setProfiles( Arrays.asList( "clean", "test", "verify" ) );
+        verifyNoMoreInteractions( request );
+        clearInvocations( request );
+
+        props.clear();
+        facade.setDefaultProfiles( Arrays.asList( "profile1",  "profile2" ) );
+        facade.configureInvocation( request, 0 );
+        verify( request ).setProfiles( Arrays.asList( "profile1",  "profile2" ) );
         verifyNoMoreInteractions( request );
+
     }
 
     @Test
@@ -193,17 +208,14 @@ public class InvokerPropertiesTest
             props.setProperty( "invoker.project", tempPom.getName() );
             facade.configureInvocation( request, 0 );
             verify( request ).getBaseDirectory();
-            verify( request ).setBaseDirectory( eq( tempDir ) );
-            verify( request ).setPomFile( eq( tempPom ) );
+            verify( request ).setBaseDirectory( tempDir  );
+            verify( request ).setPomFile( tempPom  );
             verifyNoMoreInteractions( request );
             clearInvocations( request );
 
             props.setProperty( "invoker.project", "" );
             facade.configureInvocation( request, 0 );
-            verify( request ).getBaseDirectory();
-            verify( request ).setBaseDirectory( eq( tempDir ) );
-            verify( request ).setPomFile( null );
-            verifyNoMoreInteractions( request );
+            verifyNoInteractions( request );
         }
         finally
         {
@@ -221,6 +233,15 @@ public class InvokerPropertiesTest
         facade.configureInvocation( request, 0 );
         verify( request ).setMavenOpts( "-Xmx512m" );
         verifyNoMoreInteractions( request );
+        clearInvocations( request );
+
+        props.clear();
+
+        facade.setDefaultMavenOpts( "-Xxx" );
+        facade.configureInvocation( request, 0 );
+        verify( request ).setMavenOpts( "-Xxx" );
+        verifyNoMoreInteractions( request );
+
     }
 
     @Test
@@ -232,6 +253,7 @@ public class InvokerPropertiesTest
         props.setProperty( "invoker.failureBehavior", ReactorFailureBehavior.FailNever.getLongOption() );
         facade.configureInvocation( request, 0 );
         verify( request ).setReactorFailureBehavior( eq( ReactorFailureBehavior.FailNever ) );
+
         verifyNoMoreInteractions( request );
     }
 
@@ -242,14 +264,11 @@ public class InvokerPropertiesTest
         InvokerProperties facade = new InvokerProperties( props );
 
         props.setProperty( "invoker.failureBehavior", "xxxUnKnown" );
-        try
-        {
-            facade.configureInvocation( request, 0 );
-        }
-        catch ( IllegalArgumentException e )
-        {
-            assertEquals( "The string 'xxxUnKnown' can not be converted to enumeration.", e.getMessage() );
-        }
+
+        assertThatCode( () -> facade.configureInvocation( request, 0 ) )
+            .isExactlyInstanceOf( IllegalArgumentException.class  )
+            .hasMessage( "The string 'xxxUnKnown' can not be converted to enumeration." );
+
         verifyNoInteractions( request );
     }
 
@@ -306,6 +325,41 @@ public class InvokerPropertiesTest
         facade.configureInvocation( request, 0 );
         verify( request ).setDebug( false );
         verifyNoMoreInteractions( request );
+
+        props.clear();
+
+        facade.setDefaultDebug( true );
+        facade.configureInvocation( request, 0 );
+        verify( request ).setDebug( true );
+        verifyNoMoreInteractions( request );
+        clearInvocations( request );
+
+        facade.setDefaultDebug( false );
+        facade.configureInvocation( request, 0 );
+        verify( request ).setDebug( false );
+        verifyNoMoreInteractions( request );
+        clearInvocations( request );
+    }
+
+    @Test
+    public void testConfigureRequestTimeoutInSeconds()
+    {
+        Properties props = new Properties();
+        InvokerProperties facade = new InvokerProperties( props );
+
+        props.setProperty( "invoker.timeoutInSeconds", "5" );
+        facade.configureInvocation( request, 0 );
+        verify( request ).setTimeoutInSeconds( 5 );
+        verifyNoMoreInteractions( request );
+        clearInvocations( request );
+
+        props.clear();
+
+        facade.setDefaultTimeoutInSeconds( 3 );
+        facade.configureInvocation( request, 0 );
+        verify( request ).setTimeoutInSeconds( 3 );
+        verifyNoMoreInteractions( request );
+
     }
 
     @Test
@@ -352,21 +406,21 @@ public class InvokerPropertiesTest
         Properties props = new Properties();
         InvokerProperties facade = new InvokerProperties( props );
 
-        assertFalse( facade.isInvocationDefined( 1 ) );
+        assertThat( facade.isInvocationDefined( 1 ) ).isFalse();
 
         props.setProperty( "invoker.goals", "install" );
-        assertFalse( facade.isInvocationDefined( 1 ) );
+        assertThat( facade.isInvocationDefined( 1 ) ).isFalse();
 
         props.setProperty( "invoker.goals.2", "install" );
-        assertFalse( facade.isInvocationDefined( 1 ) );
-        assertTrue( facade.isInvocationDefined( 2 ) );
-        assertFalse( facade.isInvocationDefined( 3 ) );
+        assertThat( facade.isInvocationDefined( 1 ) ).isFalse();
+        assertThat( facade.isInvocationDefined( 2 ) ).isTrue();
+        assertThat( facade.isInvocationDefined( 3 ) ).isFalse();
 
         props.setProperty( "invoker.goals.3", "install" );
-        assertFalse( facade.isInvocationDefined( 1 ) );
-        assertTrue( facade.isInvocationDefined( 2 ) );
-        assertTrue( facade.isInvocationDefined( 3 ) );
-        assertFalse( facade.isInvocationDefined( 4 ) );
+        assertThat( facade.isInvocationDefined( 1 ) ).isFalse();
+        assertThat( facade.isInvocationDefined( 2 ) ).isTrue();
+        assertThat( facade.isInvocationDefined( 3 ) ).isTrue();
+        assertThat( facade.isInvocationDefined( 4 ) ).isFalse();
     }
 
     @Test
@@ -375,21 +429,21 @@ public class InvokerPropertiesTest
         Properties props = new Properties();
         InvokerProperties facade = new InvokerProperties( props );
 
-        assertFalse( facade.isSelectorDefined( 1 ) );
+        assertThat( facade.isSelectorDefined( 1 ) ).isFalse();
 
         props.setProperty( "invoker.java.version", "1.6+" );
         props.setProperty( "invoker.maven.version", "3.0+" );
         props.setProperty( "invoker.os.family", "windows" );
-        assertFalse( facade.isSelectorDefined( 1 ) );
+        assertThat( facade.isSelectorDefined( 1 ) ).isFalse();
 
         props.setProperty( "selector.2.java.version", "1.6+" );
         props.setProperty( "selector.3.maven.version", "3.0+" );
         props.setProperty( "selector.4.os.family", "windows" );
-        assertFalse( facade.isSelectorDefined( 1 ) );
-        assertTrue( facade.isSelectorDefined( 2 ) );
-        assertTrue( facade.isSelectorDefined( 3 ) );
-        assertTrue( facade.isSelectorDefined( 4 ) );
-        assertFalse( facade.isSelectorDefined( 5 ) );
+        assertThat( facade.isSelectorDefined( 1 ) ).isFalse();
+        assertThat( facade.isSelectorDefined( 2 ) ).isTrue();
+        assertThat( facade.isSelectorDefined( 3 ) ).isTrue();
+        assertThat( facade.isSelectorDefined( 4 ) ).isTrue();
+        assertThat( facade.isSelectorDefined( 5 ) ).isFalse();
     }
 
     @Test
@@ -400,12 +454,10 @@ public class InvokerPropertiesTest
         InvokerProperties facade = new InvokerProperties( props );
 
         Collection<InvokerToolchain> toolchains = facade.getToolchains();
-        assertNotNull( toolchains );
-        assertEquals( 0, toolchains.size() );
+        assertThat( toolchains ).isEmpty();
 
         toolchains = facade.getToolchains( 1 );
-        assertNotNull( toolchains );
-        assertEquals( 0, toolchains.size() );
+        assertThat(  toolchains ).isEmpty();
     }
 
     @Test
@@ -416,11 +468,10 @@ public class InvokerPropertiesTest
         InvokerProperties facade = new InvokerProperties( props );
 
         Collection<InvokerToolchain> toolchains = facade.getToolchains();
-        assertNotNull( toolchains );
-        assertEquals( 1, toolchains.size() );
+        assertThat( toolchains ).hasSize( 1 );
         InvokerToolchain toolchain = toolchains.iterator().next();
-        assertEquals( "jdk", toolchain.getType() );
-        assertEquals( Collections.singletonMap( "version", "11" ), toolchain.getProvides() );
+        assertThat( toolchain.getType() ).isEqualTo( "jdk" );
+        assertThat( toolchain.getProvides() ).containsExactlyEntriesOf( Collections.singletonMap( "version", "11" ) );
     }
 
     @Test
@@ -431,11 +482,10 @@ public class InvokerPropertiesTest
         InvokerProperties facade = new InvokerProperties( props );
 
         Collection<InvokerToolchain> toolchains = facade.getToolchains( 1 );
-        assertNotNull( toolchains );
-        assertEquals( 1, toolchains.size() );
+        assertThat( toolchains ).hasSize( 1 );
         InvokerToolchain toolchain = toolchains.iterator().next();
-        assertEquals( "jdk", toolchain.getType() );
-        assertEquals( Collections.singletonMap( "version", "11" ), toolchain.getProvides() );
+        assertThat( toolchain.getType() ).isEqualTo( "jdk" );
+        assertThat( toolchain.getProvides() ).containsExactlyEntriesOf( Collections.singletonMap( "version", "11" ) );
     }
 
 }