You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2019/12/27 01:59:00 UTC
[maven-surefire] branch cli updated: added unit tests
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch cli
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
The following commit(s) were added to refs/heads/cli by this push:
new 6f4ee88 added unit tests
6f4ee88 is described below
commit 6f4ee88cf31605841fa9672227538f3c874c780d
Author: tibordigana <ti...@apache.org>
AuthorDate: Fri Dec 27 02:58:51 2019 +0100
added unit tests
---
.../plugin/surefire/booterclient/ForkStarter.java | 3 +-
.../surefire/booterclient/ForkStarterTest.java | 272 +++++++++++++++++++++
.../plugin/surefire/booterclient/MainClass.java | 52 ++++
.../org/apache/maven/surefire/JUnit4SuiteTest.java | 2 +
surefire-extensions-api/pom.xml | 13 +
.../extensions/util/CommandlineExecutorTest.java | 109 +++++++++
.../surefire/extensions/util/JUnit4SuiteTest.java | 38 +++
7 files changed, 487 insertions(+), 2 deletions(-)
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index a17737b..f2734ee 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -40,7 +40,6 @@ import org.apache.maven.surefire.extensions.util.LineConsumerThread;
import org.apache.maven.surefire.extensions.util.StreamFeeder;
import org.apache.maven.surefire.shared.utils.cli.CommandLineException;
import org.apache.maven.surefire.booter.AbstractPathConfiguration;
-import org.apache.maven.surefire.booter.KeyValueSource;
import org.apache.maven.surefire.booter.PropertiesWrapper;
import org.apache.maven.surefire.booter.ProviderConfiguration;
import org.apache.maven.surefire.booter.ProviderFactory;
@@ -548,7 +547,7 @@ public class ForkStarter
}
}
- private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkClient forkClient,
+ private RunResult fork( Object testSet, PropertiesWrapper providerProperties, ForkClient forkClient,
SurefireProperties effectiveSystemProperties, int forkNumber,
AbstractForkInputStream commandInputStream, boolean readTestsFromInStream )
throws SurefireBooterForkException
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
new file mode 100644
index 0000000..e0874f0
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
@@ -0,0 +1,272 @@
+package org.apache.maven.plugin.surefire.booterclient;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.surefire.StartupReportConfiguration;
+import org.apache.maven.plugin.surefire.SurefireProperties;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.AbstractForkInputStream;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStream;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
+import org.apache.maven.surefire.booter.AbstractPathConfiguration;
+import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
+import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.surefire.booter.PropertiesWrapper;
+import org.apache.maven.surefire.booter.ProviderConfiguration;
+import org.apache.maven.surefire.booter.Shutdown;
+import org.apache.maven.surefire.booter.StartupConfiguration;
+import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.report.ReporterConfiguration;
+import org.apache.maven.surefire.shared.compress.archivers.zip.Zip64Mode;
+import org.apache.maven.surefire.shared.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.maven.surefire.shared.compress.archivers.zip.ZipArchiveOutputStream;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.jar.Manifest;
+import java.util.zip.Deflater;
+
+import static org.fest.util.Files.delete;
+import static org.hamcrest.Matchers.containsString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.powermock.reflect.Whitebox.invokeMethod;
+
+/**
+ *
+ */
+public class ForkStarterTest
+{
+ private static String baseDir = System.getProperty( "user.dir" );
+ private static File tmp;
+
+ @Rule
+ public final ExpectedException e = ExpectedException.none();
+
+ @BeforeClass
+ public static void prepareFiles() throws IOException
+ {
+ File target = new File( baseDir, "target" );
+ tmp = new File( target, "tmp" );
+ tmp.mkdirs();
+ File booter = new File( tmp, "surefirebooter.jar" );
+ booter.createNewFile();
+
+ try ( ZipArchiveOutputStream zos = new ZipArchiveOutputStream( new FileOutputStream( booter ) ) )
+ {
+ zos.setUseZip64( Zip64Mode.Never );
+ zos.setLevel( Deflater.NO_COMPRESSION );
+
+ ZipArchiveEntry ze = new ZipArchiveEntry( "META-INF/MANIFEST.MF" );
+ zos.putArchiveEntry( ze );
+
+ Manifest man = new Manifest();
+
+ man.getMainAttributes().putValue( "Manifest-Version", "1.0" );
+ man.getMainAttributes().putValue( "Main-Class", MainClass.class.getName() );
+
+ man.write( zos );
+
+ zos.closeArchiveEntry();
+
+ ze = new ZipArchiveEntry( "org/apache/maven/plugin/surefire/booterclient/MainClass.class" );
+ zos.putArchiveEntry( ze );
+ String classesDir = Paths.get( target.getPath(), "test-classes" ).toString();
+ Path cls = Paths.get( classesDir, "org", "apache", "maven", "plugin", "surefire", "booterclient",
+ "MainClass.class" );
+ zos.write( Files.readAllBytes( cls ) );
+ zos.closeArchiveEntry();
+ }
+ }
+
+ @AfterClass
+ public static void deleteTmp()
+ {
+ delete( tmp );
+ }
+
+ @Test
+ public void processShouldExitWithoutSayingGoodBye() throws Exception
+ {
+ ReporterConfiguration reporterConfiguration = new ReporterConfiguration( tmp, true );
+
+ ProviderConfiguration providerConfiguration = mock( ProviderConfiguration.class );
+ when( providerConfiguration.getReporterConfiguration() )
+ .thenReturn( reporterConfiguration );
+ when( providerConfiguration.getShutdown() )
+ .thenReturn( Shutdown.EXIT );
+
+ StartupConfiguration startupConfiguration = mock( StartupConfiguration.class );
+ when( startupConfiguration.getClasspathConfiguration() )
+ .thenReturn( new ClasspathConfig() );
+ when( startupConfiguration.getClassLoaderConfiguration() )
+ .thenReturn( new ClassLoaderConfiguration( false, false ) );
+ when( startupConfiguration.getProviderClassName() )
+ .thenReturn( MainClass.class.getName() );
+
+ ForkConfiguration forkConfiguration = mock( ForkConfiguration.class );
+ when( forkConfiguration.getWorkingDirectory() )
+ .thenReturn( tmp );
+ when( forkConfiguration.getTempDirectory() )
+ .thenReturn( tmp );
+ when( forkConfiguration.getPluginPlatform() )
+ .thenReturn( new Platform() );
+ OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
+ cli.setWorkingDirectory( tmp );
+ cli.setExecutable( System.getProperty( "java.home" ) + "/bin/java" );
+ cli.createArg().setLine( "-jar" );
+ cli.createArg().setLine( "surefirebooter.jar" );
+ cli.createArg().setLine( "fail" );
+ when( forkConfiguration.createCommandLine( eq( startupConfiguration ), eq( 1 ), eq( tmp ) ) )
+ .thenReturn( cli );
+
+ StartupReportConfiguration startupReportConfiguration = new StartupReportConfiguration( true, true, null,
+ false, tmp, true, "", null, false, 0, null, null, true, null, null, null );
+
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+
+ ForkStarter forkStarter = new ForkStarter( providerConfiguration, startupConfiguration, forkConfiguration,
+ 0, startupReportConfiguration, logger );
+
+ DefaultReporterFactory reporterFactory = new DefaultReporterFactory( startupReportConfiguration, logger, 1 );
+
+ e.expect( SurefireBooterForkException.class );
+ e.expectMessage( containsString( "Process Exit Code: 1" ) );
+ e.expectMessage( containsString( "The forked VM terminated without properly saying goodbye." ) );
+ e.expectMessage( containsString( "VM crash or System.exit called?" ) );
+
+ Class<?>[] types = {Object.class, PropertiesWrapper.class, ForkClient.class, SurefireProperties.class,
+ int.class, AbstractForkInputStream.class, boolean.class};
+ TestProvidingInputStream testProvidingInputStream = new TestProvidingInputStream( new ArrayDeque<String>() );
+ invokeMethod( forkStarter, "fork", types, null,
+ new PropertiesWrapper( Collections.<String, String>emptyMap() ),
+ new ForkClient( reporterFactory, null, logger, new AtomicBoolean(), 1 ),
+ new SurefireProperties(), 1, testProvidingInputStream, true );
+ testProvidingInputStream.close();
+ }
+
+ @Test
+ public void processShouldWaitForAck() throws Exception
+ {
+ ReporterConfiguration reporterConfiguration = new ReporterConfiguration( tmp, true );
+
+ ProviderConfiguration providerConfiguration = mock( ProviderConfiguration.class );
+ when( providerConfiguration.getReporterConfiguration() )
+ .thenReturn( reporterConfiguration );
+ when( providerConfiguration.getShutdown() )
+ .thenReturn( Shutdown.EXIT );
+
+ StartupConfiguration startupConfiguration = mock( StartupConfiguration.class );
+ when( startupConfiguration.getClasspathConfiguration() )
+ .thenReturn( new ClasspathConfig() );
+ when( startupConfiguration.getClassLoaderConfiguration() )
+ .thenReturn( new ClassLoaderConfiguration( false, false ) );
+ when( startupConfiguration.getProviderClassName() )
+ .thenReturn( MainClass.class.getName() );
+
+ ForkConfiguration forkConfiguration = mock( ForkConfiguration.class );
+ when( forkConfiguration.getWorkingDirectory() )
+ .thenReturn( tmp );
+ when( forkConfiguration.getTempDirectory() )
+ .thenReturn( tmp );
+ when( forkConfiguration.getPluginPlatform() )
+ .thenReturn( new Platform() );
+ OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
+ cli.setWorkingDirectory( tmp );
+ cli.setExecutable( System.getProperty( "java.home" ) + "/bin/java" );
+ cli.createArg().setLine( "-jar" );
+ cli.createArg().setLine( "surefirebooter.jar" );
+ when( forkConfiguration.createCommandLine( eq( startupConfiguration ), eq( 1 ), eq( tmp ) ) )
+ .thenReturn( cli );
+
+ StartupReportConfiguration startupReportConfiguration = new StartupReportConfiguration( true, true, null,
+ false, tmp, true, "", null, false, 0, null, null, true, null, null, null );
+
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+
+ ForkStarter forkStarter = new ForkStarter( providerConfiguration, startupConfiguration, forkConfiguration,
+ 0, startupReportConfiguration, logger );
+
+ DefaultReporterFactory reporterFactory = new DefaultReporterFactory( startupReportConfiguration, logger, 1 );
+
+ Class<?>[] types = {Object.class, PropertiesWrapper.class, ForkClient.class, SurefireProperties.class,
+ int.class, AbstractForkInputStream.class, boolean.class};
+ TestLessInputStream testLessInputStream = new TestLessInputStreamBuilder().build();
+ invokeMethod( forkStarter, "fork", types, null,
+ new PropertiesWrapper( Collections.<String, String>emptyMap() ),
+ new ForkClient( reporterFactory, testLessInputStream, logger, new AtomicBoolean(), 1 ),
+ new SurefireProperties(), 1, testLessInputStream, true );
+ testLessInputStream.close();
+ }
+
+ private static class ClasspathConfig extends AbstractPathConfiguration
+ {
+ ClasspathConfig()
+ {
+ this( Classpath.emptyClasspath(), false, false );
+ }
+
+ private ClasspathConfig( Classpath surefireClasspathUrls, boolean enableAssertions, boolean childDelegation )
+ {
+ super( surefireClasspathUrls, enableAssertions, childDelegation );
+ }
+
+ @Override
+ public Classpath getTestClasspath()
+ {
+ return Classpath.emptyClasspath();
+ }
+
+ @Override
+ public boolean isModularPathConfig()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isClassPathConfig()
+ {
+ return true;
+ }
+
+ @Override
+ protected Classpath getInprocClasspath()
+ {
+ return Classpath.emptyClasspath();
+ }
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
new file mode 100644
index 0000000..d90a128
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
@@ -0,0 +1,52 @@
+package org.apache.maven.plugin.surefire.booterclient;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+
+/**
+ * For testing purposes.
+ */
+public class MainClass
+{
+ public static void main( String... args ) throws IOException
+ {
+ if ( "fail".equals( args[0] ) )
+ {
+ System.exit( 1 );
+ }
+ else
+ {
+ System.out.println( ":maven:surefire:std:out:bye" );
+ if ( System.in.read() == 0
+ && System.in.read() == 0
+ && System.in.read() == 0
+ && System.in.read() == 5
+ && System.in.read() == 0
+ && System.in.read() == 0
+ && System.in.read() == 0
+ && System.in.read() == 0 )
+ {
+ System.exit( 0 );
+ }
+ System.exit( 1 );
+ }
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index d28a89c..b1e3b22 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -34,6 +34,7 @@ import org.apache.maven.plugin.surefire.booterclient.BooterDeserializerProviderC
import org.apache.maven.plugin.surefire.booterclient.BooterDeserializerStartupConfigurationTest;
import org.apache.maven.plugin.surefire.booterclient.DefaultForkConfigurationTest;
import org.apache.maven.plugin.surefire.booterclient.ForkConfigurationTest;
+import org.apache.maven.plugin.surefire.booterclient.ForkStarterTest;
import org.apache.maven.plugin.surefire.booterclient.ForkingRunListenerTest;
import org.apache.maven.plugin.surefire.booterclient.JarManifestForkConfigurationTest;
import org.apache.maven.plugin.surefire.booterclient.ModularClasspathForkConfigurationTest;
@@ -104,6 +105,7 @@ public class JUnit4SuiteTest extends TestCase
suite.addTest( new JUnit4TestAdapter( TestSetStatsTest.class ) );
suite.addTest( new JUnit4TestAdapter( StatelessTestsetInfoReporterTest.class ) );
suite.addTest( new JUnit4TestAdapter( CommonReflectorTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( ForkStarterTest.class ) );
return suite;
}
}
diff --git a/surefire-extensions-api/pom.xml b/surefire-extensions-api/pom.xml
index 5904157..1e88403 100644
--- a/surefire-extensions-api/pom.xml
+++ b/surefire-extensions-api/pom.xml
@@ -48,6 +48,16 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-shared-utils</artifactId>
+ <version>3.0.0-M4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<classifier>runtime</classifier>
@@ -89,6 +99,9 @@
</dependencies>
<configuration>
<argLine>${jvm.args.tests}</argLine>
+ <includes>
+ <include>**/JUnit4SuiteTest.java</include>
+ </includes>
<systemPropertyVariables>
<jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
diff --git a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/CommandlineExecutorTest.java b/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/CommandlineExecutorTest.java
new file mode 100644
index 0000000..fd99059
--- /dev/null
+++ b/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/CommandlineExecutorTest.java
@@ -0,0 +1,109 @@
+package org.apache.maven.surefire.extensions.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.shared.utils.cli.Commandline;
+import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.nio.file.Paths;
+
+import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.util.Files.delete;
+import static org.mockito.ArgumentMatchers.contains;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ *
+ */
+public class CommandlineExecutorTest
+{
+ private CommandlineExecutor exec;
+ private CommandlineStreams streams;
+ private String baseDir;
+ LineConsumerThread out;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ baseDir = System.getProperty( "user.dir" );
+
+ delete( Paths.get( baseDir, "target", "CommandlineExecutorTest" ).toFile() );
+
+ boolean createdDir = Paths.get( baseDir, "target", "CommandlineExecutorTest" )
+ .toFile()
+ .mkdirs();
+
+ assertThat( createdDir )
+ .isTrue();
+
+ boolean createdFile = Paths.get( baseDir, "target", "CommandlineExecutorTest", "a.txt" )
+ .toFile()
+ .createNewFile();
+
+ assertThat( createdFile )
+ .isTrue();
+ }
+
+ @After
+ public void tearDown() throws Exception
+ {
+ if ( out != null )
+ {
+ out.close();
+ }
+ exec.close();
+ streams.close();
+ delete( Paths.get( baseDir, "target", "CommandlineExecutorTest" ).toFile() );
+ }
+
+ @Test
+ public void shouldExecuteNativeCommand() throws Exception
+ {
+ Closeable closer = mock( Closeable.class );
+ Commandline cli = new Commandline( IS_OS_WINDOWS ? "dir" : "ls -la" );
+ cli.setWorkingDirectory( Paths.get( baseDir, "target", "CommandlineExecutorTest" ).toFile() );
+ CountdownCloseable countdownCloseable = new CountdownCloseable( closer, 1 );
+ exec = new CommandlineExecutor( cli, countdownCloseable );
+ streams = exec.execute();
+ StreamConsumer consumer = mock( StreamConsumer.class );
+ InputStream is = new InputStream()
+ {
+ @Override
+ public int read()
+ {
+ return -1;
+ }
+ };
+ StreamFeeder in = new StreamFeeder( "std-in-fork-1", streams.getStdInChannel(), is );
+ in.start();
+ out = new LineConsumerThread( "std-out-fork-1", streams.getStdOutChannel(), consumer, countdownCloseable );
+ out.start();
+ exec.awaitExit();
+ verify( consumer )
+ .consumeLine( contains( "a.txt" ) );
+ }
+}
diff --git a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java b/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java
new file mode 100644
index 0000000..df9cca1
--- /dev/null
+++ b/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java
@@ -0,0 +1,38 @@
+package org.apache.maven.surefire.extensions.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ *
+ */
+public class JUnit4SuiteTest extends TestCase
+{
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite();
+ suite.addTest( new JUnit4TestAdapter( CommandlineExecutorTest.class ) );
+ return suite;
+ }
+}