Snap for 5285806 from ed72d74ae314877e1f19537d4351ed222003322a to pi-qpr3-release
Change-Id: I2443db6ef0272871fd4fb520eb7a75b4adb9b8b9
diff --git a/Android.mk b/Android.mk
index a5b52c7..9461ce2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -129,7 +129,7 @@
# Zip up the built files and dist it as tradefed.zip
ifneq (,$(filter tradefed tradefed-all, $(TARGET_BUILD_APPS)))
-tradefed_dist_host_jars := tradefed tradefed-tests tf-prod-tests tf-prod-metatests emmalib jack-jacoco-reporter loganalysis loganalysis-tests tf-remote-client tradefed-contrib
+tradefed_dist_host_jars := tradefed tradefed-tests tf-prod-tests tf-prod-metatests emmalib jack-jacoco-reporter loganalysis loganalysis-tests tf-remote-client tradefed-contrib tools-common-prebuilt
tradefed_dist_host_jar_files := $(foreach m, $(tradefed_dist_host_jars), $(HOST_OUT_JAVA_LIBRARIES)/$(m).jar)
tradefed_dist_host_exes := tradefed.sh tradefed_win.bat script_help.sh verify.sh run_tf_cmd.sh atest_tradefed.sh
diff --git a/src/com/android/tradefed/result/ddmlib/TestRunToTestInvocationForwarder.java b/src/com/android/tradefed/result/ddmlib/TestRunToTestInvocationForwarder.java
index 42ca817..bf26e07 100644
--- a/src/com/android/tradefed/result/ddmlib/TestRunToTestInvocationForwarder.java
+++ b/src/com/android/tradefed/result/ddmlib/TestRunToTestInvocationForwarder.java
@@ -34,7 +34,17 @@
*/
public class TestRunToTestInvocationForwarder implements ITestRunListener {
+ private static final String NULL_STRING = "null";
+ public static final String ERROR_MESSAGE_FORMAT =
+ "Runner reported an invalid method 'null' (%s). Something went wrong, Skipping "
+ + "its reporting.";
+
private Collection<ITestLifeCycleReceiver> mListeners;
+ private Long mStartTime;
+ // Sometimes the instrumentation runner (Android JUnit Runner / AJUR) fails to load some class
+ // and report a "null" as a test method. This creates a lot of issues in the reporting pipeline
+ // so catch it, and avoid it at the root.
+ private TestIdentifier mNullMethod = null;
public TestRunToTestInvocationForwarder(Collection<ITestLifeCycleReceiver> listeners) {
mListeners = listeners;
@@ -46,6 +56,11 @@
@Override
public void testStarted(TestIdentifier testId) {
+ if (NULL_STRING.equals(testId.getTestName())) {
+ mNullMethod = testId;
+ return;
+ }
+ mNullMethod = null;
for (ITestLifeCycleReceiver listener : mListeners) {
try {
listener.testStarted(TestDescription.createFromTestIdentifier(testId));
@@ -60,6 +75,11 @@
@Override
public void testStarted(TestIdentifier testId, long startTime) {
+ if (NULL_STRING.equals(testId.getTestName())) {
+ mNullMethod = testId;
+ return;
+ }
+ mNullMethod = null;
for (ITestLifeCycleReceiver listener : mListeners) {
try {
listener.testStarted(TestDescription.createFromTestIdentifier(testId), startTime);
@@ -74,6 +94,9 @@
@Override
public void testAssumptionFailure(TestIdentifier testId, String trace) {
+ if (mNullMethod != null && mNullMethod.equals(testId)) {
+ return;
+ }
for (ITestLifeCycleReceiver listener : mListeners) {
try {
listener.testAssumptionFailure(
@@ -89,6 +112,9 @@
@Override
public void testFailed(TestIdentifier testId, String trace) {
+ if (mNullMethod != null && mNullMethod.equals(testId)) {
+ return;
+ }
for (ITestLifeCycleReceiver listener : mListeners) {
try {
listener.testFailed(TestDescription.createFromTestIdentifier(testId), trace);
@@ -103,6 +129,9 @@
@Override
public void testIgnored(TestIdentifier testId) {
+ if (mNullMethod != null && mNullMethod.equals(testId)) {
+ return;
+ }
for (ITestLifeCycleReceiver listener : mListeners) {
try {
listener.testIgnored(TestDescription.createFromTestIdentifier(testId));
@@ -118,6 +147,10 @@
@Override
public void testEnded(TestIdentifier testId, Map<String, String> testMetrics) {
for (ITestLifeCycleReceiver listener : mListeners) {
+ if (mNullMethod != null && mNullMethod.equals(testId)) {
+ listener.testRunFailed(String.format(ERROR_MESSAGE_FORMAT, mNullMethod));
+ continue;
+ }
try {
listener.testEnded(
TestDescription.createFromTestIdentifier(testId),
@@ -134,6 +167,10 @@
@Override
public void testEnded(TestIdentifier testId, long endTime, Map<String, String> testMetrics) {
for (ITestLifeCycleReceiver listener : mListeners) {
+ if (mNullMethod != null && mNullMethod.equals(testId)) {
+ listener.testRunFailed(String.format(ERROR_MESSAGE_FORMAT, mNullMethod));
+ continue;
+ }
try {
listener.testEnded(
TestDescription.createFromTestIdentifier(testId),
diff --git a/src/com/android/tradefed/targetprep/SwitchUserTargetPreparer.java b/src/com/android/tradefed/targetprep/SwitchUserTargetPreparer.java
new file mode 100644
index 0000000..9b4fe49
--- /dev/null
+++ b/src/com/android/tradefed/targetprep/SwitchUserTargetPreparer.java
@@ -0,0 +1,98 @@
+/*
+ * 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 com.android.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * A {@link ITargetPreparer} that switches to the specified user kind in setUp. By default it
+ * remains in the current user, and no switching is performed.
+ *
+ * <p>Tries to restore device user state by switching back to the pre-execution current user.
+ */
+@OptionClass(alias = "switch-user-target-preparer")
+public class SwitchUserTargetPreparer extends BaseTargetPreparer implements ITargetCleaner {
+ private static final int USER_SYSTEM = 0; // From the UserHandle class.
+
+ /** Parameters that specify which user to run the test module as. */
+ public enum UserType {
+ // TODO:(b/123077733) Add support for guest and secondary.
+
+ /** current foreground user of the device */
+ CURRENT,
+ /** user flagged as primary on the device; most often primary = system user = user 0 */
+ PRIMARY,
+ /** system user = user 0 */
+ SYSTEM
+ }
+
+ @Option(
+ name = "user-type",
+ description = "The type of user to switch to before the module run."
+ )
+ private UserType mUserToSwitchTo = UserType.CURRENT;
+
+ private int mPreExecutionCurrentUser;
+
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws TargetSetupError, DeviceNotAvailableException {
+
+ mPreExecutionCurrentUser = device.getCurrentUser();
+
+ switch (mUserToSwitchTo) {
+ case SYSTEM:
+ switchToUser(USER_SYSTEM, device);
+ break;
+ case PRIMARY:
+ switchToUser(device.getPrimaryUserId(), device);
+ break;
+ }
+ }
+
+ private static void switchToUser(int userId, ITestDevice device)
+ throws TargetSetupError, DeviceNotAvailableException {
+ if (device.getCurrentUser() == userId) {
+ return;
+ }
+
+ // Otherwise, switch to user with userId.
+ if (device.switchUser(userId)) {
+ // Successful switch.
+ CLog.i("Switched to user %d.", userId);
+ } else {
+ // Couldn't switch, throw.
+ throw new TargetSetupError(
+ String.format("Failed switch to user %d.", userId),
+ device.getDeviceDescriptor());
+ }
+ }
+
+ @Override
+ public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+ throws DeviceNotAvailableException {
+ // Restore the previous user as the foreground.
+ if (!device.switchUser(mPreExecutionCurrentUser)) {
+ CLog.w("Could not switch back to the user id: %d", mPreExecutionCurrentUser);
+ }
+ }
+}
diff --git a/src/com/android/tradefed/testtype/GTestListTestParser.java b/src/com/android/tradefed/testtype/GTestListTestParser.java
index 894010e..216f4e0 100644
--- a/src/com/android/tradefed/testtype/GTestListTestParser.java
+++ b/src/com/android/tradefed/testtype/GTestListTestParser.java
@@ -45,7 +45,7 @@
// example: <line start> emptyPlayback<line end>
// example parameterized: <line start> emptyPlayback/0 # GetParam() = (object 1)<line end>
private static final Pattern TEST_METHOD =
- Pattern.compile("\\s+([a-zA-Z]+[\\S]*)(.*)?(\\s+.*)?$");
+ Pattern.compile("\\s+([a-zA-Z_]+[\\S]*)(.*)?(\\s+.*)?$");
// exposed for unit testing
protected List<TestDescription> mTests = new ArrayList<>();
diff --git a/tests/res/testtype/gtest_list1.txt b/tests/res/testtype/gtest_list1.txt
index 0cce19e..1ef5287 100644
--- a/tests/res/testtype/gtest_list1.txt
+++ b/tests/res/testtype/gtest_list1.txt
@@ -8,7 +8,7 @@
drawText
drawText_strikeThruAndUnderline
drawText_forceAlignLeft
- drawColor
+ __drawColor
backgroundAndImage
saveLayer_simple
saveLayer_missingRestore
diff --git a/tests/src/com/android/tradefed/UnitTests.java b/tests/src/com/android/tradefed/UnitTests.java
index f55bf9e..2cd4e0b 100644
--- a/tests/src/com/android/tradefed/UnitTests.java
+++ b/tests/src/com/android/tradefed/UnitTests.java
@@ -122,6 +122,7 @@
import com.android.tradefed.result.TestRunResultTest;
import com.android.tradefed.result.TestSummaryTest;
import com.android.tradefed.result.XmlResultReporterTest;
+import com.android.tradefed.result.ddmlib.TestRunToTestInvocationForwarderTest;
import com.android.tradefed.result.suite.FormattedGeneratorReporterTest;
import com.android.tradefed.result.suite.XmlSuiteResultFormatterTest;
import com.android.tradefed.sandbox.SandboxConfigDumpTest;
@@ -158,6 +159,7 @@
import com.android.tradefed.targetprep.RunHostCommandTargetPreparerTest;
import com.android.tradefed.targetprep.SdkAvdPreparerTest;
import com.android.tradefed.targetprep.StopServicesSetupTest;
+import com.android.tradefed.targetprep.SwitchUserTargetPreparerTest;
import com.android.tradefed.targetprep.SystemUpdaterDeviceFlasherTest;
import com.android.tradefed.targetprep.TestAppInstallSetupTest;
import com.android.tradefed.targetprep.TestFilePushSetupTest;
@@ -429,6 +431,9 @@
TestSummaryTest.class,
XmlResultReporterTest.class,
+ // result.ddmlib
+ TestRunToTestInvocationForwarderTest.class,
+
// result.suite
FormattedGeneratorReporterTest.class,
XmlSuiteResultFormatterTest.class,
@@ -462,6 +467,7 @@
TestAppInstallSetupTest.class,
TestFilePushSetupTest.class,
TimeSetterTargetPreparerTest.class,
+ SwitchUserTargetPreparerTest.class,
// targetprep.multi
MergeMultiBuildTargetPreparerTest.class,
diff --git a/tests/src/com/android/tradefed/result/ddmlib/TestRunToTestInvocationForwarderTest.java b/tests/src/com/android/tradefed/result/ddmlib/TestRunToTestInvocationForwarderTest.java
new file mode 100644
index 0000000..56dab4c
--- /dev/null
+++ b/tests/src/com/android/tradefed/result/ddmlib/TestRunToTestInvocationForwarderTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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 com.android.tradefed.result.ddmlib;
+
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.ITestLifeCycleReceiver;
+import com.android.tradefed.result.TestDescription;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.HashMap;
+
+/** Run unit tests {@link TestRunToTestInvocationForwarder}. */
+@RunWith(JUnit4.class)
+public class TestRunToTestInvocationForwarderTest {
+
+ private static final String RUN_NAME = "run";
+
+ private TestRunToTestInvocationForwarder mForwarder;
+ private ITestLifeCycleReceiver mMockListener;
+
+ @Before
+ public void setUp() {
+ mMockListener = EasyMock.createMock(ITestInvocationListener.class);
+ mForwarder = new TestRunToTestInvocationForwarder(mMockListener);
+ }
+
+ @Test
+ public void testForwarding() {
+ TestIdentifier tid1 = new TestIdentifier("class", "test1");
+ TestDescription td1 = new TestDescription(tid1.getClassName(), tid1.getTestName());
+ TestIdentifier tid2 = new TestIdentifier("class", "test2");
+ TestDescription td2 = new TestDescription(tid2.getClassName(), tid2.getTestName());
+ mMockListener.testRunStarted(RUN_NAME, 2);
+
+ mMockListener.testStarted(td1);
+ mMockListener.testFailed(td1, "I failed");
+ mMockListener.testEnded(td1, new HashMap<String, Metric>());
+
+ mMockListener.testStarted(td2);
+ mMockListener.testFailed(td2, "I failed");
+ mMockListener.testEnded(td2, new HashMap<String, Metric>());
+
+ mMockListener.testRunEnded(
+ EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
+
+ EasyMock.replay(mMockListener);
+ mForwarder.testRunStarted(RUN_NAME, 2);
+
+ mForwarder.testStarted(tid1);
+ mForwarder.testFailed(tid1, "I failed");
+ mForwarder.testEnded(tid1, new HashMap<>());
+
+ mForwarder.testStarted(tid2);
+ mForwarder.testFailed(tid2, "I failed");
+ mForwarder.testEnded(tid2, new HashMap<>());
+
+ mForwarder.testRunEnded(500L, new HashMap<>());
+ EasyMock.verify(mMockListener);
+ }
+
+ @Test
+ public void testForwarding_null() {
+ TestIdentifier tid1 = new TestIdentifier("class", "test1");
+ TestDescription td1 = new TestDescription(tid1.getClassName(), tid1.getTestName());
+ TestIdentifier tid2 = new TestIdentifier("class", "null");
+ mMockListener.testRunStarted(RUN_NAME, 2);
+
+ mMockListener.testStarted(td1);
+ mMockListener.testFailed(td1, "I failed");
+ mMockListener.testEnded(td1, new HashMap<String, Metric>());
+ // Second bad method is not propagated, instead we fail the run
+ mMockListener.testRunFailed(
+ String.format(TestRunToTestInvocationForwarder.ERROR_MESSAGE_FORMAT, tid2));
+
+ mMockListener.testRunEnded(
+ EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
+
+ EasyMock.replay(mMockListener);
+ mForwarder.testRunStarted(RUN_NAME, 2);
+
+ mForwarder.testStarted(tid1);
+ mForwarder.testFailed(tid1, "I failed");
+ mForwarder.testEnded(tid1, new HashMap<>());
+
+ mForwarder.testStarted(tid2);
+ mForwarder.testFailed(tid2, "I failed");
+ mForwarder.testEnded(tid2, new HashMap<>());
+
+ mForwarder.testRunEnded(500L, new HashMap<>());
+ EasyMock.verify(mMockListener);
+ }
+}
diff --git a/tests/src/com/android/tradefed/targetprep/SwitchUserTargetPreparerTest.java b/tests/src/com/android/tradefed/targetprep/SwitchUserTargetPreparerTest.java
new file mode 100644
index 0000000..6b55093
--- /dev/null
+++ b/tests/src/com/android/tradefed/targetprep/SwitchUserTargetPreparerTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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 com.android.tradefed.targetprep;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unit tests for {@link SwitchUserTargetPreparer}. */
+@RunWith(JUnit4.class)
+public class SwitchUserTargetPreparerTest {
+ private static final int USER_SYSTEM = 0; // From the UserHandle class.
+
+ @Mock private ITestDevice mMockDevice;
+
+ private SwitchUserTargetPreparer mSwitchUserTargetPreparer;
+ private OptionSetter mOptionSetter;
+
+ @Before
+ public void setUp() throws ConfigurationException {
+ MockitoAnnotations.initMocks(this);
+ mSwitchUserTargetPreparer = new SwitchUserTargetPreparer();
+ mOptionSetter = new OptionSetter(mSwitchUserTargetPreparer);
+ }
+
+ @Test
+ public void testSetUpRunAsPrimary_ifAlreadyInPrimary_noUserSwitch()
+ throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
+ // setup
+ mockUsers(/* primaryUserId= */ 11, /* currentUserId= */ 11);
+ mOptionSetter.setOptionValue("user-type", "primary");
+
+ // act
+ mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+
+ // assert
+ verify(mMockDevice, never()).switchUser(anyInt());
+ }
+
+ @Test
+ public void testSetUpRunAsSystem_ifAlreadyInSystem_noUserSwitch()
+ throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
+ // setup
+ mockUsers(/* primaryUserId= */ 11, /* currentUserId= */ USER_SYSTEM);
+ mOptionSetter.setOptionValue("user-type", "system");
+
+ // act
+ mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+
+ // assert
+ verify(mMockDevice, never()).switchUser(anyInt());
+ }
+
+ @Test
+ public void testSetUpRunAsPrimary_ifNotInPrimary_switchToPrimary()
+ throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
+ // setup
+ mockUsers(/* primaryUserId= */ 10, /* currentUserId= */ 11);
+ mOptionSetter.setOptionValue("user-type", "primary");
+
+ // act
+ mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+
+ // assert it switches to primary in setUp
+ verify(mMockDevice, times(1)).switchUser(10);
+ }
+
+ @Test
+ public void testSetUpRunAsSystem_ifNotInSystem_switchToSystem()
+ throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
+ // setup
+ mockUsers(/* primaryUserId= */ 10, /* currentUserId= */ 11);
+ mOptionSetter.setOptionValue("user-type", "system");
+
+ // act
+ mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+
+ // assert it switches to primary in setUp
+ verify(mMockDevice, times(1)).switchUser(USER_SYSTEM);
+ }
+
+ @Test
+ public void testTearDown_ifStartedInSecondary_switchesBackToSecondary()
+ throws DeviceNotAvailableException, TargetSetupError, ConfigurationException {
+ // setup
+ mockUsers(/* primaryUserId= */ 0, /* currentUserId= */ 10);
+ mOptionSetter.setOptionValue("user-type", "primary");
+
+ // first switches to primary
+ mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+ verify(mMockDevice, times(1)).switchUser(0);
+
+ // then switches back to secondary
+ mSwitchUserTargetPreparer.tearDown(mMockDevice, /* buildInfo= */ null, null);
+ verify(mMockDevice, times(1)).switchUser(10);
+ }
+
+ @Test
+ public void testSetUp_ifNoSwitchToSpecified_noUserSwitch()
+ throws DeviceNotAvailableException, TargetSetupError {
+ // setup
+ mockUsers(/* primaryUserId= */ 0, /* currentUserId= */ 10);
+
+ // act
+ mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+
+ // assert
+ verify(mMockDevice, never()).switchUser(anyInt());
+ }
+
+ @Test
+ public void testSetUp_ifSwitchFails_throwsTargetSetupError()
+ throws DeviceNotAvailableException, ConfigurationException {
+ // setup
+ mockUsers(/* primaryUserId= */ 0, /* currentUserId= */ 11);
+ mOptionSetter.setOptionValue("user-type", "primary");
+ when(mMockDevice.switchUser(0)).thenReturn(false);
+
+ // act
+ try {
+ mSwitchUserTargetPreparer.setUp(mMockDevice, /* buildInfo= */ null);
+ fail("Should have thrown TargetSetupError exception.");
+ } catch (TargetSetupError e) {
+ // do nothing
+ }
+ }
+
+ private void mockUsers(int primaryUserId, int currentUserId)
+ throws DeviceNotAvailableException {
+ when(mMockDevice.getCurrentUser()).thenReturn(currentUserId);
+ when(mMockDevice.getPrimaryUserId()).thenReturn(primaryUserId);
+ when(mMockDevice.switchUser(anyInt())).thenReturn(true);
+ }
+}