Merge "Moved profile to RunListener interface."
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 39526ca..7ce759e 100644
--- a/libraries/longevity/platform/src/android/platform/test/longevity/Profile.java
+++ b/libraries/longevity/platform/src/android/platform/test/longevity/Profile.java
@@ -16,8 +16,8 @@
package android.platform.test.longevity;
import android.content.res.AssetManager;
-import android.host.test.composer.Compose;
import android.os.Bundle;
+import android.os.SystemClock;
import android.platform.test.longevity.proto.Configuration;
import android.platform.test.longevity.proto.Configuration.Scenario;
import android.platform.test.longevity.proto.Configuration.Schedule;
@@ -27,6 +27,7 @@
import org.junit.runner.Description;
import org.junit.runner.Runner;
+import org.junit.runner.notification.RunListener;
import java.io.File;
import java.io.FileInputStream;
@@ -43,10 +44,8 @@
import java.util.function.Function;
import java.util.stream.Collectors;
-/**
- * A profile composer for device-side testing.
- */
-public class Profile implements Compose<Bundle, Runner> {
+/** A profile composer for device-side testing. */
+public class Profile extends RunListener {
@VisibleForTesting static final String PROFILE_OPTION_NAME = "profile";
protected static final String PROFILE_EXTENSION = ".pb";
@@ -56,13 +55,13 @@
// Parser for parsing "at" timestamps in profiles.
private static final SimpleDateFormat TIMESTAMP_FORMATTER = new SimpleDateFormat("HH:mm:ss");
- // Keeps track of the next scenario to run.
+ // Keeps track of the current scenario being run; updated at the end of a scenario.
private int mScenarioIndex = 0;
// A list of scenarios in the order that they will be run.
private List<Scenario> mOrderedScenariosList;
// Timestamp when the test run starts, defaults to time when the ProfileBase object is
// constructed. Can be overridden by {@link setTestRunStartTimeMs}.
- private long mRunStartTimeMs = System.currentTimeMillis();
+ private long mRunStartTimeMs = SystemClock.elapsedRealtime();
// The profile configuration.
private Configuration mConfiguration;
// The timestamp of the first scenario in milliseconds. All scenarios will be scheduled relative
@@ -112,13 +111,11 @@
}
}
- @Override
- public List<Runner> apply(Bundle args, List<Runner> input) {
- Configuration config = getConfigurationArgument(args);
- if (config == null) {
+ public List<Runner> getRunnerSequence(List<Runner> input) {
+ if (mConfiguration == null) {
return input;
}
- return getTestSequenceFromConfiguration(config, input);
+ return getTestSequenceFromConfiguration(mConfiguration, input);
}
protected List<Runner> getTestSequenceFromConfiguration(
@@ -155,13 +152,13 @@
return result;
}
- /** Enables classes using the profile composer to set the test run start time. */
- public void setTestRunStartTimeMs(long timestamp) {
- mRunStartTimeMs = timestamp;
+ @Override
+ public void testRunStarted(Description description) {
+ mRunStartTimeMs = SystemClock.elapsedRealtime();
}
- /** Called by suite runners to signal that a scenario/test has started. */
- public void scenarioStarted() {
+ @Override
+ public void testFinished(Description description) {
// Increments the index to move onto the next scenario.
mScenarioIndex += 1;
}
@@ -171,12 +168,13 @@
* false.
*/
public boolean hasNextScheduledScenario() {
- return (mOrderedScenariosList != null) && (mScenarioIndex < mOrderedScenariosList.size());
+ return (mOrderedScenariosList != null)
+ && (mScenarioIndex < mOrderedScenariosList.size() - 1);
}
/** Returns time in milliseconds until the next scenario. */
public long getTimeUntilNextScenarioMs() {
- Scenario nextScenario = mOrderedScenariosList.get(mScenarioIndex);
+ Scenario nextScenario = mOrderedScenariosList.get(mScenarioIndex + 1);
if (nextScenario.hasAt()) {
try {
// Calibrate the start time against the first scenario's timestamp.
@@ -203,14 +201,12 @@
/** Return time in milliseconds since the test run started. */
public long getTimeSinceRunStartedMs() {
- return System.currentTimeMillis() - mRunStartTimeMs;
+ return SystemClock.elapsedRealtime() - mRunStartTimeMs;
}
/** Returns the Scenario object for the current scenario. */
public Scenario getCurrentScenario() {
- // mScenarioIndex points to the next scenario, so the index for the current one is
- // mScenarioIndex - 1.
- return mOrderedScenariosList.get(mScenarioIndex - 1);
+ return mOrderedScenariosList.get(mScenarioIndex);
}
/** Returns the profile configuration. */
diff --git a/libraries/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java b/libraries/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java
index 4248a86..76746bb 100644
--- a/libraries/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java
+++ b/libraries/longevity/platform/src/android/platform/test/longevity/ProfileSuite.java
@@ -19,12 +19,10 @@
import android.app.Instrumentation;
import android.content.Context;
import android.os.Bundle;
-import android.os.SystemClock;
import android.platform.test.longevity.proto.Configuration.Scenario;
import androidx.annotation.VisibleForTesting;
import androidx.test.InstrumentationRegistry;
-import java.util.function.BiFunction;
import java.util.List;
import org.junit.runner.Runner;
@@ -112,19 +110,14 @@
}
}
// Construct and store custom runners for the full suite.
- BiFunction<Bundle, List<Runner>, List<Runner>> modifier = new Profile(args);
- return modifier.apply(args, builder.runners(suite, annotation.value()));
+ return new Profile(args).getRunnerSequence(builder.runners(suite, annotation.value()));
}
/** {@inheritDoc} */
@Override
public void run(final RunNotifier notifier) {
- // Set the test run start time in the profile composer and sleep until the first scheduled
- // test starts. When no profile is supplied, hasNextScheduledScenario() returns false and
- // no sleep is performed.
- if (mProfile.hasNextScheduledScenario()) {
- mProfile.setTestRunStartTimeMs(System.currentTimeMillis());
- }
+ // Add the profile listener.
+ notifier.addListener(mProfile);
// Register other listeners and continue with standard longevity run.
super.run(notifier);
}
@@ -132,7 +125,6 @@
/** {@inheritDoc} */
@Override
protected void runChild(Runner runner, final RunNotifier notifier) {
- mProfile.scenarioStarted();
super.runChild(runner, notifier);
}
diff --git a/libraries/longevity/platform/src/android/platform/test/longevity/listener/TimeoutTerminator.java b/libraries/longevity/platform/src/android/platform/test/longevity/listener/TimeoutTerminator.java
index 8090659..4773ce8 100644
--- a/libraries/longevity/platform/src/android/platform/test/longevity/listener/TimeoutTerminator.java
+++ b/libraries/longevity/platform/src/android/platform/test/longevity/listener/TimeoutTerminator.java
@@ -36,7 +36,7 @@
*/
@Override
protected long getCurrentTimestamp() {
- return SystemClock.uptimeMillis();
+ return SystemClock.elapsedRealtime();
}
/**
diff --git a/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java b/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java
index 76ccf1d..5f00b04 100644
--- a/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java
+++ b/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileSuiteTest.java
@@ -28,9 +28,10 @@
import android.app.Instrumentation;
import android.content.Context;
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.scenario.annotation.Scenario;
-import android.os.Bundle;
import org.junit.Assert;
import org.junit.Before;
@@ -63,8 +64,8 @@
@Mock private Instrumentation mInstrumentation;
@Mock private Context mContext;
- @Mock private RunNotifier mRunNotifier;
@Mock private Profile mProfile;
+ private RunNotifier mRunNotifier;
// Threshold above which missing a schedule is considered a failure.
private static final long SCHEDULE_LEEWAY_MS = 500;
@@ -72,6 +73,7 @@
@Before
public void setUpSuite() throws InitializationError {
initMocks(this);
+ mRunNotifier = spy(new RunNotifier());
}
/** Test that profile suites with classes that aren't scenarios are rejected. */
@@ -158,7 +160,7 @@
// 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
// same reference but altering the value.
- final AtomicLong runStartTimeMs = new AtomicLong(System.currentTimeMillis());
+ final AtomicLong runStartTimeMs = new AtomicLong(SystemClock.elapsedRealtime());
ProfileSuite suite =
spy(
new ProfileSuite(
@@ -170,7 +172,7 @@
// Stub the lifecycle calls to verify that tests are run on schedule.
doAnswer(
invocation -> {
- runStartTimeMs.set(System.currentTimeMillis());
+ runStartTimeMs.set(SystemClock.elapsedRealtime());
invocation.callRealMethod();
return null;
})
@@ -180,7 +182,7 @@
invocation -> {
// The first scenario should start immediately.
Assert.assertTrue(
- abs(System.currentTimeMillis() - runStartTimeMs.longValue())
+ abs(SystemClock.elapsedRealtime() - runStartTimeMs.longValue())
<= SCHEDULE_LEEWAY_MS);
invocation.callRealMethod();
return null;
@@ -198,7 +200,7 @@
// The second scenario should begin at 00:00:10 - 00:00:01 = 9 seconds.
Assert.assertTrue(
abs(
- System.currentTimeMillis()
+ SystemClock.elapsedRealtime()
- runStartTimeMs.longValue()
- TimeUnit.SECONDS.toMillis(9))
<= SCHEDULE_LEEWAY_MS);
diff --git a/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileTest.java b/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileTest.java
index 077481d..aacee7c 100644
--- a/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileTest.java
+++ b/libraries/longevity/platform/tests/src/android/platform/test/longevity/ProfileTest.java
@@ -120,12 +120,11 @@
"android.platform.test.scenario.calendar.FlingWeekPage",
"android.platform.test.scenario.calendar.FlingDayPage");
- List<Runner> output = getProfile(getArguments(VALID_CONFIG_KEY))
- .apply(getArguments(VALID_CONFIG_KEY), mMockInput);
+ List<Runner> output =
+ getProfile(getArguments(VALID_CONFIG_KEY)).getRunnerSequence(mMockInput);
List<String> outputDescriptions = output.stream().map(r ->
r.getDescription().getDisplayName()).collect(Collectors.toList());
boolean respected = outputDescriptions.equals(expectedJourneyOrder);
- System.out.println(outputDescriptions);
assertThat(respected).isTrue();
}
@@ -140,8 +139,9 @@
exceptionThrown.expectMessage("invalid");
// Attempt to apply a profile with invalid CUJ; the above exception should be thrown.
- List<Runner> output = getProfile(getArguments(CONFIG_WITH_INVALID_JOURNEY_KEY))
- .apply(getArguments(CONFIG_WITH_INVALID_JOURNEY_KEY), mMockInput);
+ List<Runner> output =
+ getProfile(getArguments(CONFIG_WITH_INVALID_JOURNEY_KEY))
+ .getRunnerSequence(mMockInput);
}
protected class TestableProfile extends Profile {