You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kr...@apache.org on 2013/05/03 18:51:52 UTC

git commit: SUREFIRE-569 Add support for scanning Dependencies for TestClasses

Updated Branches:
  refs/heads/master 33e110fc4 -> c808eec80


SUREFIRE-569 Add support for scanning Dependencies for TestClasses

Configure Surefire to scan any project Dependency for TestClasses
to include in the given test run.

TestClasses found as part of a Dependency are handled in the same
way as the testClassesDirectory found test classes. Includes,
Excludes and Test filters work the same.

Configuration example:

<dependency>
  <groupId>org.a</groupId>
  <artifactId>a</artifactId>
</dependency>

<configuration>
  <dependenciesToScan>
    <dependency>org.a:a</dependency>
  </dependenciesToScan>
</configuration>

Patch applied with rename of 1 file.


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/c808eec8
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/c808eec8
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/c808eec8

Branch: refs/heads/master
Commit: c808eec805509f14160454829df8f496499f0f4e
Parents: 33e110f
Author: Aslak Knutsen <as...@redhat.com>
Authored: Sat Jan 12 23:13:30 2013 +0100
Committer: Kristian Rosenvold <kr...@apache.org>
Committed: Fri May 3 18:40:20 2013 +0200

----------------------------------------------------------------------
 .../plugin/surefire/AbstractSurefireMojo.java      |   50 ++++-
 .../surefire/SurefireExecutionParameters.java      |    4 +
 .../plugin/surefire/util/DependencyScanner.java    |  172 +++++++++++++++
 .../plugin/surefire/util/DirectoryScanner.java     |   50 +----
 .../maven/plugin/surefire/util/ScannerUtil.java    |   72 ++++++
 .../surefire/util/DependenciesScannerTest.java     |   94 ++++++++
 .../Surefire569RunTestFromDependencyJarsIT.java    |   25 ++
 .../module1/pom.xml                                |   50 +++++
 .../surefire-569-RunTestFromDependencyJars/pom.xml |   29 +++
 .../testjar/pom.xml                                |   46 ++++
 .../testjar/src/test/java/org/test/TestA.java      |   10 +
 .../testjar/src/test/java/org/test/TestB.java      |   10 +
 12 files changed, 565 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index c767ea3..bcd5737 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -58,6 +58,7 @@ import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
 import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration;
 import org.apache.maven.plugin.surefire.booterclient.ForkStarter;
+import org.apache.maven.plugin.surefire.util.DependencyScanner;
 import org.apache.maven.plugin.surefire.util.DirectoryScanner;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Parameter;
@@ -581,6 +582,15 @@ public abstract class AbstractSurefireMojo
     protected String runOrder;
 
     /**
+     * List of dependencies to scan for test classes to include in the test run. Each dependency string must follow the format
+     * <i>groupId:artifactId</i>. For example: <i>org.acme:project-a</i>
+     *
+     * @since 2.14
+     */
+    @Parameter(property = "dependenciesToScan")
+    protected List<String> dependenciesToScan;
+
+    /**
      *
      */
     @Component
@@ -617,7 +627,7 @@ public abstract class AbstractSurefireMojo
 
         if ( verifyParameters() && !hasExecutedBefore() )
         {
-            DefaultScanResult scan = scanDirectories();
+            DefaultScanResult scan = scanForTestClasses();
             if ( !isValidSuiteXmlFileConfig() && scan.isEmpty() )
             {
                 if ( getEffectiveFailIfNoTests() )
@@ -640,12 +650,37 @@ public abstract class AbstractSurefireMojo
         toolchain = getToolchain();
     }
 
+    private DefaultScanResult scanForTestClasses()
+    {
+        DefaultScanResult scan = scanDirectories();
+        DefaultScanResult scanDeps = scanDependencies();
+        if(!scanDeps.isEmpty())
+        {
+            List combined = new ArrayList();
+            combined.addAll(scan.getFiles());
+            combined.addAll(scanDeps.getFiles());
+            scan = new DefaultScanResult(combined);
+        }
+        return scan;
+    }
+
     private DefaultScanResult scanDirectories()
     {
         return new DirectoryScanner( getTestClassesDirectory(), getIncludeList(), getExcludeList(),
                                      getSpecificTests() ).scan();
     }
 
+    private DefaultScanResult scanDependencies()
+    {
+        try {
+            return new DependencyScanner(
+                    DependencyScanner.filter(project.getTestArtifacts(), getDependenciesToScan()),
+                    getIncludeList(), getExcludeList(), getSpecificTests()).scan();
+	    } catch(Exception e) {
+	        throw new RuntimeException(e);
+        }
+    }
+
     boolean verifyParameters()
         throws MojoFailureException, MojoExecutionException
     {
@@ -666,7 +701,7 @@ public abstract class AbstractSurefireMojo
             }
         }
 
