You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by dw...@apache.org on 2014/04/04 11:03:36 UTC

svn commit: r1584569 - in /lucene/dev/trunk: lucene/ lucene/core/src/test/org/apache/lucene/util/ lucene/core/src/test/org/apache/lucene/util/junitcompat/ lucene/licenses/ lucene/test-framework/src/java/org/apache/lucene/util/ solr/licenses/

Author: dweiss
Date: Fri Apr  4 09:03:36 2014
New Revision: 1584569

URL: http://svn.apache.org/r1584569
Log:
LUCENE-5567: When a suite fails with zombie threads failure marker and count is not propagated properly.

Added:
    lucene/dev/trunk/lucene/licenses/junit4-ant-2.1.3.jar.sha1   (with props)
    lucene/dev/trunk/lucene/licenses/randomizedtesting-runner-2.1.3.jar.sha1   (with props)
    lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/FailureMarker.java   (with props)
    lucene/dev/trunk/solr/licenses/junit4-ant-2.1.3.jar.sha1   (with props)
    lucene/dev/trunk/solr/licenses/randomizedtesting-runner-2.1.3.jar.sha1   (with props)
Removed:
    lucene/dev/trunk/lucene/licenses/junit4-ant-2.1.1.jar.sha1
    lucene/dev/trunk/lucene/licenses/randomizedtesting-runner-2.1.1.jar.sha1
    lucene/dev/trunk/solr/licenses/junit4-ant-2.1.1.jar.sha1
    lucene/dev/trunk/solr/licenses/randomizedtesting-runner-2.1.1.jar.sha1
Modified:
    lucene/dev/trunk/lucene/CHANGES.txt
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestMaxFailuresRule.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java
    lucene/dev/trunk/lucene/ivy-versions.properties
    lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
    lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/TestRuleIgnoreAfterMaxFailures.java

Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1584569&r1=1584568&r2=1584569&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Fri Apr  4 09:03:36 2014
@@ -233,6 +233,9 @@ Bug fixes
 
 Test Framework
 
