| /* |
| * 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. |
| */ |
| package org.apache.lucene.util; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.PrintStream; |
| import java.io.UnsupportedEncodingException; |
| import java.nio.charset.StandardCharsets; |
| import java.util.List; |
| |
| import org.apache.lucene.util.LuceneTestCase.SuppressSysoutChecks; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Assume; |
| import org.junit.Before; |
| import org.junit.ClassRule; |
| import org.junit.Rule; |
| import org.junit.rules.RuleChain; |
| import org.junit.rules.TestRule; |
| import org.junit.runner.Result; |
| import org.junit.runner.notification.Failure; |
| |
| import com.carrotsearch.randomizedtesting.RandomizedRunner; |
| import com.carrotsearch.randomizedtesting.RandomizedTest; |
| import com.carrotsearch.randomizedtesting.SysGlobals; |
| import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter; |
| |
| /** |
| * An abstract test class that prepares nested test classes to run. |
| * A nested test class will assume it's executed under control of this |
| * class and be ignored otherwise. |
| * |
| * <p>The purpose of this is so that nested test suites don't run from |
| * IDEs like Eclipse (where they are automatically detected). |
| * |
| * <p>This class cannot extend {@link LuceneTestCase} because in case |
| * there's a nested {@link LuceneTestCase} afterclass hooks run twice and |
| * cause havoc (static fields). |
| */ |
| public abstract class WithNestedTests { |
| @SuppressSysoutChecks(bugUrl = "WithNestedTests has its own stream capture.") |
| public static abstract class AbstractNestedTest extends LuceneTestCase |
| implements TestRuleIgnoreTestSuites.NestedTestSuite { |
| protected static boolean isRunningNested() { |
| return TestRuleIgnoreTestSuites.isRunningNested(); |
| } |
| } |
| |
| private boolean suppressOutputStreams; |
| |
| protected WithNestedTests(boolean suppressOutputStreams) { |
| this.suppressOutputStreams = suppressOutputStreams; |
| } |
| |
| protected PrintStream prevSysErr; |
| protected PrintStream prevSysOut; |
| private ByteArrayOutputStream sysout; |
| private ByteArrayOutputStream syserr; |
| |
| @ClassRule |
| public static final TestRule classRules = RuleChain.outerRule(new TestRuleAdapter() { |
| private TestRuleIgnoreAfterMaxFailures prevRule; |
| |
| protected void before() throws Throwable { |
| 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(); |
| } |
| }); |
| |
| /** |
| * Restore properties after test. |
| */ |
| @Rule |
| public final TestRule rules; |
| { |
| final TestRuleMarkFailure marker = new TestRuleMarkFailure(); |
| rules = RuleChain |
| .outerRule(new TestRuleRestoreSystemProperties(TestRuleIgnoreTestSuites.PROPERTY_RUN_NESTED)) |
| .around(new TestRuleAdapter() { |
| @Override |
| protected void afterAlways(List<Throwable> errors) throws Throwable { |
| if (marker.hadFailures() && suppressOutputStreams) { |
| System.out.println("sysout from nested test: " + getSysOut() + "\n"); |
| System.out.println("syserr from nested test: " + getSysErr()); |
| } |
| } |
| }) |
| .around(marker); |
| } |
| |
| @Before |
| public final void before() { |
| if (suppressOutputStreams) { |
| prevSysOut = System.out; |
| prevSysErr = System.err; |
| |
| try { |
| sysout = new ByteArrayOutputStream(); |
| System.setOut(new PrintStream(sysout, true, IOUtils.UTF_8)); |
| syserr = new ByteArrayOutputStream(); |
| System.setErr(new PrintStream(syserr, true, IOUtils.UTF_8)); |
| } catch (UnsupportedEncodingException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| FailureMarker.resetFailures(); |
| System.setProperty(TestRuleIgnoreTestSuites.PROPERTY_RUN_NESTED, "true"); |
| } |
| |
| @After |
| public final void after() { |
| if (suppressOutputStreams) { |
| System.out.flush(); |
| System.err.flush(); |
| |
| System.setOut(prevSysOut); |
| System.setErr(prevSysErr); |
| } |
| } |
| |
| protected void assertFailureCount(int expected, Result result) { |
| if (result.getFailureCount() != expected) { |
| StringBuilder b = new StringBuilder(); |
| for (Failure f : result.getFailures()) { |
| b.append("\n\n"); |
| b.append(f.getMessage()); |
| b.append("\n"); |
| b.append(f.getTrace()); |
| } |
| Assert.assertFalse("Expected failures: " + expected + " but was " + |
| result.getFailureCount() + ", failures below: " + b.toString(), true); |
| } |
| } |
| |
| protected String getSysOut() { |
| Assert.assertTrue(suppressOutputStreams); |
| System.out.flush(); |
| return new String(sysout.toByteArray(), StandardCharsets.UTF_8); |
| } |
| |
| protected String getSysErr() { |
| Assert.assertTrue(suppressOutputStreams); |
| System.err.flush(); |
| return new String(syserr.toByteArray(), StandardCharsets.UTF_8); |
| } |
| } |