-        if ( !getTestClassesDirectory().exists() )
+        if ( !getTestClassesDirectory().exists() && getDependenciesToScan().size() == 0)
         {
             if ( Boolean.TRUE.equals( getFailIfNoTests() ) )
             {
@@ -1617,6 +1652,7 @@ public abstract class AbstractSurefireMojo
         checksum.add( getObjectFactory() );
         checksum.add( getFailIfNoTests() );
         checksum.add( getRunOrder() );
+        checksum.add( getDependenciesToScan() );
         addPluginSpecificChecksumItems( checksum );
         return checksum.getSha1();
 
@@ -2561,6 +2597,16 @@ public abstract class AbstractSurefireMojo
         this.runOrder = runOrder;
     }
 
+    public List<String> getDependenciesToScan()
+    {
+        return this.dependenciesToScan;
+    }
+
+    public void setDependenciesToScan(List<String> dependenciesToScan)
+    {
+        this.dependenciesToScan = dependenciesToScan;
+    }
+
     public PluginDescriptor getPluginDescriptor()
     {
         return pluginDescriptor;

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
index 5b79bcf..06dbe92 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
@@ -124,4 +124,8 @@ public interface SurefireExecutionParameters
     Boolean getFailIfNoSpecifiedTests();
 
     void setFailIfNoSpecifiedTests( Boolean failIfNoSpecifiedTests );
+
+    List<String> getDependenciesToScan();
+
+    void setDependenciesToScan(List<String> dependenciesToScan);
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java
new file mode 100644
index 0000000..cfdecff
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java
@@ -0,0 +1,172 @@
+package org.apache.maven.plugin.surefire.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 static org.apache.maven.plugin.surefire.util.ScannerUtil.convertToJavaClassName;
+import static org.apache.maven.plugin.surefire.util.ScannerUtil.processIncludesExcludes;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.shared.utils.io.MatchPatterns;
+import org.apache.maven.surefire.util.DefaultScanResult;
+
+/**
+ * Scans dependencies looking for tests.
+ *
+ * @author Aslak Knutsen
+ */
+public class DependencyScanner {
+
+	private final List<File> dependenciesToScan;
+
+	protected final List<String> includes;
+
+	protected final List<String> excludes;
+
+	protected final List<String> specificTests;
+
+	public DependencyScanner(List<File> dependenciesToScan, List<String> includes, List<String> excludes, List<String> specificTests)
+	{
+		this.dependenciesToScan = dependenciesToScan;
+        this.includes = includes;
+        this.excludes = excludes;
+        this.specificTests = specificTests;
+	}
+
+	public DefaultScanResult scan() throws MojoExecutionException
+	{
+		Matcher matcher = new Matcher(includes, excludes, specificTests);
+		List<String> found = new ArrayList<String>();
+		for(File artifact : dependenciesToScan)
+		{
+			try
+			{
+				found.addAll(scanArtifact(artifact, matcher));
+			}
+			catch (IOException e)
+			{
+				throw new MojoExecutionException("Could not scan dependency " + artifact.toString(), e);
+			}
+		}
+		return new DefaultScanResult(found);
+	}
+
+	private List<String> scanArtifact(File artifact, Matcher matcher) throws IOException
+	{
+		List<String> found = new ArrayList<String>();
+
+		if(artifact != null) {
+			if(artifact.isFile()) {
+				JarFile jar = null;
+				try {
+					jar = new JarFile(artifact);
+					Enumeration<JarEntry> entries = jar.entries();
+					while(entries.hasMoreElements())
+					{
+						JarEntry entry = entries.nextElement();
+						if(matcher.shouldInclude(entry.getName()))
+						{
+							found.add(convertToJavaClassName(entry.getName()));
+						}
+					}
+				}
+				finally
+				{
+					if(jar != null)
+					{
+						jar.close();
+					}
+				}
+			}
+		}
+		return found;
+	}
+
+	public static List<File> filter(List<Artifact> artifacts, List<String> groupArtifactIds)
+	{
+		List<File> matches = new ArrayList<File>();
+		if(groupArtifactIds == null || artifacts == null)
+		{
+			return matches;
+		}
+		for(Artifact artifact : artifacts)
+		{
+			for(String groups : groupArtifactIds)
+			{
+				String[] groupArtifact = groups.split(":");
+				if(groupArtifact.length != 2)
+				{
+					throw new IllegalArgumentException(
+							"dependencyToScan argument should be in format 'groupid:artifactid': " + groupArtifact);
+				}
+				if(
+						artifact.getGroupId().matches(groupArtifact[0]) &&
+						artifact.getArtifactId().matches(groupArtifact[1]))
+				{
+					matches.add(artifact.getFile());
+				}
+			}
+		}
+		return matches;
+	}
+
+	private class Matcher {
+
+		private MatchPatterns includes;
+		private MatchPatterns excludes;
+
+		private SpecificFileFilter specificTestFilter;
+
+		public Matcher(List<String> includes, List<String> excludes, List<String> specificTests)
+		{
+			String[] specific = specificTests == null ? new String[0] : processIncludesExcludes( specificTests );
+			specificTestFilter = new SpecificFileFilter( specific );
+
+			if(includes != null && includes.size() > 0)
+			{
+				this.includes = MatchPatterns.from(processIncludesExcludes(includes));
+			}
+			else
+			{
+				this.includes = MatchPatterns.from("**");
+			}
+			this.excludes = MatchPatterns.from(processIncludesExcludes(excludes));
+		}
+
+		public boolean shouldInclude(String name)
+		{
+			if(!name.endsWith(".class"))
+			{
+				return false;
+			}
+			boolean isIncluded = includes.matches(name, false);
+			boolean isExcluded = excludes.matches(name, false);
+
+			return isIncluded && !isExcluded && specificTestFilter.accept(name);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
index 45c2a5a..1d1f3dc 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
@@ -18,12 +18,14 @@ package org.apache.maven.plugin.surefire.util;
  * specific language governing permissions and limitations
  * under the License.
  */
+import static org.apache.maven.plugin.surefire.util.ScannerUtil.convertToJavaClassName;
+import static org.apache.maven.plugin.surefire.util.ScannerUtil.processIncludesExcludes;
+import static org.apache.maven.plugin.surefire.util.ScannerUtil.stripBaseDir;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import org.apache.commons.lang3.StringUtils;
+
 import org.apache.maven.surefire.util.DefaultScanResult;
 
 /**
@@ -34,13 +36,6 @@ import org.apache.maven.surefire.util.DefaultScanResult;
  */
 public class DirectoryScanner
 {
-
-    private static final String FS = System.getProperty( "file.separator" );
-
-    private static final String JAVA_SOURCE_FILE_EXTENSION = ".java";
-
-    private static final String JAVA_CLASS_FILE_EXTENSION = ".class";
-
     private final File basedir;
 
     private final List<String> includes;
@@ -91,39 +86,4 @@ public class DirectoryScanner
         }
         return new DefaultScanResult( result );
     }
-
-    private String convertToJavaClassName( String test )
-    {
-        return StringUtils.removeEnd( test, ".class" ).replace( FS, "." );
-    }
-
-    private String stripBaseDir( String basedir, String test )
-    {
-        return StringUtils.removeStart( test, basedir );
-    }
-
-    private static String[] processIncludesExcludes( List<String> list )
-    {
-        List<String> newList = new ArrayList<String>();
-        for ( Object aList : list )
-        {
-            String include = (String) aList;
-            String[] includes = include.split( "," );
-            Collections.addAll( newList, includes );
-        }
-
-        String[] incs = new String[newList.size()];
-
-        for ( int i = 0; i < incs.length; i++ )
-        {
-            String inc = newList.get( i );
-            if ( inc.endsWith( JAVA_SOURCE_FILE_EXTENSION ) )
-            {
-                inc = StringUtils.removeEnd( inc, JAVA_SOURCE_FILE_EXTENSION ) + JAVA_CLASS_FILE_EXTENSION;
-            }
-            incs[i] = inc;
-
-        }
-        return incs;
-    }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ScannerUtil.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ScannerUtil.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ScannerUtil.java
new file mode 100644
index 0000000..5ca9644
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ScannerUtil.java
@@ -0,0 +1,72 @@
+package org.apache.maven.plugin.surefire.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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+
+final class ScannerUtil {
+
+	private ScannerUtil() {}
+
+    private static final String FS = System.getProperty( "file.separator" );
+
+    private static final String JAVA_SOURCE_FILE_EXTENSION = ".java";
+
+    private static final String JAVA_CLASS_FILE_EXTENSION = ".class";
+
+    public static String convertToJavaClassName( String test )
+    {
+        return StringUtils.removeEnd( test, ".class" ).replace( FS, "." );
+    }
+
+    public static String stripBaseDir( String basedir, String test )
+    {
+        return StringUtils.removeStart( test, basedir );
+    }
+
+    public static String[] processIncludesExcludes( List<String> list )
+    {
+        List<String> newList = new ArrayList<String>();
+        for ( Object aList : list )
+        {
+            String include = (String) aList;
+            String[] includes = include.split( "," );
+            Collections.addAll( newList, includes );
+        }
+
+        String[] incs = new String[newList.size()];
+
+        for ( int i = 0; i < incs.length; i++ )
+        {
+            String inc = newList.get( i );
+            if ( inc.endsWith( JAVA_SOURCE_FILE_EXTENSION ) )
+            {
+                inc = StringUtils.removeEnd( inc, JAVA_SOURCE_FILE_EXTENSION ) + JAVA_CLASS_FILE_EXTENSION;
+            }
+            incs[i] = inc;
+
+        }
+        return incs;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java
new file mode 100644
index 0000000..c897e1e
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java
@@ -0,0 +1,94 @@
+package org.apache.maven.plugin.surefire.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 java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.surefire.testset.TestSetFailedException;
+import org.apache.maven.surefire.util.ScanResult;
+
+/**
+ * @author Aslak Knutsen
+ */
+public class DependenciesScannerTest
+    extends TestCase
+{
+    public void testLocateTestClasses()
+        throws Exception
+    {
+        File testFile = writeTestFile();
+
+        // use target as people can configure ide to compile in an other place than maven
+        Artifact artifact = new DefaultArtifact(
+                "org.surefire.dependency", "test-jar",
+                VersionRange.createFromVersion("1.0"), "test", "jar", "tests", null);
+        artifact.setFile(testFile);
+
+        List<String> scanDependencies = new ArrayList<String>();
+        scanDependencies.add("org.surefire.dependency:test-jar");
+
+        List<String> include = new ArrayList<String>();
+        include.add( "**/*A.java" );
+        List<String> exclude = new ArrayList<String>();
+
+        DependencyScanner scanner = new DependencyScanner(
+                DependencyScanner.filter(Arrays.asList(artifact), scanDependencies),
+                include, exclude, new ArrayList<String>() );
+
+        ScanResult classNames = scanner.scan();
+        assertNotNull( classNames );
+        System.out.println( "classNames " + classNames.toString() );
+        assertEquals( 1, classNames.size() );
+        System.out.println(classNames.getClassName(0));
+
+        Properties props = new Properties();
+        classNames.writeTo( props );
+        assertEquals( 1, props.size() );
+    }
+
+    private File writeTestFile() throws Exception {
+        File output = new File("target/DependenciesScannerTest-tests.jar");
+        output.delete();
+
+        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(output));
+
+        out.putNextEntry(new ZipEntry("org/test/TestA.class"));
+        out.closeEntry();
+        out.putNextEntry(new ZipEntry("org/test/TestB.class"));
+        out.closeEntry();
+        out.close();
+        return output;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire569RunTestFromDependencyJarsIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire569RunTestFromDependencyJarsIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire569RunTestFromDependencyJarsIT.java
new file mode 100644
index 0000000..cb9c92d
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire569RunTestFromDependencyJarsIT.java
@@ -0,0 +1,25 @@
+package org.apache.maven.surefire.its.jiras;
+
+import org.apache.maven.surefire.its.fixture.OutputValidator;
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.junit.Test;
+
+/**
+ * SUREFIRE-569 Add support for scanning Dependencies for TestClasses
+ *
+ * @author Aslak Knutsen
+ */
+public class Surefire569RunTestFromDependencyJarsIT
+	extends	SurefireJUnit4IntegrationTestCase {
+
+	@Test
+	public void shouldScanAndRunTestsInDependencyJars() throws Exception {
+		SurefireLauncher launcher = unpack( "surefire-569-RunTestFromDependencyJars" );
+		launcher.addGoal("test").addGoal("install");
+		launcher.executeCurrentGoals();
+
+		OutputValidator module1 = launcher.getSubProjectValidator("module1");
+		module1.assertTestSuiteResults(1, 0, 0, 0);
+	}
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/module1/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/module1/pom.xml b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/module1/pom.xml
new file mode 100644
index 0000000..7f1c672
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/module1/pom.xml
@@ -0,0 +1,50 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.maven.plugins.surefire</groupId>
+        <artifactId>surefire-569-RunTestFromDependencyJars</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <groupId>org.apache.maven.plugins.surefire.dependency-jar</groupId>
+    <artifactId>module1</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.1</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.maven.plugins.surefire.dependency-jar</groupId>
+            <artifactId>testjar</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <includes>
+                        <include>**/*A*.java</include>
+                    </includes>
+                    <dependenciesToScan>
+                        <dependency>org.apache.maven.plugins.surefire.dependency-jar:testjar</dependency>
+                    </dependenciesToScan>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/pom.xml b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/pom.xml
new file mode 100644
index 0000000..cd55a0e
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/pom.xml
@@ -0,0 +1,29 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.maven.plugins.surefire</groupId>
+    <artifactId>surefire-569-RunTestFromDependencyJars</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <surefire.version>2.14-SNAPSHOT</surefire.version>
+    </properties>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>${surefire.version}</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <modules>
+        <module>testjar</module>
+        <module>module1</module>
+    </modules>
+</project>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/pom.xml b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/pom.xml
new file mode 100644
index 0000000..ddfe3c0
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/pom.xml
@@ -0,0 +1,46 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.maven.plugins.surefire</groupId>
+        <artifactId>surefire-569-RunTestFromDependencyJars</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <groupId>org.apache.maven.plugins.surefire.dependency-jar</groupId>
+    <artifactId>testjar</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.1</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <skipTests>true</skipTests>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestA.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestA.java b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestA.java
new file mode 100644
index 0000000..6f432d1
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestA.java
@@ -0,0 +1,10 @@
+package org.test;
+
+import org.junit.Test;
+
+public class TestA {
+
+	@Test
+	public void shouldRun() {
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c808eec8/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestB.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestB.java b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestB.java
new file mode 100644
index 0000000..7e91ddd
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-569-RunTestFromDependencyJars/testjar/src/test/java/org/test/TestB.java
@@ -0,0 +1,10 @@
+package org.test;
+
+import org.junit.Test;
+
+public class TestB {
+
+	@Test
+	public void shouldRun() {
+	}
+}
\ No newline at end of file