Add support for indexed profiles.
Bug: 143773722
Test: included
Change-Id: I2ccaaf21ae9c1b9c517bf3c5773ca36841c63a2f
diff --git a/libraries/health/runners/longevity/platform/samples/assets/sample_indexed_profile.textpb b/libraries/health/runners/longevity/platform/samples/assets/sample_indexed_profile.textpb
new file mode 100644
index 0000000..4a4ade4
--- /dev/null
+++ b/libraries/health/runners/longevity/platform/samples/assets/sample_indexed_profile.textpb
@@ -0,0 +1,17 @@
+schedule: INDEXED
+scenarios [{
+ index: 1
+ journey: "android.platform.test.longevity.samples.SimpleSuite$PassingTest"
+}, {
+ index: 2
+ journey: "android.platform.test.longevity.samples.SimpleSuite$FailingTest"
+}, {
+ index: 3
+ journey: "android.platform.test.longevity.samples.SimpleSuite$PassingTest"
+}, {
+ index: 4
+ journey: "android.platform.test.longevity.samples.SimpleSuite$PassingTest"
+}, {
+ index: 5
+ journey: "android.platform.test.longevity.samples.SimpleSuite$FailingTest"
+}]
diff --git a/libraries/health/runners/longevity/platform/samples/assets/sample_profile.textpb b/libraries/health/runners/longevity/platform/samples/assets/sample_scheduled_profile.textpb
similarity index 100%
rename from libraries/health/runners/longevity/platform/samples/assets/sample_profile.textpb
rename to libraries/health/runners/longevity/platform/samples/assets/sample_scheduled_profile.textpb
diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/Profile.java b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/Profile.java
index 4cb3933..b981276 100644
--- a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/Profile.java
+++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/Profile.java
@@ -79,6 +79,17 @@
}
}
+ // Comparator for sorting indexed CUJs.
+ private static class ScenarioIndexedComparator implements Comparator<Scenario> {
+ public int compare(Scenario s1, Scenario s2) {
+ if (!(s1.hasIndex() && s2.hasIndex())) {
+ throw new IllegalArgumentException(
+ "Scenarios in indexed profiles must have indexes.");
+ }
+ return Integer.compare(s1.getIndex(), s2.getIndex());
+ }
+ }
+
public Profile(Bundle args) {
super();
// Set the timestamp parser to UTC to get test timstamps as "time elapsed since zero".
@@ -105,6 +116,8 @@
throw new IllegalArgumentException(
"Cannot parse the timestamp of the first scenario.", e);
}
+ } else if (mConfiguration.getSchedule().equals(Schedule.INDEXED)) {
+ Collections.sort(mOrderedScenariosList, new ScenarioIndexedComparator());
} else {
throw new UnsupportedOperationException(
"Only scheduled profiles are currently supported.");
diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java
index 2baa274..d557780 100644
--- a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java
+++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java
@@ -147,6 +147,11 @@
mProfile.getCurrentScenario(),
timeout,
mProfile.hasNextScheduledScenario());
+
+ case INDEXED:
+ return getIndexedRunner(
+ (BlockJUnit4ClassRunner) runner, mProfile.getCurrentScenario());
+
default:
throw new RuntimeException(
String.format(
@@ -173,4 +178,19 @@
e);
}
}
+
+ /** Replace a runner with {@link ScenarioRunner} for features specific to indexed profiles. */
+ @VisibleForTesting
+ protected ScenarioRunner getIndexedRunner(BlockJUnit4ClassRunner runner, Scenario scenario) {
+ Class<?> testClass = runner.getTestClass().getJavaClass();
+ try {
+ return new ScenarioRunner(testClass, scenario);
+ } catch (InitializationError e) {
+ throw new RuntimeException(
+ String.format(
+ "Unable to run scenario %s with an indexed runner.",
+ runner.getDescription().getDisplayName()),
+ e);
+ }
+ }
}
diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScenarioRunner.java b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScenarioRunner.java
new file mode 100644
index 0000000..33e4056
--- /dev/null
+++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScenarioRunner.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed 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 android.platform.test.longevity;
+
+import android.os.Bundle;
+import android.platform.test.longevity.proto.Configuration.Scenario;
+import android.platform.test.longevity.proto.Configuration.Scenario.ExtraArg;
+import androidx.annotation.VisibleForTesting;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+
+/** A {@link BlockJUnit4ClassRunner} that runs a test class with profile-specified options. */
+public class ScenarioRunner extends LongevityClassRunner {
+ private final Scenario mScenario;
+ private final Bundle mArguments;
+
+ public ScenarioRunner(Class<?> klass, Scenario scenario) throws InitializationError {
+ this(klass, scenario, InstrumentationRegistry.getArguments());
+ }
+
+ @VisibleForTesting
+ ScenarioRunner(Class<?> klass, Scenario scenario, Bundle arguments) throws InitializationError {
+ super(klass, arguments);
+ mScenario = scenario;
+ mArguments = arguments;
+ }
+
+ @Override
+ protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
+ // Keep a copy of the bundle arguments for restoring later.
+ Bundle modifiedArguments = mArguments.deepCopy();
+ for (ExtraArg argPair : mScenario.getExtrasList()) {
+ if (argPair.getKey() == null || argPair.getValue() == null) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Each extra arg entry in scenario must have both a key and a value,"
+ + " but scenario is %s.",
+ mScenario.toString()));
+ }
+ modifiedArguments.putString(argPair.getKey(), argPair.getValue());
+ }
+ // Swap the arguments, run the scenario, and then restore arguments.
+ InstrumentationRegistry.registerInstance(
+ InstrumentationRegistry.getInstrumentation(), modifiedArguments);
+ super.runChild(method, notifier);
+ InstrumentationRegistry.registerInstance(
+ InstrumentationRegistry.getInstrumentation(), mArguments);
+ }
+}
diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java
index 1c4043e..c5a9ced 100644
--- a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java
+++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java
@@ -38,6 +38,8 @@
/**
* A {@link BlockJUnit4ClassRunner} that runs a test class with a specified timeout and optionally
* performs an idle before teardown (staying inside the app for Android CUJs).
+ *
+ * <p>TODO(b/146215435): Refactor to extends the index-based {@link ScenarioRunner}.
*/
public class ScheduledScenarioRunner extends LongevityClassRunner {
// A leeway to ensure that the teardown steps in @After and @AfterClass has time to finish.
diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/profile.proto b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/profile.proto
index 37bed59..d05fd5a 100644
--- a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/profile.proto
+++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/profile.proto
@@ -21,17 +21,17 @@
message Configuration {
// Schedule used to run the profile.
- // TODO(b/122323704): Implement ordered profile.
enum Schedule {
TIMESTAMPED = 1;
+ INDEXED = 2;
}
optional Schedule schedule = 1 [default = TIMESTAMPED];
// Information for each scenario.
message Scenario {
oneof schedule {
- // Timestamp to run the scenario in HH:MM:SS.
- string at = 1;
+ string at = 1; // A timestamp (HH:MM:SS) for when to run the scenario.
+ int32 index = 2; // An index for the relative order of the scenario.
}
// Reference to the CUJ (<package>.<class>).
optional string journey = 3;
diff --git a/libraries/health/runners/longevity/platform/tests/assets/testIndexedScheduling_respectsSchedule.textpb b/libraries/health/runners/longevity/platform/tests/assets/testIndexedScheduling_respectsSchedule.textpb
new file mode 100644
index 0000000..6f67f1e
--- /dev/null
+++ b/libraries/health/runners/longevity/platform/tests/assets/testIndexedScheduling_respectsSchedule.textpb
@@ -0,0 +1,11 @@
+schedule: INDEXED
+scenarios [{
+ index: 1
+ journey: "android.platform.test.longevity.samples.testing.SampleBasicProfileSuite$PassingTest1"
+}, {
+ index: 2
+ journey: "android.platform.test.longevity.samples.testing.SampleBasicProfileSuite$PassingTest2"
+}, {
+ index: 3
+ journey: "android.platform.test.longevity.samples.testing.SampleBasicProfileSuite$PassingTest1"
+}]
diff --git a/libraries/health/runners/longevity/platform/tests/assets/testScheduling_respectsSchedule.textpb b/libraries/health/runners/longevity/platform/tests/assets/testTimestampScheduling_respectsSchedule.textpb
similarity index 78%
rename from libraries/health/runners/longevity/platform/tests/assets/testScheduling_respectsSchedule.textpb
rename to libraries/health/runners/longevity/platform/tests/assets/testTimestampScheduling_respectsSchedule.textpb
index 4c02f42..f68cc2f 100644
--- a/libraries/health/runners/longevity/platform/tests/assets/testScheduling_respectsSchedule.textpb
+++ b/libraries/health/runners/longevity/platform/tests/assets/testTimestampScheduling_respectsSchedule.textpb
@@ -1,10 +1,10 @@
schedule: TIMESTAMPED
scenarios [{
at: "00:00:01"
- journey: "android.platform.test.longevity.samples.testing.SampleProfileSuite$LongIdleTest"
+ journey: "android.platform.test.longevity.samples.testing.SampleTimedProfileSuite$LongIdleTest"
after_test: STAY_IN_APP
}, {
at: "00:00:10"
- journey: "android.platform.test.longevity.samples.testing.SampleProfileSuite$PassingTest"
+ journey: "android.platform.test.longevity.samples.testing.SampleTimedProfileSuite$PassingTest"
after_test: STAY_IN_APP
}]
diff --git a/libraries/health/runners/longevity/platform/tests/assets/testScheduling_respectsSuiteTimeout.textpb b/libraries/health/runners/longevity/platform/tests/assets/testTimestampScheduling_respectsSuiteTimeout.textpb
similarity index 77%
rename from libraries/health/runners/longevity/platform/tests/assets/testScheduling_respectsSuiteTimeout.textpb
rename to libraries/health/runners/longevity/platform/tests/assets/testTimestampScheduling_respectsSuiteTimeout.textpb
index 7c32fa7..06af14f 100644
--- a/libraries/health/runners/longevity/platform/tests/assets/testScheduling_respectsSuiteTimeout.textpb
+++ b/libraries/health/runners/longevity/platform/tests/assets/testTimestampScheduling_respectsSuiteTimeout.textpb
@@ -1,9 +1,9 @@
schedule: TIMESTAMPED
scenarios [{
at: "00:00:01"
- journey: "android.platform.test.longevity.samples.testing.SampleProfileSuite$PassingTest"
+ journey: "android.platform.test.longevity.samples.testing.SampleTimedProfileSuite$PassingTest"
}, {
at: "00:00:05"
- journey: "android.platform.test.longevity.samples.testing.SampleProfileSuite$LongIdleTest"
+ journey: "android.platform.test.longevity.samples.testing.SampleTimedProfileSuite$LongIdleTest"
after_test: STAY_IN_APP
}]
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java
index d42ccd7..14d66de 100644
--- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java
@@ -30,7 +30,8 @@
import android.host.test.longevity.listener.TimeoutTerminator;
import android.os.Bundle;
import android.os.SystemClock;
-import android.platform.test.longevity.samples.testing.SampleProfileSuite;
+import android.platform.test.longevity.samples.testing.SampleBasicProfileSuite;
+import android.platform.test.longevity.samples.testing.SampleTimedProfileSuite;
import android.platform.test.scenario.annotation.Scenario;
import org.junit.Assert;
@@ -143,19 +144,21 @@
@RunWith(Parameterized.class)
public static class NotSupportedRunner extends BasicScenario {}
- /** Test that a profile's scheduling is followed. */
+ /** Test that a timestamped profile's scheduling is followed. */
@Test
- public void testScheduling_respectsSchedule() throws InitializationError {
+ public void testTimestampScheduling_respectsSchedule() throws InitializationError {
// TODO(harrytczhang@): Find a way to run this without relying on actual idles.
// Arguments with the profile under test.
Bundle args = new Bundle();
- args.putString(Profile.PROFILE_OPTION_NAME, "testScheduling_respectsSchedule");
+ args.putString(Profile.PROFILE_OPTION_NAME, "testTimestampScheduling_respectsSchedule");
// Scenario names from the profile.
final String firstScenarioName =
- "android.platform.test.longevity.samples.testing.SampleProfileSuite$LongIdleTest";
+ "android.platform.test.longevity.samples.testing."
+ + "SampleTimedProfileSuite$LongIdleTest";
final String secondScenarioName =
- "android.platform.test.longevity.samples.testing.SampleProfileSuite$PassingTest";
+ "android.platform.test.longevity.samples.testing."
+ + "SampleTimedProfileSuite$PassingTest";
// Stores the start time of the test run for the suite. Using AtomicLong here as the time
// should be initialized when run() is called on the suite, but Java does not want
// assignment to local varaible in lambda expressions. AtomicLong allows for using the
@@ -164,7 +167,7 @@
ProfileSuite suite =
spy(
new ProfileSuite(
- SampleProfileSuite.class,
+ SampleTimedProfileSuite.class,
new AllDefaultPossibilitiesBuilder(true),
mInstrumentation,
mContext,
@@ -242,22 +245,22 @@
argThat(notifier -> notifier.equals(mRunNotifier)));
}
- /** Test that a profile's last scenario is bounded by the suite timeout. */
+ /** Test that a timestamp profile's last scenario is bounded by the suite timeout. */
@Test
- public void testScheduling_respectsSuiteTimeout() throws InitializationError {
+ public void testTimestampScheduling_respectsSuiteTimeout() throws InitializationError {
long suiteTimeoutMsecs = TimeUnit.SECONDS.toMillis(10);
ArgumentCaptor<Failure> failureCaptor = ArgumentCaptor.forClass(Failure.class);
// Arguments with the profile under test and suite timeout.
Bundle args = new Bundle();
- args.putString(Profile.PROFILE_OPTION_NAME, "testScheduling_respectsSuiteTimeout");
+ args.putString(Profile.PROFILE_OPTION_NAME, "testTimestampScheduling_respectsSuiteTimeout");
args.putString(TimeoutTerminator.OPTION, String.valueOf(suiteTimeoutMsecs));
// Construct and run the profile suite.
ProfileSuite suite =
spy(
new ProfileSuite(
- SampleProfileSuite.class,
+ SampleTimedProfileSuite.class,
new AllDefaultPossibilitiesBuilder(true),
mInstrumentation,
mContext,
@@ -294,4 +297,64 @@
});
Assert.assertTrue(correctTestTimedOutExceptionFired);
}
+
+ /** Test that an indexed profile's scheduling is followed. */
+ @Test
+ public void testIndexedScheduling_respectsSchedule() throws InitializationError {
+ // Arguments with the profile under test.
+ Bundle args = new Bundle();
+ args.putString(Profile.PROFILE_OPTION_NAME, "testIndexedScheduling_respectsSchedule");
+ // Scenario names from the profile.
+ final String firstScenarioName =
+ "android.platform.test.longevity.samples.testing."
+ + "SampleBasicProfileSuite$PassingTest1";
+ final String secondScenarioName =
+ "android.platform.test.longevity.samples.testing."
+ + "SampleBasicProfileSuite$PassingTest2";
+ final String thirdScenarioName =
+ "android.platform.test.longevity.samples.testing."
+ + "SampleBasicProfileSuite$PassingTest1";
+ ProfileSuite suite =
+ spy(
+ new ProfileSuite(
+ SampleBasicProfileSuite.class,
+ new AllDefaultPossibilitiesBuilder(true),
+ mInstrumentation,
+ mContext,
+ args));
+
+ InOrder inOrderVerifier = inOrder(suite);
+
+ suite.run(mRunNotifier);
+ // Verify that the first scenario is started.
+ inOrderVerifier
+ .verify(suite)
+ .runChild(
+ argThat(
+ runner ->
+ runner.getDescription()
+ .getDisplayName()
+ .equals(firstScenarioName)),
+ argThat(notifier -> notifier.equals(mRunNotifier)));
+ // Verify that the second scenario is started.
+ inOrderVerifier
+ .verify(suite)
+ .runChild(
+ argThat(
+ runner ->
+ runner.getDescription()
+ .getDisplayName()
+ .equals(secondScenarioName)),
+ argThat(notifier -> notifier.equals(mRunNotifier)));
+ // Verify that the third scenario is started.
+ inOrderVerifier
+ .verify(suite)
+ .runChild(
+ argThat(
+ runner ->
+ runner.getDescription()
+ .getDisplayName()
+ .equals(thirdScenarioName)),
+ argThat(notifier -> notifier.equals(mRunNotifier)));
+ }
}
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScenarioRunnerTest.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScenarioRunnerTest.java
new file mode 100644
index 0000000..a6f3c50
--- /dev/null
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScenarioRunnerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed 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 android.platform.test.longevity;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.os.Bundle;
+import android.platform.test.longevity.proto.Configuration.Scenario;
+import android.platform.test.longevity.proto.Configuration.Scenario.ExtraArg;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.JUnit4;
+import org.junit.runners.model.InitializationError;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.exceptions.base.MockitoAssertionError;
+
+import java.util.HashSet;
+import java.util.List;
+
+/** Unit tests for the {@link ScenarioRunner} runner. */
+@RunWith(JUnit4.class)
+public class ScenarioRunnerTest {
+
+ @Mock private RunNotifier mRunNotifier;
+
+ private static final String ASSERTION_FAILURE_MESSAGE = "Test assertion failed";
+
+ public static class ArgumentTest {
+ public static final String TEST_ARG = "test-arg-test-only";
+ public static final String TEST_ARG_DEFAULT = "default";
+ public static final String TEST_ARG_OVERRIDE = "not default";
+
+ @Before
+ public void setUp() {
+ // The actual argument testing happens here as this is where instrumentation args are
+ // parsed in the CUJs.
+ String argValue =
+ InstrumentationRegistry.getArguments().getString(TEST_ARG, TEST_ARG_DEFAULT);
+ Assert.assertEquals(ASSERTION_FAILURE_MESSAGE, argValue, TEST_ARG_OVERRIDE);
+ }
+
+ @Test
+ public void dummyTest() {
+ // Does nothing; always passes.
+ }
+ }
+
+ // Holds the state of the instrumentation args before each test for restoring after, as one test
+ // might affect the state of another otherwise.
+ // TODO(b/124239142): Avoid manipulating the instrumentation args here.
+ private Bundle mArgumentsBeforeTest;
+
+ @Before
+ public void setUpSuite() throws InitializationError {
+ initMocks(this);
+ mArgumentsBeforeTest = InstrumentationRegistry.getArguments();
+ }
+
+ @After
+ public void restoreSuite() {
+ InstrumentationRegistry.registerInstance(
+ InstrumentationRegistry.getInstrumentation(), mArgumentsBeforeTest);
+ }
+
+ /** Test that the "extras" in a scenario is properly registered before the test. */
+ @Test
+ public void testExtraArgs_registeredBeforeTest() throws Throwable {
+ Scenario testScenario =
+ Scenario.newBuilder()
+ .setIndex(1)
+ .setJourney(ArgumentTest.class.getName())
+ .addExtras(
+ ExtraArg.newBuilder()
+ .setKey(ArgumentTest.TEST_ARG)
+ .setValue(ArgumentTest.TEST_ARG_OVERRIDE))
+ .build();
+ ScenarioRunner runner = spy(new ScenarioRunner(ArgumentTest.class, testScenario));
+ runner.run(mRunNotifier);
+ verifyForAssertionFailures(mRunNotifier);
+ }
+
+ /** Test that the "extras" in a scenario is properly un-registered after the test. */
+ @Test
+ public void testExtraArgs_unregisteredAfterTest() throws Throwable {
+ Bundle argsBeforeTest = InstrumentationRegistry.getArguments();
+ Scenario testScenario =
+ Scenario.newBuilder()
+ .setIndex(1)
+ .setJourney(ArgumentTest.class.getName())
+ .addExtras(
+ ExtraArg.newBuilder()
+ .setKey(ArgumentTest.TEST_ARG)
+ .setValue(ArgumentTest.TEST_ARG_OVERRIDE))
+ .build();
+ ScenarioRunner runner = spy(new ScenarioRunner(ArgumentTest.class, testScenario));
+ runner.run(mRunNotifier);
+ Bundle argsAfterTest = InstrumentationRegistry.getArguments();
+ Assert.assertTrue(bundlesContainSameStringKeyValuePairs(argsBeforeTest, argsAfterTest));
+ }
+
+ /**
+ * Verify that no test failure is fired because of an assertion failure in the stubbed methods.
+ * If the verification fails, check whether it's due the injected assertions failing. If yes,
+ * throw that exception out; otherwise, throw the first exception.
+ */
+ private void verifyForAssertionFailures(final RunNotifier notifier) throws Throwable {
+ try {
+ verify(notifier, never()).fireTestFailure(any());
+ } catch (MockitoAssertionError e) {
+ ArgumentCaptor<Failure> failureCaptor = ArgumentCaptor.forClass(Failure.class);
+ verify(notifier, atLeastOnce()).fireTestFailure(failureCaptor.capture());
+ List<Failure> failures = failureCaptor.getAllValues();
+ // Go through the failures, look for an known failure case from the above exceptions
+ // and throw the exception in the first one out if any.
+ for (Failure failure : failures) {
+ if (failure.getException().getMessage().contains(ASSERTION_FAILURE_MESSAGE)) {
+ throw failure.getException();
+ }
+ }
+ // Otherwise, throw the exception from the first failure reported.
+ throw failures.get(0).getException();
+ }
+ }
+
+ /**
+ * Helper method to check whether two {@link Bundle}s are equal since the built-in {@code
+ * equals} is not properly overridden.
+ */
+ private boolean bundlesContainSameStringKeyValuePairs(Bundle b1, Bundle b2) {
+ if (b1.size() != b2.size()) {
+ return false;
+ }
+ HashSet<String> allKeys = new HashSet<String>(b1.keySet());
+ allKeys.addAll(b2.keySet());
+ for (String key : allKeys) {
+ if (b1.getString(key) != null) {
+ // If key is in b1 and corresponds to a string, check whether this key corresponds
+ // to the same value in b2.
+ if (!b1.getString(key).equals(b2.getString(key))) {
+ return false;
+ }
+ } else if (b2.getString(key) != null) {
+ // Otherwise if b2 has a string at this key, return false since we know that b1 does
+ // not have a string at this key.
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java
index 7afec46..e8d1218 100644
--- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java
@@ -31,7 +31,7 @@
import android.platform.test.longevity.proto.Configuration.Scenario;
import android.platform.test.longevity.proto.Configuration.Scenario.AfterTest;
import android.platform.test.longevity.proto.Configuration.Scenario.ExtraArg;
-import android.platform.test.longevity.samples.testing.SampleProfileSuite;
+import android.platform.test.longevity.samples.testing.SampleTimedProfileSuite;
import androidx.test.InstrumentationRegistry;
import org.junit.Assert;
@@ -114,13 +114,13 @@
Scenario testScenario =
Scenario.newBuilder()
.setAt("00:00:00")
- .setJourney(SampleProfileSuite.LongIdleTest.class.getName())
+ .setJourney(SampleTimedProfileSuite.LongIdleTest.class.getName())
.setAfterTest(AfterTest.STAY_IN_APP)
.build();
ScheduledScenarioRunner runner =
spy(
new ScheduledScenarioRunner(
- SampleProfileSuite.LongIdleTest.class,
+ SampleTimedProfileSuite.LongIdleTest.class,
testScenario,
timeoutMs,
true));
@@ -157,13 +157,13 @@
Scenario testScenario =
Scenario.newBuilder()
.setAt("00:00:00")
- .setJourney(SampleProfileSuite.LongIdleTest.class.getName())
+ .setJourney(SampleTimedProfileSuite.LongIdleTest.class.getName())
.setAfterTest(AfterTest.STAY_IN_APP)
.build();
ScheduledScenarioRunner runner =
spy(
new ScheduledScenarioRunner(
- SampleProfileSuite.LongIdleTest.class,
+ SampleTimedProfileSuite.LongIdleTest.class,
testScenario,
TimeUnit.SECONDS.toMillis(6),
true));
@@ -181,13 +181,13 @@
Scenario testScenario =
Scenario.newBuilder()
.setAt("00:00:00")
- .setJourney(SampleProfileSuite.LongIdleTest.class.getName())
+ .setJourney(SampleTimedProfileSuite.LongIdleTest.class.getName())
.setAfterTest(AfterTest.STAY_IN_APP)
.build();
ScheduledScenarioRunner runner =
spy(
new ScheduledScenarioRunner(
- SampleProfileSuite.LongIdleTest.class,
+ SampleTimedProfileSuite.LongIdleTest.class,
testScenario,
TimeUnit.SECONDS.toMillis(6),
true));
@@ -210,13 +210,13 @@
Scenario testScenario =
Scenario.newBuilder()
.setAt("00:00:00")
- .setJourney(SampleProfileSuite.PassingTest.class.getName())
+ .setJourney(SampleTimedProfileSuite.PassingTest.class.getName())
.setAfterTest(AfterTest.STAY_IN_APP)
.build();
ScheduledScenarioRunner runner =
spy(
new ScheduledScenarioRunner(
- SampleProfileSuite.PassingTest.class,
+ SampleTimedProfileSuite.PassingTest.class,
testScenario,
timeoutMs,
true));
@@ -242,13 +242,13 @@
Scenario testScenario =
Scenario.newBuilder()
.setAt("00:00:00")
- .setJourney(SampleProfileSuite.PassingTest.class.getName())
+ .setJourney(SampleTimedProfileSuite.PassingTest.class.getName())
.setAfterTest(AfterTest.EXIT)
.build();
ScheduledScenarioRunner runner =
spy(
new ScheduledScenarioRunner(
- SampleProfileSuite.PassingTest.class,
+ SampleTimedProfileSuite.PassingTest.class,
testScenario,
timeoutMs,
true));
@@ -270,17 +270,17 @@
Scenario testScenario =
Scenario.newBuilder()
.setAt("00:00:00")
- .setJourney(SampleProfileSuite.PassingTest.class.getName())
+ .setJourney(SampleTimedProfileSuite.PassingTest.class.getName())
.setAfterTest(AfterTest.EXIT)
.build();
Bundle ignores = new Bundle();
ignores.putString(
LongevityClassRunner.FILTER_OPTION,
- SampleProfileSuite.PassingTest.class.getCanonicalName());
+ SampleTimedProfileSuite.PassingTest.class.getCanonicalName());
ScheduledScenarioRunner runner =
spy(
new ScheduledScenarioRunner(
- SampleProfileSuite.PassingTest.class,
+ SampleTimedProfileSuite.PassingTest.class,
testScenario,
timeoutMs,
true,
@@ -307,13 +307,13 @@
Scenario testScenario =
Scenario.newBuilder()
.setAt("00:00:00")
- .setJourney(SampleProfileSuite.PassingTest.class.getName())
+ .setJourney(SampleTimedProfileSuite.PassingTest.class.getName())
.setAfterTest(AfterTest.STAY_IN_APP)
.build();
ScheduledScenarioRunner runner =
spy(
new ScheduledScenarioRunner(
- SampleProfileSuite.PassingTest.class,
+ SampleTimedProfileSuite.PassingTest.class,
testScenario,
TimeUnit.SECONDS.toMillis(6),
false));
@@ -380,7 +380,7 @@
/**
* Verify that no test failure is fired because of an assertion failure in the stubbed methods.
- * If the verfication fails, check whether it's due the injected assertions failing. If yes,
+ * If the verification fails, check whether it's due the injected assertions failing. If yes,
* throw that exception out; otherwise, throw the first exception.
*/
private void verifyForAssertionFailures(final RunNotifier notifier) throws Throwable {
@@ -404,7 +404,7 @@
/**
* Helper method to check whether two {@link Bundle}s are equal since the built-in {@code
- * equals} is not properly overriden.
+ * equals} is not properly overridden.
*/
private boolean bundlesContainSameStringKeyValuePairs(Bundle b1, Bundle b2) {
if (b1.size() != b2.size()) {
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleProfileSuite.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleBasicProfileSuite.java
similarity index 64%
copy from libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleProfileSuite.java
copy to libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleBasicProfileSuite.java
index 2b1bf10..2c0cd5f 100644
--- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleProfileSuite.java
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleBasicProfileSuite.java
@@ -16,53 +16,38 @@
package android.platform.test.longevity.samples.testing;
-import android.os.SystemClock;
import android.platform.test.longevity.ProfileSuite;
import android.platform.test.scenario.annotation.Scenario;
-import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.runners.Suite.SuiteClasses;
-import java.util.concurrent.TimeUnit;
-
@RunWith(ProfileSuite.class)
@SuiteClasses({
- SampleProfileSuite.LongIdleTest.class,
- SampleProfileSuite.PassingTest.class,
+ SampleBasicProfileSuite.PassingTest1.class,
+ SampleBasicProfileSuite.PassingTest2.class,
})
/** Sample device-side test cases using a profile. */
-public class SampleProfileSuite {
+public class SampleBasicProfileSuite {
+
@Scenario
@RunWith(JUnit4.class)
- public static class LongIdleTest {
+ public static class PassingTest1 {
@Test
- public void testLongIdle() {
- SystemClock.sleep(TimeUnit.SECONDS.toMillis(10));
- }
-
- // Simulates a quick teardown step.
- @AfterClass
- public static void dummyTearDown() {
- SystemClock.sleep(100);
+ public void testPassing() {
+ Assert.assertEquals(1, 1);
}
}
@Scenario
@RunWith(JUnit4.class)
- public static class PassingTest {
+ public static class PassingTest2 {
@Test
public void testPassing() {
- Assert.assertEquals(1, 1);
- }
-
- // Simulates a quick teardown step.
- @AfterClass
- public static void dummyTearDown() {
- SystemClock.sleep(100);
+ Assert.assertEquals(2, 2);
}
}
}
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleProfileSuite.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleTimedProfileSuite.java
similarity index 93%
rename from libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleProfileSuite.java
rename to libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleTimedProfileSuite.java
index 2b1bf10..16686ee 100644
--- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleProfileSuite.java
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/samples/testing/SampleTimedProfileSuite.java
@@ -31,11 +31,11 @@
@RunWith(ProfileSuite.class)
@SuiteClasses({
- SampleProfileSuite.LongIdleTest.class,
- SampleProfileSuite.PassingTest.class,
+ SampleTimedProfileSuite.LongIdleTest.class,
+ SampleTimedProfileSuite.PassingTest.class,
})
/** Sample device-side test cases using a profile. */
-public class SampleProfileSuite {
+public class SampleTimedProfileSuite {
@Scenario
@RunWith(JUnit4.class)
public static class LongIdleTest {