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 2017/05/04 18:52:20 UTC

maven-surefire git commit: [SUREFIRE-1264] Some tests can be lost when running in parallel with parameterized tests [Forced Update!]

Repository: maven-surefire
Updated Branches:
  refs/heads/SUREFIRE-1264 b93eaf50a -> 92b39d6a0 (forced update)


[SUREFIRE-1264] Some tests can be lost when running in parallel with parameterized tests


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

Branch: refs/heads/SUREFIRE-1264
Commit: 92b39d6a04e0c60f4892ad7200d555fab99cc4dc
Parents: 4e993a0
Author: Tibor17 <ti...@lycos.com>
Authored: Thu May 4 20:45:28 2017 +0200
Committer: Tibor17 <ti...@lycos.com>
Committed: Thu May 4 20:51:40 2017 +0200

----------------------------------------------------------------------
 .../util/internal/TestClassMethodNameUtils.java |  53 +++++++++-
 .../maven/surefire/its/fixture/TestFile.java    |   6 +-
 ...urefire1082ParallelJUnitParameterizedIT.java | 102 ++++++++++++++++---
 .../java/jiras/surefire1082/Jira1082Test.java   |   4 +-
 .../java/jiras/surefire1082/Jira1264Test.java   |  36 +++++++
 .../junitcore/JUnitCoreRunListener.java         |  49 ++++++---
 6 files changed, 219 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/92b39d6a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java
index 1a30c72..4e66f52 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java
@@ -1 +1,52 @@
-package org.apache.maven.surefire.util.internal;

/*
 * 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.regex.Matcher;
import java.util.regex.Pattern;

/**
 * JUnit Description parser.
 * Used by JUnit Version lower than 4.
 7.
 *
 * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
 * @since 2.20
 */
public final class TestClassMethodNameUtils
{
    private static final Pattern METHOD_CLASS_PATTERN = Pattern.compile( "([\\s\\S]*)\\((.*)\\)" );

    private TestClassMethodNameUtils()
    {
        throw new IllegalStateException( "no instantiable constructor" );
    }

    public static String extractClassName( String displayName )
    {
        Matcher m = METHOD_CLASS_PATTERN.matcher( displayName );
        return m.matches() ? m.group( 2 ) : displayName;
    }

