diff options
author | Michael Rosenfeld <mrosenfeld@google.com> | 2019-05-21 16:52:52 -0700 |
---|---|---|
committer | Michael Rosenfeld <mrosenfeld@google.com> | 2019-05-29 20:08:18 +0000 |
commit | 4c68ea29b69330527c386b0ca5dee018926f4ce8 (patch) | |
tree | 832d0395792960f4d0d05c56f597729c349b6ce9 | |
parent | bde25972fd727bbb6079bb430b75996406385f85 (diff) | |
download | platform_testing-4c68ea29b69330527c386b0ca5dee018926f4ce8.tar.gz |
Add filtering support to the longevity runners.
Bug: 127530862
Test: included
Change-Id: I251fa70233537cce08444813d6b726e8f77ea160
6 files changed, 102 insertions, 6 deletions
diff --git a/libraries/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java b/libraries/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java index 4e4a18802..0097d7b48 100644 --- a/libraries/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java +++ b/libraries/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java @@ -16,10 +16,15 @@ package android.platform.test.longevity; +import android.os.Bundle; import androidx.annotation.VisibleForTesting; +import androidx.test.InstrumentationRegistry; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.junit.After; import org.junit.AfterClass; @@ -39,11 +44,24 @@ import org.junit.runners.model.Statement; * longevity tests. */ public class LongevityClassRunner extends BlockJUnit4ClassRunner { + @VisibleForTesting static final String FILTER_OPTION = "exclude-class"; + + private String[] mExcludedClasses; + private boolean mTestFailed = true; private boolean mTestAttempted = false; public LongevityClassRunner(Class<?> klass) throws InitializationError { + this(klass, InstrumentationRegistry.getArguments()); + } + + @VisibleForTesting + LongevityClassRunner(Class<?> klass, Bundle args) throws InitializationError { super(klass); + mExcludedClasses = + args.containsKey(FILTER_OPTION) + ? args.getString(FILTER_OPTION).split(",") + : new String[] {}; } /** @@ -123,6 +141,16 @@ public class LongevityClassRunner extends BlockJUnit4ClassRunner { return mTestFailed; } + @Override + protected boolean isIgnored(FrameworkMethod child) { + if (super.isIgnored(child)) return true; + // Check if this class has been filtered. + String name = getTestClass().getJavaClass().getCanonicalName(); + return Arrays.stream(mExcludedClasses) + .map(f -> Pattern.compile(f).matcher(name)) + .anyMatch(Matcher::matches); + } + /** * {@link Statement} to run the statement and the {@link After} methods. If the test does not * fail, also runs the {@link AfterClass} method as {@link After} methods. diff --git a/libraries/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java b/libraries/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java index 70dc7e837..76ada9a99 100644 --- a/libraries/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java +++ b/libraries/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java @@ -195,8 +195,7 @@ public class LongevitySuite extends android.host.test.longevity.LongevitySuite { */ protected Runner getSuiteRunner(Runner runner) { try { - // Cast is safe as we have verified that the runner is BlockJUnit4Runner during - // initialization. + // Cast is safe as we verified the runner is BlockJUnit4Runner at initialization. return new LongevityClassRunner( ((BlockJUnit4ClassRunner) runner).getTestClass().getJavaClass()); } catch (InitializationError e) { diff --git a/libraries/longevity/platform/src/android/platform/test/longevity/Profile.java b/libraries/longevity/platform/src/android/platform/test/longevity/Profile.java index 7ce759e6d..4cb39335b 100644 --- a/libraries/longevity/platform/src/android/platform/test/longevity/Profile.java +++ b/libraries/longevity/platform/src/android/platform/test/longevity/Profile.java @@ -163,6 +163,12 @@ public class Profile extends RunListener { mScenarioIndex += 1; } + @Override + public void testIgnored(Description description) { + // Increments the index to move onto the next scenario. + mScenarioIndex += 1; + } + /** * Returns true if there is a next scheduled scenario to run. If no profile is supplied, returns * false. diff --git a/libraries/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java b/libraries/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java index ca3bbd46d..a263e0af6 100644 --- a/libraries/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java +++ b/libraries/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java @@ -45,17 +45,26 @@ public class ScheduledScenarioRunner extends LongevityClassRunner { private final Scenario mScenario; private final long mTotalTimeoutMs; private final boolean mShouldIdle; + private final Bundle mArguments; private long mStartTimeMs; public ScheduledScenarioRunner( Class<?> klass, Scenario scenario, long timeout, boolean shouldIdle) throws InitializationError { - super(klass); + this(klass, scenario, timeout, shouldIdle, InstrumentationRegistry.getArguments()); + } + + @VisibleForTesting + ScheduledScenarioRunner( + Class<?> klass, Scenario scenario, long timeout, boolean shouldIdle, Bundle arguments) + throws InitializationError { + super(klass, arguments); mScenario = scenario; // Ensure that the timeout is non-negative. mTotalTimeoutMs = max(timeout, 0); mShouldIdle = shouldIdle; + mArguments = arguments; } @Override @@ -100,8 +109,7 @@ public class ScheduledScenarioRunner extends LongevityClassRunner { protected void runChild(final FrameworkMethod method, RunNotifier notifier) { mStartTimeMs = System.currentTimeMillis(); // Keep a copy of the bundle arguments for restoring later. - Bundle initialArguments = InstrumentationRegistry.getArguments(); - Bundle modifiedArguments = initialArguments.deepCopy(); + Bundle modifiedArguments = mArguments.deepCopy(); for (ExtraArg argPair : mScenario.getExtrasList()) { if (argPair.getKey() == null || argPair.getValue() == null) { throw new IllegalArgumentException( @@ -117,7 +125,7 @@ public class ScheduledScenarioRunner extends LongevityClassRunner { super.runChild(method, notifier); // Restore the arguments to the state prior to the scenario. InstrumentationRegistry.registerInstance( - InstrumentationRegistry.getInstrumentation(), initialArguments); + InstrumentationRegistry.getInstrumentation(), mArguments); // If there are remaining scenarios, idle until the next one starts. if (mShouldIdle) { performIdleBeforeNextScenario(getTimeRemaining()); diff --git a/libraries/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java b/libraries/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java index ef1c64ef3..9db4e269b 100644 --- a/libraries/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java +++ b/libraries/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java @@ -27,6 +27,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; +import android.os.Bundle; + import java.util.List; import org.junit.Assert; @@ -37,12 +39,14 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; import org.junit.runner.notification.RunNotifier; import org.junit.runners.JUnit4; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.exceptions.base.MockitoAssertionError; @@ -352,6 +356,19 @@ public class LongevityClassRunnerTest { .invokeAndCollectErrors(getMethodNameMatcher("afterClassMethod"), any()); } + /** Test that excluded classes are not executed. */ + @Test + public void testIgnore_excludedClasses() throws Throwable { + RunNotifier notifier = Mockito.spy(new RunNotifier()); + RunListener listener = Mockito.mock(RunListener.class); + notifier.addListener(listener); + Bundle ignores = new Bundle(); + ignores.putString(LongevityClassRunner.FILTER_OPTION, FailingTest.class.getCanonicalName()); + mRunner = spy(new LongevityClassRunner(FailingTest.class, ignores)); + mRunner.run(notifier); + verify(listener, times(1)).testIgnored(any()); + } + private List<FrameworkMethod> getMethodNameMatcher(String methodName) { return argThat( l -> diff --git a/libraries/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java b/libraries/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java index 6e876d186..7c2e5fdc1 100644 --- a/libraries/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java +++ b/libraries/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java @@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.longThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -39,6 +40,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; import org.junit.runner.notification.RunNotifier; import org.junit.runners.JUnit4; import org.junit.runners.model.InitializationError; @@ -257,6 +259,42 @@ public class ScheduledScenarioRunnerTest { getWithinMarginMatcher(timeoutMs, TIMEOUT_ERROR_MARGIN_MS)); } + /** Test that an ignored scenario still includes the timeout dictated in a profile. */ + @Test + public void testIgnoredScenario_doesIdle() throws InitializationError, Exception { + long timeoutMs = TimeUnit.SECONDS.toMillis(5); + Scenario testScenario = + Scenario.newBuilder() + .setAt("00:00:00") + .setJourney(SampleProfileSuite.PassingTest.class.getName()) + .setAfterTest(AfterTest.EXIT) + .build(); + Bundle ignores = new Bundle(); + ignores.putString( + LongevityClassRunner.FILTER_OPTION, + SampleProfileSuite.PassingTest.class.getCanonicalName()); + ScheduledScenarioRunner runner = + spy( + new ScheduledScenarioRunner( + SampleProfileSuite.PassingTest.class, + testScenario, + timeoutMs, + true, + ignores)); + RunNotifier notifier = spy(new RunNotifier()); + RunListener listener = mock(RunListener.class); + notifier.addListener(listener); + runner.run(notifier); + // There should not be idle before teardown. + verify(runner, never()).performIdleBeforeTeardown(anyLong()); + // Ensure the test was ignored via listener. + verify(listener, times(1)).testIgnored(any()); + // Idles before the next scenario; duration should be roughly equal to the timeout. + verify(runner, times(1)) + .performIdleBeforeNextScenario( + getWithinMarginMatcher(timeoutMs, TIMEOUT_ERROR_MARGIN_MS)); + } + /** Test that the last test does not have idle after it, regardless of its AfterTest policy. */ @Test public void testLastScenarioDoesNotIdle() throws InitializationError { |