diff --git a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java index 8c8fed693fc..f96af913803 100644 --- a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java +++ b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java @@ -20,11 +20,18 @@ package org.apache.lucene.util.junitcompat; import java.util.Properties; import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util.SystemPropertiesInvariantRule; +import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.junit.*; +import org.junit.rules.TestRule; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; +/** + * @see SystemPropertiesRestoreRule + * @see SystemPropertiesInvariantRule + */ public class TestSystemPropertiesInvariantRule extends WithNestedTests { public static final String PROP_KEY1 = "new-property-1"; public static final String VALUE1 = "new-value-1"; @@ -85,6 +92,16 @@ public class TestSystemPropertiesInvariantRule extends WithNestedTests { } } + public static class IgnoredProperty { + @Rule + public TestRule invariant = new SystemPropertiesInvariantRule(PROP_KEY1); + + @Test + public void testMethod1() { + System.setProperty(PROP_KEY1, VALUE1); + } + } + @Test public void testRuleInvariantBeforeClass() { Result runClasses = JUnitCore.runClasses(InBeforeClass.class); @@ -120,4 +137,16 @@ public class TestSystemPropertiesInvariantRule extends WithNestedTests { Assert.assertTrue(runClasses.getFailures().get(0).getMessage().contains("Will pass")); Assert.assertEquals(3, runClasses.getRunCount()); } + + @Test + public void testIgnoredProperty() { + System.clearProperty(PROP_KEY1); + try { + Result runClasses = JUnitCore.runClasses(IgnoredProperty.class); + Assert.assertEquals(0, runClasses.getFailureCount()); + Assert.assertEquals(VALUE1, System.getProperty(PROP_KEY1)); + } finally { + System.clearProperty(PROP_KEY1); + } + } } diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java index 20181fc17dc..19cf45b37f8 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java @@ -276,6 +276,16 @@ public abstract class LuceneTestCase extends Assert { */ private static final UncaughtExceptionsRule uncaughtExceptionsRule = new UncaughtExceptionsRule(null); + /** + * These property keys will be ignored in verification of altered properties. + * @see SystemPropertiesInvariantRule + * @see #ruleChain + * @see #classRules + */ + private static final String [] ignoredInvariantProperties = { + "user.timezone" + }; + /** * This controls how suite-level rules are nested. It is important that _all_ rules declared * in {@link LuceneTestCase} are executed in proper order if they depend on each @@ -283,7 +293,7 @@ public abstract class LuceneTestCase extends Assert { */ @ClassRule public static TestRule classRules = RuleChain - .outerRule(new SystemPropertiesInvariantRule()) + .outerRule(new SystemPropertiesInvariantRule(ignoredInvariantProperties)) .around(classNameRule) .around(uncaughtExceptionsRule); @@ -297,7 +307,7 @@ public abstract class LuceneTestCase extends Assert { .outerRule(new RememberThreadRule()) .around(new UncaughtExceptionsRule(this)) .around(new TestResultInterceptorRule()) - .around(new SystemPropertiesInvariantRule()) + .around(new SystemPropertiesInvariantRule(ignoredInvariantProperties)) .around(new InternalSetupTeardownRule()) .around(new SubclassSetupTeardownRule()); diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesInvariantRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesInvariantRule.java index de3f40551c4..5d8079e374c 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesInvariantRule.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesInvariantRule.java @@ -18,7 +18,11 @@ package org.apache.lucene.util; */ import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; +import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; @@ -28,6 +32,32 @@ import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; public class SystemPropertiesInvariantRule implements TestRule { + /** + * Ignored property keys. + */ + private final HashSet ignoredProperties; + + /** + * Cares about all properties. + */ + public SystemPropertiesInvariantRule() { + this(Collections.emptySet()); + } + + /** + * Don't care about the given set of properties. + */ + public SystemPropertiesInvariantRule(String... ignoredProperties) { + this.ignoredProperties = new HashSet(Arrays.asList(ignoredProperties)); + } + + /** + * Don't care about the given set of properties. + */ + public SystemPropertiesInvariantRule(Set ignoredProperties) { + this.ignoredProperties = new HashSet(ignoredProperties); + } + @Override public Statement apply(final Statement s, Description d) { return new Statement() { @@ -40,7 +70,12 @@ public class SystemPropertiesInvariantRule implements TestRule { } catch (Throwable t) { errors.add(t); } finally { - TreeMap after = SystemPropertiesRestoreRule.cloneAsMap(System.getProperties()); + final TreeMap after = SystemPropertiesRestoreRule.cloneAsMap(System.getProperties()); + + // Remove ignored if they exist. + before.keySet().removeAll(ignoredProperties); + after.keySet().removeAll(ignoredProperties); + if (!after.equals(before)) { errors.add( new AssertionError("System properties invariant violated.\n" + @@ -48,7 +83,7 @@ public class SystemPropertiesInvariantRule implements TestRule { } // Restore original properties. - SystemPropertiesRestoreRule.restore(before, after); + SystemPropertiesRestoreRule.restore(before, after, ignoredProperties); } MultipleFailureException.assertEmpty(errors); diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesRestoreRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesRestoreRule.java index 4e7b57a3588..0411aae53da 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesRestoreRule.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesRestoreRule.java @@ -27,6 +27,32 @@ import org.junit.runners.model.Statement; * Restore system properties from before the nested {@link Statement}. */ public class SystemPropertiesRestoreRule implements TestRule { + /** + * Ignored property keys. + */ + private final HashSet ignoredProperties; + + /** + * Restores all properties. + */ + public SystemPropertiesRestoreRule() { + this(Collections.emptySet()); + } + + /** + * @param ignoredProperties Properties that will be ignored (and will not be restored). + */ + public SystemPropertiesRestoreRule(Set ignoredProperties) { + this.ignoredProperties = new HashSet(this.ignoredProperties); + } + + /** + * @param ignoredProperties Properties that will be ignored (and will not be restored). + */ + public SystemPropertiesRestoreRule(String... ignoredProperties) { + this.ignoredProperties = new HashSet(Arrays.asList(ignoredProperties)); + } + @Override public Statement apply(final Statement s, Description d) { return new Statement() { @@ -39,7 +65,7 @@ public class SystemPropertiesRestoreRule implements TestRule { TreeMap after = cloneAsMap(System.getProperties()); if (!after.equals(before)) { // Restore original properties. - restore(before, after); + restore(before, after, ignoredProperties); } } } @@ -69,16 +95,25 @@ public class SystemPropertiesRestoreRule implements TestRule { static void restore( TreeMap before, - TreeMap after) { + TreeMap after, + Set ignoredKeys) { + + // Clear anything that is present after but wasn't before. after.keySet().removeAll(before.keySet()); for (String key : after.keySet()) { - System.clearProperty(key); + if (!ignoredKeys.contains(key)) + System.clearProperty(key); } + + // Restore original property values unless they are ignored (then leave). for (Map.Entry e : before.entrySet()) { - if (e.getValue() == null) { - System.clearProperty(e.getKey()); // Can this happen? - } else { - System.setProperty(e.getKey(), e.getValue()); + String key = e.getValue(); + if (!ignoredKeys.contains(key)) { + if (key == null) { + System.clearProperty(e.getKey()); // Can this happen? + } else { + System.setProperty(e.getKey(), key); + } } } }