Merge "DO NOT MERGE ANYWHERE Add test for files in no_backup folder." into nougat-mr1-cts-dev
diff --git a/hostsidetests/backup/AndroidTest.xml b/hostsidetests/backup/AndroidTest.xml
index 0a39104..2ea4663 100644
--- a/hostsidetests/backup/AndroidTest.xml
+++ b/hostsidetests/backup/AndroidTest.xml
@@ -17,6 +17,7 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsBackupRestoreDeviceApp.apk" />
+ <option name="test-file-name" value="CtsFullbackupApp.apk" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsBackupHostTestCases.jar" />
diff --git a/hostsidetests/backup/fullbackupapp/Android.mk b/hostsidetests/backup/fullbackupapp/Android.mk
new file mode 100644
index 0000000..46af984
--- /dev/null
+++ b/hostsidetests/backup/fullbackupapp/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2017 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)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsFullbackupApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/backup/fullbackupapp/AndroidManifest.xml b/hostsidetests/backup/fullbackupapp/AndroidManifest.xml
new file mode 100644
index 0000000..58f9306
--- /dev/null
+++ b/hostsidetests/backup/fullbackupapp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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="android.cts.backup.fullbackupapp">
+
+ <application android:label="FullbackupApp" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.cts.backup.fullbackupapp" />
+
+</manifest>
diff --git a/hostsidetests/backup/fullbackupapp/src/android/cts/backup/fullbackupapp/FullbackupTest.java b/hostsidetests/backup/fullbackupapp/src/android/cts/backup/fullbackupapp/FullbackupTest.java
new file mode 100644
index 0000000..7c3a6f6
--- /dev/null
+++ b/hostsidetests/backup/fullbackupapp/src/android/cts/backup/fullbackupapp/FullbackupTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2017 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.cts.backup.fullbackupapp;
+
+import static android.support.test.InstrumentationRegistry.getTargetContext;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import android.content.Context;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+/**
+ * Device side routines to be invoked by the host side NoBackupFolderHostSideTest. These are not
+ * designed to be called in any other way, as they rely on state set up by the host side test.
+ */
+@RunWith(AndroidJUnit4.class)
+public class FullbackupTest {
+ public static final String TAG = "FullbackupCTSApp";
+ private static final int FILE_SIZE_BYTES = 1024 * 1024;
+
+ private Context mContext;
+
+ private File mNoBackupFile;
+ private File mNoBackupFile2;
+ private File mDoBackupFile;
+ private File mDoBackupFile2;
+
+ @Before
+ public void setUp() {
+ mContext = getTargetContext();
+ setupFiles();
+ }
+
+ private void setupFiles() {
+ // Files in the 'no_backup' directory. We expect these to not be backed up.
+ File noBackupDir = mContext.getNoBackupFilesDir();
+ File folderInNoBackup = new File(noBackupDir, "folder_not_to_backup");
+
+ mNoBackupFile = new File(noBackupDir, "file_not_backed_up");
+ mNoBackupFile2 = new File(folderInNoBackup, "file_not_backed_up2");
+
+ // Files in the normal files directory. These should be backed up and restored.
+ File filesDir = mContext.getFilesDir();
+ File normalFolder = new File(filesDir, "normal_folder");
+
+ mDoBackupFile = new File(filesDir, "file_to_backup");
+ mDoBackupFile2 = new File(normalFolder, "file_to_backup2");
+ }
+
+ @Test
+ public void createFiles() throws Exception {
+ // Make sure the data does not exist from before
+ deleteAllFiles();
+ checkNoFilesExist();
+
+ // Create test data
+ generateFiles();
+ checkAllFilesExist();
+
+ Log.d(TAG, "Test files created:");
+ Log.d(TAG, mNoBackupFile.getAbsolutePath());
+ Log.d(TAG, mNoBackupFile2.getAbsolutePath());
+ Log.d(TAG, mDoBackupFile.getAbsolutePath());
+ Log.d(TAG, mDoBackupFile2.getAbsolutePath());
+ }
+
+ @Test
+ public void deleteFilesAfterBackup() throws Exception {
+ // Make sure the test data exists first
+ checkAllFilesExist();
+
+ // Delete test data
+ deleteAllFiles();
+
+ // No there should be no files left
+ checkNoFilesExist();
+ }
+
+ @Test
+ public void checkRestoredFiles() throws Exception {
+ // After a restore, only files outside the 'no_backup' folder should exist
+ checkNoBackupFilesDoNotExist();
+ checkDoBackupFilesDoExist();
+ }
+
+ private void generateFiles() {
+ try {
+ // Add data to all the files we created
+ addData(mNoBackupFile);
+ addData(mNoBackupFile2);
+ addData(mDoBackupFile);
+ addData(mDoBackupFile2);
+ Log.d(TAG, "Files generated!");
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to generate files", e);
+ }
+ }
+
+ private void deleteAllFiles() {
+ mNoBackupFile.delete();
+ mNoBackupFile2.delete();
+ mDoBackupFile.delete();
+ mDoBackupFile2.delete();
+ Log.d(TAG, "Files deleted!");
+ }
+
+ private void addData(File file) throws IOException {
+ file.getParentFile().mkdirs();
+ byte[] bytes = new byte[FILE_SIZE_BYTES];
+ new Random().nextBytes(bytes);
+
+ try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
+ bos.write(bytes, 0, bytes.length);
+ }
+ }
+
+ private void checkAllFilesExist() {
+ assertTrue("File in 'no_backup' did not exist!", mNoBackupFile.exists());
+ assertTrue("File in folder inside 'no_backup' did not exist!", mNoBackupFile2.exists());
+ assertTrue("File in 'files' did not exist!", mDoBackupFile.exists());
+ assertTrue("File in folder inside 'files' did not exist!", mDoBackupFile2.exists());
+ }
+
+ private void checkNoFilesExist() {
+ assertFalse("File in 'no_backup' did exist!", mNoBackupFile.exists());
+ assertFalse("File in folder inside 'no_backup' did exist!", mNoBackupFile2.exists());
+ assertFalse("File in 'files' did exist!", mDoBackupFile.exists());
+ assertFalse("File in folder inside 'files' did exist!", mDoBackupFile2.exists());
+ }
+
+ private void checkNoBackupFilesDoNotExist() {
+ assertFalse("File in 'no_backup' did exist!", mNoBackupFile.exists());
+ assertFalse("File in folder inside 'no_backup' did exist!", mNoBackupFile2.exists());
+ }
+
+ private void checkDoBackupFilesDoExist() {
+ assertTrue("File in 'files' did not exist!", mDoBackupFile.exists());
+ assertTrue("File in folder inside 'files' did not exist!", mDoBackupFile2.exists());
+ }
+}
diff --git a/hostsidetests/backup/src/android/backup/cts/BackupRestoreHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/BackupRestoreHostSideTest.java
similarity index 64%
rename from hostsidetests/backup/src/android/backup/cts/BackupRestoreHostSideTest.java
rename to hostsidetests/backup/src/android/cts/backup/BackupRestoreHostSideTest.java
index 2c239cd..f156e68 100644
--- a/hostsidetests/backup/src/android/backup/cts/BackupRestoreHostSideTest.java
+++ b/hostsidetests/backup/src/android/cts/backup/BackupRestoreHostSideTest.java
@@ -14,37 +14,20 @@
* limitations under the License
*/
-package android.backup.cts.backup;
+package android.cts.backup;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.cts.migration.MigrationHelper;
-import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
import java.io.FileNotFoundException;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* Test for checking that key/value backup and restore works correctly.
@@ -54,14 +37,7 @@
*
* NB: The tests uses "bmgr backupnow" for backup, which works on N+ devices.
*/
-public class BackupRestoreHostSideTest extends DeviceTestCase implements IBuildReceiver {
-
- /** Value of PackageManager.FEATURE_BACKUP */
- private static final String FEATURE_BACKUP = "android.software.backup";
-
- private static final String LOCAL_TRANSPORT =
- "android/com.android.internal.backup.LocalTransport";
-
+public class BackupRestoreHostSideTest extends BaseBackupHostSideTest {
/** The name of the APK of the app under test */
private static final String TEST_APP_APK = "CtsBackupRestoreDeviceApp.apk";
@@ -120,9 +96,6 @@
private boolean mIsBackupSupported;
private boolean mWasBackupEnabled;
private String mOldTransport;
- private ITestDevice mDevice;
- private HashSet<String> mAvailableFeatures;
- private IBuildInfo mCtsBuildInfo;
/**
* Map of the shared preferences/files values reported by the app.
@@ -130,31 +103,6 @@
*/
private Map<String, String> mSavedValues;
- @Override
- public void setBuild(IBuildInfo buildInfo) {
- mCtsBuildInfo = buildInfo;
- }
-
- @Override
- public void setUp() throws DeviceNotAvailableException, Exception {
- mDevice = getDevice();
- mIsBackupSupported = hasDeviceFeature(FEATURE_BACKUP);
- assumeTrue(mIsBackupSupported);
- // Enable backup and select local backup transport
- assertTrue("LocalTransport should be available.", hasBackupTransport(LOCAL_TRANSPORT));
- mWasBackupEnabled = enableBackup(true);
- mOldTransport = setBackupTransport(LOCAL_TRANSPORT);
- assertNotNull(mCtsBuildInfo);
- }
-
- @Override
- public void tearDown() throws Exception {
- if (mIsBackupSupported) {
- setBackupTransport(mOldTransport);
- enableBackup(mWasBackupEnabled);
- }
- }
-
public void testKeyValueBackupAndRestore() throws Exception {
// Clear app data if any
mDevice.executeShellCommand(CLEAR_DATA_IN_PACKAGE_UNDER_TEST_COMMAND);
@@ -171,15 +119,13 @@
// Run backup
// TODO: make this compatible with N-, potentially by replacing 'backupnow' with 'run'.
- String backupnowOutput = mDevice.executeShellCommand(
- "bmgr backupnow " + PACKAGE_UNDER_TEST);
+ String backupnowOutput = backupNow(PACKAGE_UNDER_TEST);
- assertBackupIsSuccessful(backupnowOutput);
+ assertBackupIsSuccessful(PACKAGE_UNDER_TEST, backupnowOutput);
mDevice.uninstallPackage(PACKAGE_UNDER_TEST);
- assertNull(mDevice.installPackage(MigrationHelper.getTestFile(mCtsBuildInfo, TEST_APP_APK),
- true));
+ assertNull(super.installPackage(TEST_APP_APK));
mDevice.executeAdbCommand("logcat", "-c");
@@ -217,27 +163,6 @@
}
/**
- * Parsing the output of "bmgr backupnow" command and checking that the package under test
- * was backed up successfully.
- *
- * Expected format: "Package android.backup.cts.backuprestoreapp with result: Success"
- */
- private void assertBackupIsSuccessful(String backupnowOutput) {
- // Assert backup was successful.
- Scanner in = new Scanner(backupnowOutput);
- while (in.hasNextLine()) {
- String line = in.nextLine();
-
- if (line.contains(PACKAGE_UNDER_TEST)) {
- String result = line.split(":")[1].trim();
-
- assertEquals(result, "Success");
- }
- }
- in.close();
- }
-
- /**
* Reads the values logged by the app and verifies that they are the same as the ones we saved
* in {@code mSavedValues}.
*/
@@ -312,71 +237,6 @@
* Returns the logcat string with the tag {@param className} and clears everything else.
*/
private String getLogcatForClass(String className) throws DeviceNotAvailableException {
- return mDevice.executeAdbCommand("logcat", "-v", "brief", "-d",
- className + ":I", "*:S");
- }
-
- // Copied over from BackupQuotaTest
- private boolean enableBackup(boolean enable) throws Exception {
- boolean previouslyEnabled;
- String output = mDevice.executeShellCommand("bmgr enabled");
- Pattern pattern = Pattern.compile("^Backup Manager currently (enabled|disabled)$");
- Matcher matcher = pattern.matcher(output.trim());
- if (matcher.find()) {
- previouslyEnabled = "enabled".equals(matcher.group(1));
- } else {
- throw new RuntimeException("non-parsable output setting bmgr enabled: " + output);
- }
-
- mDevice.executeShellCommand("bmgr enable " + enable);
- return previouslyEnabled;
- }
-
- // Copied over from BackupQuotaTest
- private String setBackupTransport(String transport) throws Exception {
- String output = mDevice.executeShellCommand("bmgr transport " + transport);
- Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
- Matcher matcher = pattern.matcher(output);
- if (matcher.find()) {
- return matcher.group(1);
- } else {
- throw new RuntimeException("non-parsable output setting bmgr transport: " + output);
- }
- }
-
- // Copied over from BackupQuotaTest
- private boolean hasBackupTransport(String transport) throws Exception {
- String output = mDevice.executeShellCommand("bmgr list transports");
- for (String t : output.split(" ")) {
- if (transport.equals(t.trim())) {
- return true;
- }
- }
- return false;
- }
-
- private boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
- if (mAvailableFeatures == null) {
- String command = "pm list features";
- String commandOutput = getDevice().executeShellCommand(command);
- CLog.i("Output for command " + command + ": " + commandOutput);
-
- // Extract the id of the new user.
- mAvailableFeatures = new HashSet<>();
- for (String feature: commandOutput.split("\\s+")) {
- // Each line in the output of the command has the format "feature:{FEATURE_VALUE}".
- String[] tokens = feature.split(":");
- assertTrue("\"" + feature + "\" expected to have format feature:{FEATURE_VALUE}",
- tokens.length > 1);
- assertEquals(feature, "feature", tokens[0]);
- mAvailableFeatures.add(tokens[1]);
- }
- }
- boolean result = mAvailableFeatures.contains(requiredFeature);
- if (!result) {
- CLog.d("Device doesn't have required feature "
- + requiredFeature + ". Test won't run.");
- }
- return result;
+ return mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", className + ":I", "*:S");
}
}
diff --git a/hostsidetests/backup/src/android/cts/backup/BaseBackupHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/BaseBackupHostSideTest.java
new file mode 100644
index 0000000..a3c2467
--- /dev/null
+++ b/hostsidetests/backup/src/android/cts/backup/BaseBackupHostSideTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2017 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.cts.backup;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.TestResult;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.FileNotFoundException;
+import java.util.Map;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.Scanner;
+
+/**
+ * Base class for CTS backup/restore hostside tests
+ */
+public abstract class BaseBackupHostSideTest extends DeviceTestCase implements IBuildReceiver {
+
+ /** Value of PackageManager.FEATURE_BACKUP */
+ private static final String FEATURE_BACKUP = "android.software.backup";
+
+ private static final String LOCAL_TRANSPORT =
+ "android/com.android.internal.backup.LocalTransport";
+
+ protected ITestDevice mDevice;
+
+ private boolean mIsBackupSupported;
+ private boolean mWasBackupEnabled;
+ private String mOldTransport;
+ private HashSet<String> mAvailableFeatures;
+ private IBuildInfo mCtsBuildInfo;
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuildInfo = buildInfo;
+ }
+
+ @Override
+ public void setUp() throws DeviceNotAvailableException, Exception {
+ mDevice = getDevice();
+ mIsBackupSupported = hasDeviceFeature(FEATURE_BACKUP);
+ assumeTrue(mIsBackupSupported);
+ // Enable backup and select local backup transport
+ assertTrue("LocalTransport should be available.", hasBackupTransport(LOCAL_TRANSPORT));
+ mWasBackupEnabled = enableBackup(true);
+ mOldTransport = setBackupTransport(LOCAL_TRANSPORT);
+ assertNotNull(mCtsBuildInfo);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ if (mIsBackupSupported) {
+ setBackupTransport(mOldTransport);
+ enableBackup(mWasBackupEnabled);
+ }
+ }
+
+ /**
+ * Execute shell command "bmgr backupnow <packageName>" and return output from this command.
+ */
+ protected String backupNow(String packageName) throws DeviceNotAvailableException {
+ return mDevice.executeShellCommand("bmgr backupnow " + packageName);
+ }
+
+ /**
+ * Execute shell command "bmgr restore <packageName>" and return output from this command.
+ */
+ protected String restore(String packageName) throws DeviceNotAvailableException {
+ return mDevice.executeShellCommand("bmgr restore " + packageName);
+ }
+
+ /**
+ * Copied from com.android.cts.net.HostsideNetworkTestCase.
+ */
+ protected void runDeviceTest(String packageName, String className, String testName)
+ throws DeviceNotAvailableException {
+ RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
+ "android.support.test.runner.AndroidJUnitRunner", mDevice.getIDevice());
+
+ if (className != null) {
+ if (testName != null) {
+ testRunner.setMethodName(className, testName);
+ } else {
+ testRunner.setClassName(className);
+ }
+ }
+
+ final CollectingTestListener listener = new CollectingTestListener();
+ mDevice.runInstrumentationTests(testRunner, listener);
+
+ final TestRunResult result = listener.getCurrentRunResults();
+ if (result.isRunFailure()) {
+ throw new AssertionError("Failed to successfully run device tests for "
+ + result.getName() + ": " + result.getRunFailureMessage());
+ }
+ if (result.getNumTests() == 0) {
+ throw new AssertionError("No tests were run on the device");
+ }
+ if (result.hasFailedTests()) {
+ // build a meaningful error message
+ StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
+ for (Map.Entry<TestIdentifier, TestResult> resultEntry :
+ result.getTestResults().entrySet()) {
+ if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+ errorBuilder.append(resultEntry.getKey().toString());
+ errorBuilder.append(":\n");
+ errorBuilder.append(resultEntry.getValue().getStackTrace());
+ }
+ }
+ throw new AssertionError(errorBuilder.toString());
+ }
+ }
+
+ /**
+ * Parsing the output of "bmgr backupnow" command and checking that the package under test
+ * was backed up successfully.
+ *
+ * Expected format: "Package <packageName> with result: Success"
+ */
+ protected void assertBackupIsSuccessful(String packageName, String backupnowOutput) {
+ // Assert backup was successful.
+ Scanner in = new Scanner(backupnowOutput);
+ boolean success = false;
+ while (in.hasNextLine()) {
+ String line = in.nextLine();
+
+ if (line.contains(packageName)) {
+ String result = line.split(":")[1].trim();
+ if ("Success".equals(result)) {
+ success = true;
+ }
+ }
+ }
+ in.close();
+ assertTrue(success);
+ }
+
+ protected String installPackage(String apkName)
+ throws DeviceNotAvailableException, FileNotFoundException {
+ return mDevice.installPackage(MigrationHelper.getTestFile(mCtsBuildInfo, apkName), true);
+ }
+
+ /**
+ * Parsing the output of "bmgr restore" command and checking that the package under test
+ * was restored successfully.
+ *
+ * Expected format: "restoreFinished: 0"
+ */
+ protected void assertRestoreIsSuccessful(String restoreOutput) {
+ assertTrue("Restore not successful", restoreOutput.contains("restoreFinished: 0"));
+ }
+
+ private boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
+ if (mAvailableFeatures == null) {
+ String command = "pm list features";
+ String commandOutput = getDevice().executeShellCommand(command);
+ CLog.i("Output for command " + command + ": " + commandOutput);
+
+ // Extract the id of the new user.
+ mAvailableFeatures = new HashSet<>();
+ for (String feature: commandOutput.split("\\s+")) {
+ // Each line in the output of the command has the format "feature:{FEATURE_VALUE}".
+ String[] tokens = feature.split(":");
+ assertTrue("\"" + feature + "\" expected to have format feature:{FEATURE_VALUE}",
+ tokens.length > 1);
+ assertEquals(feature, "feature", tokens[0]);
+ mAvailableFeatures.add(tokens[1]);
+ }
+ }
+ boolean result = mAvailableFeatures.contains(requiredFeature);
+ if (!result) {
+ CLog.d("Device doesn't have required feature "
+ + requiredFeature + ". Test won't run.");
+ }
+ return result;
+ }
+
+ // Copied over from BackupQuotaTest
+ private boolean enableBackup(boolean enable) throws Exception {
+ boolean previouslyEnabled;
+ String output = mDevice.executeShellCommand("bmgr enabled");
+ Pattern pattern = Pattern.compile("^Backup Manager currently (enabled|disabled)$");
+ Matcher matcher = pattern.matcher(output.trim());
+ if (matcher.find()) {
+ previouslyEnabled = "enabled".equals(matcher.group(1));
+ } else {
+ throw new RuntimeException("non-parsable output setting bmgr enabled: " + output);
+ }
+
+ mDevice.executeShellCommand("bmgr enable " + enable);
+ return previouslyEnabled;
+ }
+
+ // Copied over from BackupQuotaTest
+ private String setBackupTransport(String transport) throws Exception {
+ String output = mDevice.executeShellCommand("bmgr transport " + transport);
+ Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
+ Matcher matcher = pattern.matcher(output);
+ if (matcher.find()) {
+ return matcher.group(1);
+ } else {
+ throw new RuntimeException("non-parsable output setting bmgr transport: " + output);
+ }
+ }
+
+ // Copied over from BackupQuotaTest
+ private boolean hasBackupTransport(String transport) throws Exception {
+ String output = mDevice.executeShellCommand("bmgr list transports");
+ for (String t : output.split(" ")) {
+ if (transport.equals(t.trim())) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/hostsidetests/backup/src/android/cts/backup/NoBackupFolderHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/NoBackupFolderHostSideTest.java
new file mode 100644
index 0000000..d51b46d
--- /dev/null
+++ b/hostsidetests/backup/src/android/cts/backup/NoBackupFolderHostSideTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.cts.backup;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test checking that files created by an app are restored successfully after a backup, but that
+ * files put in the folder provided by getNoBackupFilesDir() [files/no_backup] are NOT backed up.
+ *
+ * Invokes device side tests provided by android.cts.backup.fullbackupapp.FullbackupTest.
+ */
+public class NoBackupFolderHostSideTest extends BaseBackupHostSideTest {
+
+ private static final String TESTS_APP_NAME = "android.cts.backup.fullbackupapp";
+ private static final String DEVICE_TEST_CLASS_NAME = TESTS_APP_NAME + ".FullbackupTest";
+
+ public void testNoBackupFolder() throws Exception {
+ // Generate the files that are going to be backed up.
+ runDeviceTest(TESTS_APP_NAME, DEVICE_TEST_CLASS_NAME, "createFiles");
+
+ // Do a backup
+ String backupnowOutput = backupNow(TESTS_APP_NAME);
+
+ assertBackupIsSuccessful(TESTS_APP_NAME, backupnowOutput);
+
+ // Delete the files
+ runDeviceTest(TESTS_APP_NAME, DEVICE_TEST_CLASS_NAME, "deleteFilesAfterBackup");
+
+ // Do a restore
+ String restoreOutput = restore(TESTS_APP_NAME);
+
+ assertRestoreIsSuccessful(restoreOutput);
+
+ // Check that the right files were restored
+ runDeviceTest(TESTS_APP_NAME, DEVICE_TEST_CLASS_NAME, "checkRestoredFiles");
+ }
+}