diff options
author | Paul Trautrim <paultrautrim@google.com> | 2019-02-21 17:15:42 +0900 |
---|---|---|
committer | Paul Trautrim <paultrautrim@google.com> | 2019-05-20 17:57:29 +0900 |
commit | bdecb22ce2ef2b6a22c433d70d27bafe7f23e683 (patch) | |
tree | a9b2135134fb3ae4f6129e24855f7dff78af026c /tests | |
parent | 448072c2e355cc39c9186257d4b688cb202e4fb8 (diff) | |
download | gsid-bdecb22ce2ef2b6a22c433d70d27bafe7f23e683.tar.gz |
Add end-to-end test for Dynamic System Updates
Bug: 116513434
Test: lunch aosp_cf_x86_phone-userdebug, atest -v DSUEndtoEndTest -- --test-arg \
com.android.tradefed.testtype.HostTest:set-option:system_image_path:/full/path/to/system.img
Change-Id: Iac5e28d499908830bd8956a5c2ee0bb39539514d
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Android.bp | 54 | ||||
-rw-r--r-- | tests/AndroidManifest.xml | 30 | ||||
-rw-r--r-- | tests/DSUEndtoEndTest.java | 168 | ||||
-rw-r--r-- | tests/LockScreenAutomation.java | 151 | ||||
-rw-r--r-- | tests/dsu-test.xml | 21 |
5 files changed, 424 insertions, 0 deletions
diff --git a/tests/Android.bp b/tests/Android.bp new file mode 100644 index 0000000..cb4ae49 --- /dev/null +++ b/tests/Android.bp @@ -0,0 +1,54 @@ +// +// 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. +// + +cc_test { + name: "gsi_boot_test", + shared_libs: [ + "libbase", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + ], + static_libs: [ + "libext4_utils", + "libfstab", + "android.hardware.weaver@1.0", + ], + srcs: [ + "boot_tests.cpp", + ], +} + +java_test_host { + name: "DSUEndtoEndTest", + srcs: ["DSUEndtoEndTest.java"], + libs: ["tradefed"], + test_config: "dsu-test.xml", + test_suites: ["general-tests"], +} + +android_test { + name: "LockScreenAutomation", + srcs: ["LockScreenAutomation.java"], + libs: ["junit", "android.test.base.stubs"], + static_libs: ["androidx.test.uiautomator"], + certificate: "platform", + manifest: "AndroidManifest.xml" +} diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml new file mode 100644 index 0000000..19d0c53 --- /dev/null +++ b/tests/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 Google Inc. + + 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.google.android.lockscreenautomation" + android:sharedUserId="android.uid.system" + > + + <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="28"/> + + <application debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner" + android:targetPackage="com.google.android.lockscreenautomation" + android:label="Lock Screen Automation"/> +</manifest> diff --git a/tests/DSUEndtoEndTest.java b/tests/DSUEndtoEndTest.java new file mode 100644 index 0000000..a0580aa --- /dev/null +++ b/tests/DSUEndtoEndTest.java @@ -0,0 +1,168 @@ +/* + * 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.tests.dsu; + +import com.android.tradefed.build.BuildRetrievalError; +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.build.IDeviceBuildInfo; +import com.android.tradefed.config.Option; +import com.android.tradefed.config.Option.Importance; +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.util.CommandResult; +import com.android.tradefed.util.ZipUtil2; + +import org.apache.commons.compress.archivers.zip.ZipFile; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.IOException; +import java.lang.Process; +import java.lang.Runtime; +import java.util.concurrent.TimeUnit; + +/** + * Test Dynamic System Updates by booting in and out of a supplied system image + */ +@RunWith(DeviceJUnit4ClassRunner.class) +public class DSUEndtoEndTest extends BaseHostJUnit4Test { + private static final long kDefaultUserdataSize = 4L * 1024 * 1024 * 1024; + private static final String APK = "LockScreenAutomation.apk"; + private static final String PACKAGE = "com.google.android.lockscreenautomation"; + private static final String UI_AUTOMATOR_INSTRUMENTATION_RUNNER = + "androidx.test.uiautomator.UiAutomatorInstrumentationTestRunner"; + private static final String CLASS = "LockScreenAutomation"; + private static final String SIMG2IMG_PATH = "bin/simg2img"; + + // Example: atest -v DSUEndtoEndTest -- --test-arg \ + // com.android.tradefed.testtype.HostTest:set-option:system_image_path:/full/path/to/system.img + @Option(name="system_image_path", + shortName='s', + description="full path to the system image to use. If not specified, attempt " + + "to download the image from the test infrastructure", + importance=Importance.ALWAYS) + private String mSystemImagePath; + + private File mUnsparseSystemImage; + + @After + public void teardown() throws Exception { + uninstallPackage(PACKAGE); + if (mUnsparseSystemImage != null) { + mUnsparseSystemImage.delete(); + } + } + + @Test + public void testDSU() throws Exception { + String simg2imgPath = "simg2img"; + if (mSystemImagePath == null) { + IDeviceBuildInfo deviceBuild = (IDeviceBuildInfo) getBuild(); + File system = deviceBuild.getDeviceImageFile(); + Assert.assertNotEquals("Failed to fetch system image. See system_image_path parameter", null, system); + mSystemImagePath = system.getAbsolutePath(); + File otaPackage = deviceBuild.getOtaPackageFile(); + File simg2img = ZipUtil2.extractFileFromZip(new ZipFile(otaPackage), SIMG2IMG_PATH); + simg2imgPath = simg2img.getAbsolutePath(); + } + File gsi = new File(mSystemImagePath); + Assert.assertTrue("not a valid file", gsi.isFile()); + String[] cmd = {simg2imgPath, mSystemImagePath, mSystemImagePath + ".raw"}; + Process p = Runtime.getRuntime().exec(cmd); + p.waitFor(); + if (p.exitValue() == 0) { + mUnsparseSystemImage = new File(mSystemImagePath + ".raw"); + gsi = mUnsparseSystemImage; + } + + boolean wasRoot = getDevice().isAdbRoot(); + if (!wasRoot) + Assert.assertTrue("Test requires root", getDevice().enableAdbRoot()); + + expectGsiStatus("normal"); + + installPackage(APK); + String method = "setPin"; + String testClass = PACKAGE + "." + CLASS; + String testMethod = testClass + "." + method; + Assert.assertTrue(testMethod + " failed.", + runDeviceTests(UI_AUTOMATOR_INSTRUMENTATION_RUNNER, PACKAGE, testClass, method)); + + // Sleep after installing to allow time for gsi_tool to reboot. This prevents a race between + // the device rebooting and waitForDeviceAvailable() returning. + getDevice().executeShellV2Command("gsi_tool install --userdata-size " + kDefaultUserdataSize + + " --gsi-size " + gsi.length() + " && sleep 10000000", gsi, null, 10, TimeUnit.MINUTES, 1); + getDevice().waitForDeviceAvailable(); + getDevice().enableAdbRoot(); + + expectGsiStatus("running"); + + rebootAndUnlock(); + + expectGsiStatus("installed"); + + CommandResult result = getDevice().executeShellV2Command("gsi_tool enable"); + Assert.assertEquals("gsi_tool enable failed", 0, result.getExitCode().longValue()); + + getDevice().reboot(); + + expectGsiStatus("running"); + + getDevice().reboot(); + + expectGsiStatus("running"); + + getDevice().executeShellV2Command("gsi_tool wipe"); + + rebootAndUnlock(); + + expectGsiStatus("normal"); + + method = "removePin"; + testClass = PACKAGE + "." + CLASS; + testMethod = testClass + "." + method; + Assert.assertTrue(testMethod + " failed.", + runDeviceTests(UI_AUTOMATOR_INSTRUMENTATION_RUNNER, PACKAGE, testClass, method)); + + if (wasRoot) { + getDevice().enableAdbRoot(); + } + } + + private void expectGsiStatus(String expected) throws Exception { + CommandResult result = getDevice().executeShellV2Command("gsi_tool status"); + String status = result.getStdout().split("\n", 2)[0].trim(); + Assert.assertEquals("Device not in expected DSU state", expected, status); + } + + private void rebootAndUnlock() throws Exception { + getDevice().rebootUntilOnline(); + getDevice().executeShellV2Command("input keyevent 224"); // KeyEvent.KEYCODE_WAKEUP + getDevice().executeShellV2Command("wm dismiss-keyguard"); + getDevice().executeShellV2Command("input keyevent 7"); // KeyEvent.KEYCODE_0 + getDevice().executeShellV2Command("input keyevent 7"); + getDevice().executeShellV2Command("input keyevent 7"); + getDevice().executeShellV2Command("input keyevent 7"); + getDevice().executeShellV2Command("input keyevent 66"); // KeyEvent.KEYCODE_ENTER + } +} + diff --git a/tests/LockScreenAutomation.java b/tests/LockScreenAutomation.java new file mode 100644 index 0000000..afefa1c --- /dev/null +++ b/tests/LockScreenAutomation.java @@ -0,0 +1,151 @@ +/* + * 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.google.android.lockscreenautomation; + +import org.junit.Assert; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.provider.Settings; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiAutomatorTestCase; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; +import android.view.KeyEvent; + +/** + * Methods for configuring lock screen settings + */ +public class LockScreenAutomation extends UiAutomatorTestCase { + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + + private static final long TIMEOUT = 2000L; + + private Context mContext; + private UiDevice mDevice; + + public void setPin() throws Exception { + mContext = getInstrumentation().getContext(); + mDevice = UiDevice.getInstance(getInstrumentation()); + + mDevice.wakeUp(); + mDevice.pressKeyCode(KeyEvent.KEYCODE_MENU); + mDevice.waitForIdle(TIMEOUT); + launchLockScreenSettings(); + + PackageManager pm = mContext.getPackageManager(); + Resources res = pm.getResourcesForApplication(SETTINGS_PACKAGE); + + int resId = res.getIdentifier("unlock_set_unlock_pin_title", "string", SETTINGS_PACKAGE); + findAndClick(By.text(res.getString(resId))); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressEnter(); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + + // Re-enter PIN + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressEnter(); + + findAndClick(By.res(SETTINGS_PACKAGE, "redact_sensitive")); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + findAndClick(By.clazz("android.widget.Button")); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + } + + public void unlock() throws Exception { + mContext = getInstrumentation().getContext(); + mDevice = UiDevice.getInstance(getInstrumentation()); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.pressKeyCode(KeyEvent.KEYCODE_ENTER); + } + + public void removePin() throws Exception { + mContext = getInstrumentation().getContext(); + mDevice = UiDevice.getInstance(getInstrumentation()); + + mDevice.wakeUp(); + mDevice.pressKeyCode(KeyEvent.KEYCODE_MENU); + mDevice.waitForIdle(TIMEOUT); + launchLockScreenSettings(); + + PackageManager pm = mContext.getPackageManager(); + Resources res = pm.getResourcesForApplication(SETTINGS_PACKAGE); + + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressKeyCode(KeyEvent.KEYCODE_0); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + mDevice.pressEnter(); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + + int resId = res.getIdentifier("unlock_set_unlock_off_title", "string", SETTINGS_PACKAGE); + findAndClick(By.text(res.getString(resId))); + mDevice.waitForWindowUpdate(SETTINGS_PACKAGE, 5); + + findAndClick(By.res("android", "button1")); + mDevice.waitForIdle(TIMEOUT); + } + + private void findAndClick(BySelector selector) + { + for (int i = 0; i < 3; i++) { + mDevice.wait(Until.findObject(selector), TIMEOUT); + UiObject2 obj = mDevice.findObject(selector); + if (obj != null) { + obj.click(); + return; + } + } + Assert.fail("Could not find and click " + selector); + } + + private void launchLockScreenSettings() { + final Intent intent = new Intent().setClassName(SETTINGS_PACKAGE, "com.android.settings.password.ChooseLockGeneric"); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + mContext.startActivity(intent); + mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT); + } +} diff --git a/tests/dsu-test.xml b/tests/dsu-test.xml new file mode 100644 index 0000000..13c5895 --- /dev/null +++ b/tests/dsu-test.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<configuration description="Config for DSU test case"> + <test class="com.android.tradefed.testtype.HostTest" > + <option name="jar" value="DSUEndtoEndTest.jar" /> + </test> +</configuration> + |