diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2021-10-06 00:31:53 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-10-06 00:31:53 +0000 |
commit | 76a39932afc6e8c2676bf5fbee66db84a84309b3 (patch) | |
tree | 0f65c95e55c2dbdfeab4c3bbae85c637c3077e7f | |
parent | cc8cb9d11483ff295d160ccef4806f4d7d343d0f (diff) | |
parent | 118cd5eb5618b149d9c382940b3fd2078294a149 (diff) | |
download | platform_testing-76a39932afc6e8c2676bf5fbee66db84a84309b3.tar.gz |
Merge "Enable runtime test-level rule injection in microbenchmarks." into sc-dev
2 files changed, 114 insertions, 5 deletions
diff --git a/libraries/health/runners/microbenchmark/src/android/platform/test/microbenchmark/Microbenchmark.java b/libraries/health/runners/microbenchmark/src/android/platform/test/microbenchmark/Microbenchmark.java index e82fd3e18..b6c6f134f 100644 --- a/libraries/health/runners/microbenchmark/src/android/platform/test/microbenchmark/Microbenchmark.java +++ b/libraries/health/runners/microbenchmark/src/android/platform/test/microbenchmark/Microbenchmark.java @@ -23,6 +23,7 @@ import android.os.BatteryManager; import android.os.Bundle; import android.os.SystemClock; import android.platform.test.composer.Iterate; +import android.platform.test.rule.DynamicRuleChain; import android.platform.test.rule.TracePointRule; import android.util.Log; import androidx.annotation.VisibleForTesting; @@ -32,6 +33,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -71,6 +73,10 @@ public class Microbenchmark extends BlockJUnit4ClassRunner { }; @VisibleForTesting static final String MIN_BATTERY_LEVEL_OPTION = "min-battery"; @VisibleForTesting static final String MAX_BATTERY_DRAIN_OPTION = "max-battery-drain"; + // Use these options to inject rules at runtime via the command line. For details, please see + // documentation for DynamicRuleChain. + @VisibleForTesting static final String DYNAMIC_OUTER_RULES_OPTION = "outer-rules"; + @VisibleForTesting static final String DYNAMIC_INNER_RULES_OPTION = "inner-rules"; // Options for aligning with the battery charge (coulomb) counter for power tests. We want to // start microbenchmarks just after the coulomb counter has decremented to account for the @@ -275,7 +281,11 @@ public class Microbenchmark extends BlockJUnit4ClassRunner { /** Re-implement the private rules wrapper from {@link BlockJUnit4ClassRunner} in JUnit 4.12. */ private Statement withRules(FrameworkMethod method, Object target, Statement statement) { Statement result = statement; - List<TestRule> testRules = getTestRules(target); + List<TestRule> testRules = new ArrayList<>(); + // Inner dynamic rules should be included first because RunRules applies rules inside-out. + testRules.add(new DynamicRuleChain(DYNAMIC_INNER_RULES_OPTION, mArguments)); + testRules.addAll(getTestRules(target)); + testRules.add(new DynamicRuleChain(DYNAMIC_OUTER_RULES_OPTION, mArguments)); // Apply legacy MethodRules, if they don't overlap with TestRules. for (org.junit.rules.MethodRule each : rules(target)) { if (!testRules.contains(each)) { @@ -283,10 +293,7 @@ public class Microbenchmark extends BlockJUnit4ClassRunner { } } // Apply modern, method-level TestRules in outer statements. - result = - testRules.isEmpty() - ? statement - : new RunRules(result, testRules, describeChild(method)); + result = new RunRules(result, testRules, describeChild(method)); return result; } diff --git a/libraries/health/runners/microbenchmark/tests/src/android/platform/test/microbenchmark/MicrobenchmarkTest.java b/libraries/health/runners/microbenchmark/tests/src/android/platform/test/microbenchmark/MicrobenchmarkTest.java index 8d4cd822a..0b44d1aac 100644 --- a/libraries/health/runners/microbenchmark/tests/src/android/platform/test/microbenchmark/MicrobenchmarkTest.java +++ b/libraries/health/runners/microbenchmark/tests/src/android/platform/test/microbenchmark/MicrobenchmarkTest.java @@ -25,10 +25,12 @@ import static org.mockito.Mockito.verify; import android.os.Bundle; import android.os.SystemClock; import android.platform.test.microbenchmark.Microbenchmark.TerminateEarlyException; +import android.platform.test.rule.TestWatcher; import android.platform.test.rule.TracePointRule; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -51,6 +53,15 @@ import java.util.List; */ @RunWith(JUnit4.class) public final class MicrobenchmarkTest { + // Static logs are needed to validate dynamic rules, which are instantiated reflectively and + // cannot access non-static variables. + private static List<String> sLogs = new ArrayList<>(); + + @Before + public void setUp() { + sLogs.clear(); + } + /** * Tests that iterations are respected for microbenchmark tests. */ @@ -408,6 +419,57 @@ public final class MicrobenchmarkTest { } /** + * Test successive iteration will be executed when the terminate on test fail option is + * disabled. + */ + @Test + public void testDynamicRuleInjection() throws InitializationError { + Bundle args = new Bundle(); + args.putString("iterations", "2"); + args.putString("rename-iterations", "false"); + args.putString("terminate-on-test-fail", "false"); + args.putString(Microbenchmark.DYNAMIC_INNER_RULES_OPTION, LoggingRule1.class.getName()); + args.putString(Microbenchmark.DYNAMIC_OUTER_RULES_OPTION, LoggingRule2.class.getName()); + LoggingMicrobenchmark loggingRunner = + new LoggingMicrobenchmark(LoggingTestWithRule.class, args); + loggingRunner.setOperationLog(sLogs); + new JUnitCore().run(loggingRunner); + assertThat(sLogs) + .containsExactly( + "logging rule 2 starting", + "hardcoded rule starting", + "logging rule 1 starting", + "before", + "tight before", + "begin: testMethod(" + + "android.platform.test.microbenchmark.MicrobenchmarkTest" + + "$LoggingTestWithRule)", + "test", + "end", + "tight after", + "after", + "logging rule 1 finished", + "hardcoded rule finished", + "logging rule 2 finished", + "logging rule 2 starting", + "hardcoded rule starting", + "logging rule 1 starting", + "before", + "tight before", + "begin: testMethod(" + + "android.platform.test.microbenchmark.MicrobenchmarkTest" + + "$LoggingTestWithRule)", + "test", + "end", + "tight after", + "after", + "logging rule 1 finished", + "hardcoded rule finished", + "logging rule 2 finished") + .inOrder(); + } + + /** * An extensions of the {@link Microbenchmark} runner that logs the start and end of collecting * traces. It also passes the operation log to the provided test {@code Class}, if it is a * {@link LoggingTest}. This is used for ensuring the proper order for evaluating test {@link @@ -503,10 +565,50 @@ public final class MicrobenchmarkTest { } } + public static class LoggingTestWithRule extends LoggingTest { + @Rule + public TestRule hardCodedRule = + new TestWatcher() { + @Override + public void starting(Description description) { + sLogs.add("hardcoded rule starting"); + } + + @Override + public void finished(Description description) { + sLogs.add("hardcoded rule finished"); + } + }; + } + public static class LoggingFailedTest extends LoggingTest { @Test public void testMethod() { throw new RuntimeException("I failed."); } } + + public static class LoggingRule1 extends TestWatcher { + @Override + public void starting(Description description) { + sLogs.add("logging rule 1 starting"); + } + + @Override + public void finished(Description description) { + sLogs.add("logging rule 1 finished"); + } + } + + public static class LoggingRule2 extends TestWatcher { + @Override + public void starting(Description description) { + sLogs.add("logging rule 2 starting"); + } + + @Override + public void finished(Description description) { + sLogs.add("logging rule 2 finished"); + } + } } |