DO NOT MERGE CTS device-side preconditions for MNC
bug:23939594
Change-Id: I93245401a7136b5aee0a757a48eb80e063a523c3
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 975ac47..62fdbdd 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -102,6 +102,7 @@
CtsMonkeyApp2 \
CtsPackageInstallerApp \
CtsPermissionApp \
+ CtsPreconditionsApp \
CtsSimpleApp \
CtsSimplePreMApp \
CtsSomeAccessibilityServices \
diff --git a/tools/Android.mk b/tools/Android.mk
index 8377036..8cb90db 100644
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -19,12 +19,13 @@
TF_JAR := $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
CTS_TF_JAR := $(HOST_OUT_JAVA_LIBRARIES)/cts-tradefed.jar
CTS_TF_EXEC_PATH ?= $(HOST_OUT_EXECUTABLES)/cts-tradefed
+PRECONDITIONS_APK := $(CTS_TESTCASES_OUT)/CtsPreconditionsApp.apk
cts_prebuilt_jar := $(HOST_OUT)/cts/android-cts/tools/cts-prebuilt.jar
$(cts_prebuilt_jar): PRIVATE_TESTS_DIR := $(HOST_OUT)/cts/android-cts/repository/testcases
$(cts_prebuilt_jar): PRIVATE_PLANS_DIR := $(HOST_OUT)/cts/android-cts/repository/plans
$(cts_prebuilt_jar): PRIVATE_TOOLS_DIR := $(HOST_OUT)/cts/android-cts/tools
-$(cts_prebuilt_jar): $(JUNIT_HOST_JAR) $(HOSTTESTLIB_JAR) $(TF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(ADDITIONAL_TF_JARS) | $(ACP) $(HOST_OUT_EXECUTABLES)/adb
+$(cts_prebuilt_jar): $(JUNIT_HOST_JAR) $(HOSTTESTLIB_JAR) $(TF_JAR) $(CTS_TF_JAR) $(CTS_TF_EXEC_PATH) $(ADDITIONAL_TF_JARS) $(PRECONDITIONS_APK) | $(ACP) $(HOST_OUT_EXECUTABLES)/adb
mkdir -p $(PRIVATE_TESTS_DIR)
mkdir -p $(PRIVATE_PLANS_DIR)
mkdir -p $(PRIVATE_TOOLS_DIR)
diff --git a/tools/tradefed-host/preconditions/Android.mk b/tools/tradefed-host/preconditions/Android.mk
new file mode 100644
index 0000000..bcd7b49
--- /dev/null
+++ b/tools/tradefed-host/preconditions/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsPreconditionsApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tools/tradefed-host/preconditions/AndroidManifest.xml b/tools/tradefed-host/preconditions/AndroidManifest.xml
new file mode 100644
index 0000000..02b3534
--- /dev/null
+++ b/tools/tradefed-host/preconditions/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.preconditions">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:label="CTS device-side preconditions test"
+ android:targetPackage="com.android.cts.preconditions" >
+ </instrumentation>
+</manifest>
diff --git a/tools/tradefed-host/preconditions/src/com/android/cts/preconditions/PreconditionsTest.java b/tools/tradefed-host/preconditions/src/com/android/cts/preconditions/PreconditionsTest.java
new file mode 100644
index 0000000..64a2b31
--- /dev/null
+++ b/tools/tradefed-host/preconditions/src/com/android/cts/preconditions/PreconditionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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.cts.preconditions;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.os.Environment;
+import android.test.AndroidTestCase;
+
+/**
+ * An AndroidTestCase class to verify that device-side preconditions are met for CTS
+ */
+public class PreconditionsTest extends AndroidTestCase {
+
+ /**
+ * Test if device has no screen lock
+ * @throws Exception
+ */
+ public void testScreenUnlocked() throws Exception {
+ KeyguardManager km =
+ (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
+ assertFalse("Device must have screen lock disabled", km.isDeviceSecure());
+ }
+
+ /**
+ * Test if device has accessible external storage
+ * @throws Exception
+ */
+ public void testExternalStoragePresent() throws Exception {
+ String state = Environment.getExternalStorageState();
+ assertTrue("Device must have writable external storage mounted in order to run CTS",
+ Environment.MEDIA_MOUNTED.equals(state));
+ }
+
+}
diff --git a/tools/tradefed-host/res/config/cts.xml b/tools/tradefed-host/res/config/cts.xml
index 416b400..3f89630 100644
--- a/tools/tradefed-host/res/config/cts.xml
+++ b/tools/tradefed-host/res/config/cts.xml
@@ -19,6 +19,7 @@
<option name="enable-root" value="false" />
<build_provider class="com.android.cts.tradefed.build.CtsBuildProvider" />
<device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
+ <target_preparer class="com.android.cts.tradefed.targetprep.DevicePreconditionPreparer" />
<test class="com.android.cts.tradefed.testtype.CtsTest" />
<logger class="com.android.tradefed.log.FileLogger" />
<result_reporter class="com.android.cts.tradefed.result.CtsXmlResultReporter" />
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/DevicePreconditionPreparer.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/DevicePreconditionPreparer.java
new file mode 100644
index 0000000..039470b
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/DevicePreconditionPreparer.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2015 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.cts.tradefed.targetprep;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.tradefed.testtype.Abi;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.build.IFolderBuildInfo;
+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;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestSummary;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.InstrumentationTest;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A {@link ITargetPreparer} that performs precondition checks on the device-side for CTS.
+ * <p/>
+ * This class instruments an APK containing tests verifying that the device meets CTS
+ * preconditions. At present, the APK contains tests to ensure that the device's screen is not
+ * locked, and that the device's external storage is present and writable. The test lives under
+ * //cts/tools/tradefed-host/preconditions, and can be modified to perform further checks and tasks
+ * from the device-side.
+ */
+@OptionClass(alias="device-precondition-preparer")
+public class DevicePreconditionPreparer implements ITargetPreparer {
+
+ /* This option also exists in the HostPreconditionPreparer */
+ @Option(name = "skip-preconditions",
+ description = "Whether to skip precondition checks and automation")
+ protected boolean mSkipPreconditions = false;
+
+ /* Constants for the InstrumentationTest */
+ private static final String APK_NAME = "CtsPreconditionsApp.apk";
+ private static final String PACKAGE_NAME = "com.android.cts.preconditions";
+ private static final String RUNNER_NAME = "android.support.test.runner.AndroidJUnitRunner";
+
+ /* Map used to track test failures */
+ private ConcurrentHashMap<TestIdentifier, String> testFailures = new ConcurrentHashMap<>();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ BuildError, DeviceNotAvailableException {
+ if (mSkipPreconditions) {
+ return; // skipping device-side preconditions
+ }
+
+ try {
+ if (!instrument(device, buildInfo)) {
+ throw new TargetSetupError("Not all device-side preconditions met");
+ }
+ } catch (FileNotFoundException e) {
+ throw new TargetSetupError(
+ String.format("Couldn't find %s to instrument", APK_NAME), e);
+ }
+ }
+
+ /* Instruments the APK on the device, and logs precondition test failures, if any are found.
+ * Returns true if all tests pass, and otherwise returns false */
+ private boolean instrument(ITestDevice device, IBuildInfo buildInfo)
+ throws DeviceNotAvailableException, FileNotFoundException {
+ ITestInvocationListener listener = new PreconditionPreparerListener();
+ CtsBuildHelper mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ File apkFile = mCtsBuild.getTestApp(APK_NAME); // get the APK file with the CtsBuildHelper
+ InstrumentationTest instrTest = new InstrumentationTest();
+ instrTest.setDevice(device);
+ instrTest.setInstallFile(apkFile);
+ instrTest.setPackageName(PACKAGE_NAME);
+ instrTest.setRunnerName(RUNNER_NAME);
+ instrTest.run(listener);
+ boolean success = true;
+ if (!testFailures.isEmpty()) {
+ success = false; // at least one precondition has failed
+ for (TestIdentifier test : testFailures.keySet()) {
+ String trace = testFailures.get(test);
+ CLog.e("Precondition test %s failed.\n%s", test.getTestName(), trace);
+ }
+ }
+ return success;
+ }
+
+ /**
+ * The PreconditionPreparerListener is an implementation of ITestInvocationListener
+ * that adds entries to the ConcurrentHashMap 'testFailures' of the outer class whenever
+ * a test fails. The listener also logs information if the test run fails, for debugging
+ * purposes.
+ */
+ public class PreconditionPreparerListener implements ITestInvocationListener {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testFailed(TestIdentifier test, String trace) {
+ testFailures.put(test, trace);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testRunFailed(String errorMessage) {
+ CLog.e("Device-side preconditions test run failed: %s", errorMessage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testEnded(TestIdentifier test, Map<String, String> metrics) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invocationStarted(IBuildInfo buildInfo) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invocationEnded(long elapsedTime) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invocationFailed(Throwable cause) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public TestSummary getSummary() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testRunStarted(String runName, int testCount) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testStarted(TestIdentifier test) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testAssumptionFailure(TestIdentifier test, String trace) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testIgnored(TestIdentifier test) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testRunStopped(long elapsedTime) {}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {}
+ }
+}