+* LUCENE-5567: When a suite fails with zombie threads failure marker and count 
+  is not propagated properly. (Dawid Weiss)
+
 * LUCENE-5449: Rename _TestUtil and _TestHelper to remove the leading _.
 
 * LUCENE-5501: Added random out-of-order collection testing (when the collector

Modified: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestMaxFailuresRule.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestMaxFailuresRule.java?rev=1584569&r1=1584568&r2=1584569&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestMaxFailuresRule.java (original)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestMaxFailuresRule.java Fri Apr  4 09:03:36 2014
@@ -17,8 +17,11 @@ package org.apache.lucene.util;
  * limitations under the License.
  */
 
+import java.util.concurrent.CountDownLatch;
+
 import org.apache.lucene.util.junitcompat.WithNestedTests;
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.Description;
@@ -27,8 +30,13 @@ import org.junit.runner.Result;
 import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunListener;
 
-import com.carrotsearch.randomizedtesting.SysGlobals;
 import com.carrotsearch.randomizedtesting.annotations.Repeat;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakAction;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakLingering;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies.Consequence;
 import com.carrotsearch.randomizedtesting.rules.SystemPropertiesInvariantRule;
 import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
 
@@ -66,48 +74,118 @@ public class TestMaxFailuresRule extends
 
   @Test
   public void testMaxFailures() {
-    TestRuleIgnoreAfterMaxFailures newRule = new TestRuleIgnoreAfterMaxFailures(2);
-    TestRuleIgnoreAfterMaxFailures prevRule = LuceneTestCase.replaceMaxFailureRule(newRule);
-    System.clearProperty(SysGlobals.SYSPROP_ITERATIONS());
-    try {
-      JUnitCore core = new JUnitCore();
-      final StringBuilder results = new StringBuilder();
-      core.addListener(new RunListener() {
-        char lastTest;
-
-        @Override
-        public void testStarted(Description description) throws Exception {
-          lastTest = 'S'; // success.
-        }
-
-        @Override
-        public void testAssumptionFailure(Failure failure) {
-          lastTest = 'A'; // assumption failure.
-        }
-
-        @Override
-        public void testFailure(Failure failure) throws Exception {
-          lastTest = 'F'; // failure
-        }
-
-        @Override
-        public void testFinished(Description description) throws Exception {
-          results.append(lastTest);
-        }
-      });
-
-      Result result = core.run(Nested.class);
-      Assert.assertEquals(500, result.getRunCount());
-      Assert.assertEquals(0, result.getIgnoreCount());
-      Assert.assertEquals(2, result.getFailureCount());
-
-      // Make sure we had exactly two failures followed by assumption-failures
-      // resulting from ignored tests.
-      Assert.assertTrue(results.toString(), 
-          results.toString().matches("(S*F){2}A+"));
+    LuceneTestCase.replaceMaxFailureRule(new TestRuleIgnoreAfterMaxFailures(2));
+    JUnitCore core = new JUnitCore();
+    final StringBuilder results = new StringBuilder();
+    core.addListener(new RunListener() {
+      char lastTest;
+
+      @Override
+      public void testStarted(Description description) throws Exception {
+        lastTest = 'S'; // success.
+      }
+
+      @Override
+      public void testAssumptionFailure(Failure failure) {
+        lastTest = 'A'; // assumption failure.
+      }
 
-    } finally {
-      LuceneTestCase.replaceMaxFailureRule(prevRule);
+      @Override
+      public void testFailure(Failure failure) throws Exception {
+        lastTest = 'F'; // failure
+      }
+
+      @Override
+      public void testFinished(Description description) throws Exception {
+        results.append(lastTest);
+      }
+    });
+
+    Result result = core.run(Nested.class);
+    Assert.assertEquals(500, result.getRunCount());
+    Assert.assertEquals(0, result.getIgnoreCount());
+    Assert.assertEquals(2, result.getFailureCount());
+
+    // Make sure we had exactly two failures followed by assumption-failures
+    // resulting from ignored tests.
+    Assert.assertTrue(results.toString(), 
+        results.toString().matches("(S*F){2}A+"));
+  }
+
+  @ThreadLeakZombies(Consequence.IGNORE_REMAINING_TESTS)
+  @ThreadLeakAction({ThreadLeakAction.Action.WARN})
+  @ThreadLeakScope(Scope.TEST)
+  @ThreadLeakLingering(linger = 500)
+  public static class Nested2 extends WithNestedTests.AbstractNestedTest {
+    public static final int TOTAL_ITERS = 10;
+    public static CountDownLatch die;
+    public static Thread zombie;
+    public static int testNum;
+    
+    @BeforeClass
+    public static void setup() {
+      assert zombie == null;
+      die = new CountDownLatch(1);
+      testNum = 0;
+    }
+
+    @Repeat(iterations = TOTAL_ITERS)
+    public void testLeaveZombie() {
+      if (++testNum == 2) {
+        zombie = new Thread() {
+          @Override
+          public void run() {
+            while (true) {
+              try {
+                die.await();
+                return;
+              } catch (Exception e) { /* ignore */ }
+            }
+          }
+        };
+        zombie.start();
+      }
     }
   }
+
+  @Test
+  public void testZombieThreadFailures() throws Exception {
+    LuceneTestCase.replaceMaxFailureRule(new TestRuleIgnoreAfterMaxFailures(1));
+    JUnitCore core = new JUnitCore();
+    final StringBuilder results = new StringBuilder();
+    core.addListener(new RunListener() {
+      char lastTest;
+
+      @Override
+      public void testStarted(Description description) throws Exception {
+        lastTest = 'S'; // success.
+      }
+
+      @Override
+      public void testAssumptionFailure(Failure failure) {
+        lastTest = 'A'; // assumption failure.
+      }
+
+      @Override
+      public void testFailure(Failure failure) throws Exception {
+        lastTest = 'F'; // failure
+        System.out.println(failure.getMessage());
+      }
+
+      @Override
+      public void testFinished(Description description) throws Exception {
+        results.append(lastTest);
+      }
+    });
+
+    Result result = core.run(Nested2.class);
+    if (Nested2.die != null) {
+      Nested2.die.countDown();
+      Nested2.zombie.join();
+    }
+    
+    super.prevSysOut.println(results.toString());
+    Assert.assertEquals(Nested2.TOTAL_ITERS, result.getRunCount());
+    Assert.assertEquals(results.toString(), "SFAAAAAAAA", results.toString());
+  }  
 }

Modified: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java?rev=1584569&r1=1584568&r2=1584569&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java (original)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/junitcompat/WithNestedTests.java Fri Apr  4 09:03:36 2014
@@ -23,6 +23,7 @@ import java.io.UnsupportedEncodingExcept
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 
+import org.apache.lucene.util.FailureMarker;
 import org.apache.lucene.util.IOUtils;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util.TestRuleIgnoreAfterMaxFailures;
@@ -37,6 +38,9 @@ import org.junit.Rule;
 import org.junit.rules.RuleChain;
 import org.junit.rules.TestRule;
 
+import com.carrotsearch.randomizedtesting.RandomizedRunner;
+import com.carrotsearch.randomizedtesting.RandomizedTest;
+import com.carrotsearch.randomizedtesting.SysGlobals;
 import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
 import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter;
 
@@ -76,22 +80,36 @@ public abstract class WithNestedTests {
     private TestRuleIgnoreAfterMaxFailures prevRule;
 
     protected void before() throws Throwable {
-      String filter = System.getProperty("tests.filter");
-      if (filter != null && !filter.trim().isEmpty()) {
-        // We're running with a complex test filter. This will affect nested tests anyway
-        // so ignore them.
+      if (!isPropertyEmpty(SysGlobals.SYSPROP_TESTFILTER()) ||
+          !isPropertyEmpty(SysGlobals.SYSPROP_TESTCLASS())  ||
+          !isPropertyEmpty(SysGlobals.SYSPROP_TESTMETHOD()) ||
+          !isPropertyEmpty(SysGlobals.SYSPROP_ITERATIONS())) {
+        // We're running with a complex test filter that is properly handled by classes
+        // which are executed by RandomizedRunner. The "outer" classes testing LuceneTestCase
+        // itself are executed by the default JUnit runner and would be always executed.
+        // We thus always skip execution if any filtering is detected.
         Assume.assumeTrue(false);
       }
       
+      // Check zombie threads from previous suites. Don't run if zombies are around.
+      RandomizedTest.assumeFalse(RandomizedRunner.hasZombieThreads());
+
       TestRuleIgnoreAfterMaxFailures newRule = new TestRuleIgnoreAfterMaxFailures(Integer.MAX_VALUE);
       prevRule = LuceneTestCase.replaceMaxFailureRule(newRule);
+      RandomizedTest.assumeFalse(FailureMarker.hadFailures());
     }
 
     protected void afterAlways(List<Throwable> errors) throws Throwable {
       if (prevRule != null) {
         LuceneTestCase.replaceMaxFailureRule(prevRule);
       }
+      FailureMarker.resetFailures();
     }
+
+    private boolean isPropertyEmpty(String propertyName) {
+      String value = System.getProperty(propertyName);
+      return value == null || value.trim().isEmpty();
+    }    
   }); 
 
   /**
@@ -131,6 +149,7 @@ public abstract class WithNestedTests {
       }
     }
 
+    FailureMarker.resetFailures();
     System.setProperty(TestRuleIgnoreTestSuites.PROPERTY_RUN_NESTED, "true");
   }
 

Modified: lucene/dev/trunk/lucene/ivy-versions.properties
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/ivy-versions.properties?rev=1584569&r1=1584568&r2=1584569&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/ivy-versions.properties (original)
+++ lucene/dev/trunk/lucene/ivy-versions.properties Fri Apr  4 09:03:36 2014
@@ -8,7 +8,7 @@
 /cglib/cglib-nodep = 2.2
 /com.adobe.xmp/xmpcore = 5.1.2
 
-com.carrotsearch.randomizedtesting.version = 2.1.1
+com.carrotsearch.randomizedtesting.version = 2.1.3
 /com.carrotsearch.randomizedtesting/junit4-ant = ${com.carrotsearch.randomizedtesting.version}
 /com.carrotsearch.randomizedtesting/randomizedtesting-runner = ${com.carrotsearch.randomizedtesting.version}
 

Added: lucene/dev/trunk/lucene/licenses/junit4-ant-2.1.3.jar.sha1
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/licenses/junit4-ant-2.1.3.jar.sha1?rev=1584569&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/licenses/junit4-ant-2.1.3.jar.sha1 (added)
+++ lucene/dev/trunk/lucene/licenses/junit4-ant-2.1.3.jar.sha1 Fri Apr  4 09:03:36 2014
@@ -0,0 +1 @@
+8636804644d4ae3874f0efaa98978887e171cd55

Added: lucene/dev/trunk/lucene/licenses/randomizedtesting-runner-2.1.3.jar.sha1
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/licenses/randomizedtesting-runner-2.1.3.jar.sha1?rev=1584569&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/licenses/randomizedtesting-runner-2.1.3.jar.sha1 (added)
+++ lucene/dev/trunk/lucene/licenses/randomizedtesting-runner-2.1.3.jar.sha1 Fri Apr  4 09:03:36 2014
@@ -0,0 +1 @@
+d340caee99857ed0384681eea6219a4d937e7ee4

Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/FailureMarker.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/FailureMarker.java?rev=1584569&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/FailureMarker.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/FailureMarker.java Fri Apr  4 09:03:36 2014
@@ -0,0 +1,48 @@
+package org.apache.lucene.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+/*
+ * 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.
+ */
+
+/**
+ * A {@link RunListener} that detects suite/ test failures. We need it because failures
+ * due to thread leaks happen outside of any rule contexts.
+ */
+public class FailureMarker extends RunListener {
+  static final AtomicInteger failures = new AtomicInteger();
+
+  @Override
+  public void testFailure(Failure failure) throws Exception {
+    failures.incrementAndGet();
+  }
+
+  public static boolean hadFailures() {
+    return failures.get() > 0;
+  }
+
+  static int getFailures() {
+    return failures.get();
+  }
+
+  public static void resetFailures() {
+    failures.set(0);
+  }
+}

Modified: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java?rev=1584569&r1=1584568&r2=1584569&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java (original)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java Fri Apr  4 09:03:36 2014
@@ -126,7 +126,8 @@ import static com.carrotsearch.randomize
   JUnit4MethodProvider.class
 })
 @Listeners({
-  RunListenerPrintReproduceInfo.class
+  RunListenerPrintReproduceInfo.class,
+  FailureMarker.class
 })
 @SeedDecorators({MixWithSuiteName.class}) // See LUCENE-3995 for rationale.
 @ThreadLeakScope(Scope.SUITE)