    public static String extractMethodName( String displayName )
    {
        int i = displayName.indexOf( "(" );
        return i >= 0 ? displayName.substring( 0, i ) : displayName;
    }
}
\ No newline at end of file
+package org.apache.maven.surefire.util.internal;
+
+/*
+ * 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.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * JUnit Description parser.
+ * Used by JUnit Version lower than 4.7.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20
+ */
+public final class TestClassMethodNameUtils
+{
+    private static final Pattern METHOD_CLASS_PATTERN = Pattern.compile( "([\\s\\S]*)\\((.*)\\)" );
+
+    private TestClassMethodNameUtils()
+    {
+        throw new IllegalStateException( "no instantiable constructor" );
+    }
+
+    public static String extractClassName( String displayName )
+    {
+        Matcher m = METHOD_CLASS_PATTERN.matcher( displayName );
+        return m.matches() ? m.group( 2 ) : displayName;
+    }
+
+    public static String extractMethodName( String displayName )
+    {
+        Matcher m = METHOD_CLASS_PATTERN.matcher( displayName );
+        return m.matches() ? m.group( 1 ) : null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/92b39d6a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java
index 61736df..cf6ad84 100644
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java
@@ -39,7 +39,6 @@ import static junit.framework.Assert.assertTrue;
  */
 public class TestFile
 {
-
     private final File file;
 
     private final Charset encoding;
@@ -148,4 +147,9 @@ public class TestFile
     {
         return file.toURI();
     }
+
+    public File getFile()
+    {
+        return file;
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/92b39d6a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1082ParallelJUnitParameterizedIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1082ParallelJUnitParameterizedIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1082ParallelJUnitParameterizedIT.java
index b1d9d4f..b6c8421 100644
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1082ParallelJUnitParameterizedIT.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1082ParallelJUnitParameterizedIT.java
@@ -23,17 +23,22 @@ import org.apache.maven.it.VerificationException;
 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.apache.maven.surefire.its.fixture.TestFile;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.junit.Test;
 
+import java.nio.charset.Charset;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.SortedSet;
 import java.util.TreeSet;
 
 import static org.hamcrest.core.AnyOf.anyOf;
 import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertThat;
 
 /**
@@ -44,17 +49,29 @@ import static org.junit.Assert.assertThat;
 public class Surefire1082ParallelJUnitParameterizedIT
     extends SurefireJUnit4IntegrationTestCase
 {
+    private static Set<String> printOnlyTestLinesFromConsole( OutputValidator validator )
+            throws VerificationException
+    {
+        return printOnlyTestLines( validator.loadLogLines() );
+    }
+
+    private static Set<String> printOnlyTestLinesFromOutFile( OutputValidator validator )
+            throws VerificationException
+    {
+        TestFile report = validator.getSurefireReportsFile( "jiras.surefire1082.Jira1082Test-output.txt" );
+        report.assertFileExists();
+        return printOnlyTestLines( validator.loadFile( report.getFile(), Charset.forName( "UTF-8" ) ) );
+    }
 
-    private static Set<String> printOnlyTestLines( OutputValidator validator )
+    private static Set<String> printOnlyTestLines( Collection<String> logs )
         throws VerificationException
     {
-        Set<String> log = new TreeSet<String>( validator.loadLogLines() );
-        for ( Iterator<String> it = log.iterator(); it.hasNext(); )
+        SortedSet<String> log = new TreeSet<String>();
+        for ( String line : logs )
         {
-            String line = it.next();
-            if ( !line.startsWith( "class jiras.surefire1082." ) )
+            if ( line.startsWith( "class jiras.surefire1082." ) )
             {
-                it.remove();
+                log.add( line );
             }
         }
         return log;
@@ -65,14 +82,8 @@ public class Surefire1082ParallelJUnitParameterizedIT
         return new IsRegex( r );
     }
 
-    @Test
-    public void test()
-        throws VerificationException
+    private static void assertParallelRun( Set<String> log )
     {
-        OutputValidator validator = unpack().setTestToRun(
-            "Jira1082Test" ).parallelClasses().useUnlimitedThreads().executeTest().verifyErrorFree( 4 );
-
-        Set<String> log = printOnlyTestLines( validator );
         assertThat( log.size(), is( 4 ) );
 
         Set<String> expectedLogs1 = new TreeSet<String>();
@@ -90,6 +101,71 @@ public class Surefire1082ParallelJUnitParameterizedIT
         assertThat( log, anyOf( regex( expectedLogs1 ), regex( expectedLogs2 ) ) );
     }
 
+    @Test
+    public void checkClassesRunParallel()
+        throws VerificationException
+    {
+        OutputValidator validator = unpack().setTestToRun( "Jira1082Test" )
+                                            .parallelClasses()
+                                            .useUnlimitedThreads()
+                                            .executeTest()
+                                            .verifyErrorFree( 4 );
+
+        validator.getSurefireReportsXmlFile( "TEST-jiras.surefire1082.Jira1082Test.xml" )
+                .assertFileExists();
+
+        validator.assertThatLogLine( containsString( "Running jiras.surefire1082.Jira1082Test" ), is( 1 ) );
+
+        Set<String> log = printOnlyTestLinesFromConsole( validator );
+        assertParallelRun( log );
+    }
+
+    @Test
+    public void checkOutFileClassesRunParallel()
+            throws VerificationException
+    {
+        OutputValidator validator = unpack().redirectToFile( true )
+                                            .setTestToRun( "Jira1082Test" )
+                                            .parallelClasses()
+                                            .useUnlimitedThreads()
+                                            .executeTest()
+                                            .verifyErrorFree( 4 );
+
+        validator.getSurefireReportsXmlFile( "TEST-jiras.surefire1082.Jira1082Test.xml" )
+                .assertFileExists();
+
+        validator.assertThatLogLine( containsString( "Running jiras.surefire1082.Jira1082Test" ), is( 1 ) );
+
+        Set<String> log = printOnlyTestLinesFromOutFile( validator );
+        assertParallelRun( log );
+    }
+
+    @Test
+    public void shouldRunTwo() throws VerificationException
+    {
+        OutputValidator validator = unpack().redirectToFile( true )
+                                            .parallelClasses()
+                                            .useUnlimitedThreads()
+                                            .executeTest()
+                                            .verifyErrorFree( 8 );
+
+        validator.getSurefireReportsXmlFile( "TEST-jiras.surefire1082.Jira1082Test.xml" )
+                .assertFileExists();
+
+        validator.getSurefireReportsXmlFile( "TEST-jiras.surefire1082.Jira1264Test.xml" )
+                .assertFileExists();
+
+        validator.getSurefireReportsFile( "jiras.surefire1082.Jira1082Test-output.txt" )
+                .assertFileExists();
+
+        validator.getSurefireReportsFile( "jiras.surefire1082.Jira1264Test-output.txt" )
+                .assertFileExists();
+
+        validator.assertThatLogLine( containsString( "Running jiras.surefire1082.Jira1082Test" ), is( 1 ) );
+
+        validator.assertThatLogLine( containsString( "Running jiras.surefire1082.Jira1264Test" ), is( 1 ) );
+    }
+
     private SurefireLauncher unpack()
     {
         return unpack( "surefire-1082-parallel-junit-parameterized" );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/92b39d6a/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1082Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1082Test.java b/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1082Test.java
index abf2a58..e8cef99 100644
--- a/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1082Test.java
+++ b/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1082Test.java
@@ -27,9 +27,9 @@ import java.util.Arrays;
 import java.util.concurrent.TimeUnit;
 
 @RunWith( Parameterized.class )
-public final class Jira1082Test
+public class Jira1082Test
 {
-    private int x;
+    private final int x;
 
     public Jira1082Test( int x )
     {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/92b39d6a/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1264Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1264Test.java b/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1264Test.java
new file mode 100644
index 0000000..56e7644
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-1082-parallel-junit-parameterized/src/test/java/jiras/surefire1082/Jira1264Test.java
@@ -0,0 +1,36 @@
+package jiras.surefire1082;
+
+/*
+ * 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.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+@RunWith( Parameterized.class )
+public final class Jira1264Test extends Jira1082Test
+{
+    public Jira1264Test( int x )
+    {
+        super( x );
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/92b39d6a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java
index e32e32c..4a187e4 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java
@@ -19,16 +19,18 @@ package org.apache.maven.surefire.junitcore;
  * under the License.
  */
 
-import java.util.ArrayList;
-import java.util.Map;
 import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
 import org.apache.maven.surefire.common.junit48.JUnit46StackTraceWriter;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.StackTraceWriter;
-
 import org.junit.runner.Description;
 import org.junit.runner.Result;
+import org.junit.runner.RunWith;
 import org.junit.runner.notification.Failure;
+import org.junit.runners.Parameterized;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
 
 /**
  * Noteworthy things about JUnit4 listening:
@@ -74,38 +76,57 @@ public class JUnitCoreRunListener
         reporter.testSetCompleted( null );
     }
 
-    private void fillTestCountMap( Description description )
+    private void fillTestCountMap( Description testDesc )
     {
-        final ArrayList<Description> children = description.getChildren();
+        TestSet testSet = new TestSet( testDesc );
+
+        String itemTestClassName =
+                isParameterizedRunner( testDesc ) ? testDesc.getClassName() : asSuiteRunner( testDesc, testSet );
 
-        TestSet testSet = new TestSet( description );
+        if ( itemTestClassName != null )
+        {
+            classMethodCounts.put( itemTestClassName, testSet );
+        }
+    }
+
+    private String asSuiteRunner( Description description, TestSet testSet )
+    {
         String itemTestClassName = null;
-        for ( Description item : children )
+        for ( Description child : description.getChildren() )
         {
-            if ( !item.isTest() )
+            if ( !child.isTest() )
             {
-                fillTestCountMap( item );
+                fillTestCountMap( child );
             }
             else
             {
-                if ( extractDescriptionMethodName( item ) != null )
+                if ( extractDescriptionMethodName( child ) != null )
                 {
                     testSet.incrementTestMethodCount();
                     if ( itemTestClassName == null )
                     {
-                        itemTestClassName = extractDescriptionClassName( item );
+                        itemTestClassName = extractDescriptionClassName( child );
                     }
                 }
                 else
                 {
-                    classMethodCounts.put( extractDescriptionClassName( item ), new TestSet( item ) );
+                    classMethodCounts.put( extractDescriptionClassName( child ), new TestSet( child ) );
                 }
             }
         }
-        if ( itemTestClassName != null )
+        return itemTestClassName;
+    }
+
+    private static boolean isParameterizedRunner( Description description )
+    {
+        for ( Annotation ann : description.getAnnotations() )
         {
-            classMethodCounts.put( itemTestClassName, testSet );
+            if ( ann.annotationType() == RunWith.class )
+            {
+                return Parameterized.class.isAssignableFrom( ( (RunWith) ann ).value() );
+            }
         }
+        return false;
     }
 
     @Override