@@ -355,8 +356,7 @@ public abstract class LuceneTestCase ext
   /**
    * Suite failure marker (any error in the test or suite scope).
    */
-  public final static TestRuleMarkFailure suiteFailureMarker = 
-      new TestRuleMarkFailure();
+  public static TestRuleMarkFailure suiteFailureMarker;
 
   /**
    * Ignore tests after hitting a designated number of initial failures. This
@@ -421,7 +421,7 @@ public abstract class LuceneTestCase ext
   public static TestRule classRules = RuleChain
     .outerRule(new TestRuleIgnoreTestSuites())
     .around(ignoreAfterMaxFailures)
-    .around(suiteFailureMarker)
+    .around(suiteFailureMarker = new TestRuleMarkFailure())
     .around(new TestRuleAssertionsRequired())
     .around(new StaticFieldsInvariantRule(STATIC_LEAK_THRESHOLD, true) {
       @Override

Modified: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/TestRuleIgnoreAfterMaxFailures.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/TestRuleIgnoreAfterMaxFailures.java?rev=1584569&r1=1584568&r2=1584569&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/TestRuleIgnoreAfterMaxFailures.java (original)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/TestRuleIgnoreAfterMaxFailures.java Fri Apr  4 09:03:36 2014
@@ -40,11 +40,6 @@ public final class TestRuleIgnoreAfterMa
    * Maximum failures. Package scope for tests.
    */
   int maxFailures;
-
-  /**
-   * Current count of failures. Package scope for tests.
-   */
-  int failuresSoFar;
   
   /**
    * @param maxFailures
@@ -61,19 +56,13 @@ public final class TestRuleIgnoreAfterMa
     return new Statement() {
       @Override
       public void evaluate() throws Throwable {
+        int failuresSoFar = FailureMarker.getFailures();
         if (failuresSoFar >= maxFailures) {
           RandomizedTest.assumeTrue("Ignored, failures limit reached (" + 
               failuresSoFar + " >= " + maxFailures + ").", false);
         }
 
-        try {
-          s.evaluate();
-        } catch (Throwable t) {
-          if (!TestRuleMarkFailure.isAssumption(t)) {
-            failuresSoFar++;
-          }
-          throw t;
-        }
+        s.evaluate();
       }
     };
   }

Added: lucene/dev/trunk/solr/licenses/junit4-ant-2.1.3.jar.sha1
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/licenses/junit4-ant-2.1.3.jar.sha1?rev=1584569&view=auto
==============================================================================
--- lucene/dev/trunk/solr/licenses/junit4-ant-2.1.3.jar.sha1 (added)
+++ lucene/dev/trunk/solr/licenses/junit4-ant-2.1.3.jar.sha1 Fri Apr  4 09:03:36 2014
@@ -0,0 +1 @@
+8636804644d4ae3874f0efaa98978887e171cd55

Added: lucene/dev/trunk/solr/licenses/randomizedtesting-runner-2.1.3.jar.sha1
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/licenses/randomizedtesting-runner-2.1.3.jar.sha1?rev=1584569&view=auto
==============================================================================
--- lucene/dev/trunk/solr/licenses/randomizedtesting-runner-2.1.3.jar.sha1 (added)
+++ lucene/dev/trunk/solr/licenses/randomizedtesting-runner-2.1.3.jar.sha1 Fri Apr  4 09:03:36 2014
@@ -0,0 +1 @@
+d340caee99857ed0384681eea6219a4d937e7ee4