Add lifecycle and quota tests for key value backup

Test: run CtsBackupTests
Change-Id: I553b2e3c09a4caae04d306565eee1aee2df578c8
diff --git a/tests/backup/AndroidTest.xml b/tests/backup/AndroidTest.xml
index f292943..ec18a5d 100644
--- a/tests/backup/AndroidTest.xml
+++ b/tests/backup/AndroidTest.xml
@@ -18,7 +18,8 @@
     <option name="config-descriptor:metadata" key="component" value="backup" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsBackupApp.apk" />
+        <option name="test-file-name" value="CtsFullBackupApp.apk" />
+        <option name="test-file-name" value="CtsKeyValueBackupApp.apk" />
         <option name="test-file-name" value="CtsBackupTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/backup/app/Android.mk b/tests/backup/app/Android.mk
index dd1992b..cddf11e 100644
--- a/tests/backup/app/Android.mk
+++ b/tests/backup/app/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2016 The Android Open Source Project
+# 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.
@@ -14,21 +14,4 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsBackupApp
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    compatibility-device-util \
-    ctstestrunner
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/backup/app/fullbackup/Android.mk b/tests/backup/app/fullbackup/Android.mk
new file mode 100644
index 0000000..a8b4f5a
--- /dev/null
+++ b/tests/backup/app/fullbackup/Android.mk
@@ -0,0 +1,34 @@
+# 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)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+
+LOCAL_PACKAGE_NAME := CtsFullBackupApp
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    ctstestrunner
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/backup/app/AndroidManifest.xml b/tests/backup/app/fullbackup/AndroidManifest.xml
similarity index 95%
rename from tests/backup/app/AndroidManifest.xml
rename to tests/backup/app/fullbackup/AndroidManifest.xml
index 1507bc2..849b13f 100644
--- a/tests/backup/app/AndroidManifest.xml
+++ b/tests/backup/app/fullbackup/AndroidManifest.xml
@@ -20,7 +20,7 @@
 
     <application
         android:allowBackup="true"
-        android:backupAgent="BackupCtsBackupAgent"
+        android:backupAgent="FullBackupBackupAgent"
         android:label="Android Backup CTS App"
         android:fullBackupOnly="true">
         <activity
diff --git a/tests/backup/app/keyvalue/Android.mk b/tests/backup/app/keyvalue/Android.mk
new file mode 100644
index 0000000..b6f17e6
--- /dev/null
+++ b/tests/backup/app/keyvalue/Android.mk
@@ -0,0 +1,34 @@
+# 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)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+
+LOCAL_PACKAGE_NAME := CtsKeyValueBackupApp
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    ctstestrunner
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/backup/app/AndroidManifest.xml b/tests/backup/app/keyvalue/AndroidManifest.xml
similarity index 78%
copy from tests/backup/app/AndroidManifest.xml
copy to tests/backup/app/keyvalue/AndroidManifest.xml
index 1507bc2..c99b4b4 100644
--- a/tests/backup/app/AndroidManifest.xml
+++ b/tests/backup/app/keyvalue/AndroidManifest.xml
@@ -16,16 +16,15 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.backup.app" >
+    package="android.backup.kvapp" >
 
     <application
         android:allowBackup="true"
-        android:backupAgent="BackupCtsBackupAgent"
-        android:label="Android Backup CTS App"
-        android:fullBackupOnly="true">
+        android:backupAgent="android.backup.app.KeyValueBackupAgent"
+        android:label="Android Key Value Backup CTS App">
         <activity
-            android:name=".MainActivity"
-            android:label="Android Backup CTS App" >
+            android:name="android.backup.app.MainActivity"
+            android:label="Android Key Value Backup CTS App" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java b/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
similarity index 90%
rename from tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java
rename to tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
index ea5f2af..8535344 100644
--- a/tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java
+++ b/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
@@ -27,11 +27,11 @@
 import java.io.IOException;
 
 /*
- * Backup agent for Backup CTS App.
+ * Full Backup agent for Backup CTS App.
  *
  * Logs callbacks into logcat.
  */
-public class BackupCtsBackupAgent extends BackupAgent {
+public class FullBackupBackupAgent extends BackupAgent {
 
     @Override
     public void onCreate() {
@@ -41,13 +41,13 @@
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
                          ParcelFileDescriptor newState) throws IOException {
-        Log.d(MainActivity.TAG, "Backup requested");
+        throw new IllegalStateException("unexpected onBackup");
     }
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode,
                           ParcelFileDescriptor newState) throws IOException {
-        Log.d(MainActivity.TAG, "Restore requested");
+        throw new IllegalStateException("unexpected onRestore");
     }
 
     @Override
diff --git a/tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java b/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
similarity index 70%
copy from tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java
copy to tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
index ea5f2af..155d8f9 100644
--- a/tests/backup/app/src/android/backup/app/BackupCtsBackupAgent.java
+++ b/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
@@ -24,14 +24,15 @@
 import android.util.Log;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 
 /*
- * Backup agent for Backup CTS App.
+ * Key Value Backup agent for Backup CTS App.
  *
  * Logs callbacks into logcat.
  */
-public class BackupCtsBackupAgent extends BackupAgent {
+public class KeyValueBackupAgent extends BackupAgent {
 
     @Override
     public void onCreate() {
@@ -41,7 +42,20 @@
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
                          ParcelFileDescriptor newState) throws IOException {
-        Log.d(MainActivity.TAG, "Backup requested");
+        Log.d(MainActivity.TAG, "Backup requested, quota is " + data.getQuota());
+
+        // Always backup the entire file
+        File testFile = new File(getFilesDir(), MainActivity.FILE_NAME);
+        Log.d(MainActivity.TAG, "Writing " + testFile.length());
+
+        data.writeEntityHeader(MainActivity.FILE_NAME, (int) testFile.length());
+        byte[] buffer = new byte[4096];
+        try (FileInputStream input = new FileInputStream(testFile)) {
+            int read;
+            while ((read = input.read(buffer)) >= 0) {
+                data.writeEntityData(buffer, read);
+            }
+        }
     }
 
     @Override
@@ -53,14 +67,12 @@
     @Override
     public void onRestoreFile(ParcelFileDescriptor data, long size,
             File destination, int type, long mode, long mtime) throws IOException {
-        Log.d(MainActivity.TAG, "onRestoreFile " + destination);
-        super.onRestoreFile(data, size, destination, type, mode, mtime);
+        throw new IllegalStateException("unexpected onRestoreFile");
     }
 
     @Override
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
-        Log.d(MainActivity.TAG, "Full backup requested, quota is " + data.getQuota());
-        super.onFullBackup(data);
+        throw new IllegalStateException("unexpected onFullBackup");
     }
 
     @Override
diff --git a/tests/backup/app/src/android/backup/app/MainActivity.java b/tests/backup/app/src/android/backup/app/MainActivity.java
index 93c6dd6..3127a56 100644
--- a/tests/backup/app/src/android/backup/app/MainActivity.java
+++ b/tests/backup/app/src/android/backup/app/MainActivity.java
@@ -40,8 +40,8 @@
  */
 public class MainActivity extends Activity {
     public static final String TAG = "BackupCTSApp";
+    public static final String FILE_NAME = "file_name";
 
-    private static final String FILE_NAME = "file_name";
     private static final String FILE_SIZE_EXTRA = "file_size";
     private static final int DATA_CHUNK_SIZE = 1024 * 1024;
 
@@ -60,6 +60,7 @@
         } else {
             Log.d(TAG, "No file size was provided");
         }
+        finish();
     }
 
     private void createFile(int size) throws IOException {
diff --git a/tests/backup/src/android/backup/cts/BaseBackupCtsTest.java b/tests/backup/src/android/backup/cts/BaseBackupCtsTest.java
index 5f361e8..0fa2775 100644
--- a/tests/backup/src/android/backup/cts/BaseBackupCtsTest.java
+++ b/tests/backup/src/android/backup/cts/BaseBackupCtsTest.java
@@ -41,7 +41,6 @@
 
     private static final String LOCAL_TRANSPORT =
             "android/com.android.internal.backup.LocalTransport";
-    protected static final String BACKUP_APP_NAME = "android.backup.app";
 
     private static final int SMALL_LOGCAT_DELAY = 1000;
 
@@ -134,10 +133,10 @@
         return false;
     }
 
-    protected void createTestFileOfSize(int size) throws Exception {
-        exec("am start -W -a android.intent.action.MAIN " +
+    protected void createTestFileOfSize(String packageName, int size) throws Exception {
+        exec("am start -a android.intent.action.MAIN " +
             "-c android.intent.category.LAUNCHER " +
-            "-n " + BACKUP_APP_NAME + "/" + BACKUP_APP_NAME +".MainActivity " +
+            "-n " + packageName + "/android.backup.app.MainActivity " +
             "-e file_size " + size);
         assertTrue("File was not created", waitForLogcat("File created!", 30));
     }
diff --git a/tests/backup/src/android/backup/cts/FullBackupLifecycleTest.java b/tests/backup/src/android/backup/cts/FullBackupLifecycleTest.java
index 8b2b2cb..16ecb79 100644
--- a/tests/backup/src/android/backup/cts/FullBackupLifecycleTest.java
+++ b/tests/backup/src/android/backup/cts/FullBackupLifecycleTest.java
@@ -21,6 +21,8 @@
  */
 public class FullBackupLifecycleTest extends BaseBackupCtsTest {
 
+    private static final String BACKUP_APP_NAME = "android.backup.app";
+
     private static final int LOCAL_TRANSPORT_CONFORMING_FILE_SIZE = 5 * 1024;
 
     public void testExpectedMethodsCalledInOrder() throws Exception {
@@ -31,7 +33,7 @@
         exec("setprop log.tag." + APP_LOG_TAG +" VERBOSE");
 
         // Make sure there's something to backup
-        createTestFileOfSize(LOCAL_TRANSPORT_CONFORMING_FILE_SIZE);
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_CONFORMING_FILE_SIZE);
 
         // Request backup and wait for it to complete
         exec("bmgr backupnow " + BACKUP_APP_NAME);
diff --git a/tests/backup/src/android/backup/cts/FullBackupQuotaTest.java b/tests/backup/src/android/backup/cts/FullBackupQuotaTest.java
index 1adbcfb..cfe007c 100644
--- a/tests/backup/src/android/backup/cts/FullBackupQuotaTest.java
+++ b/tests/backup/src/android/backup/cts/FullBackupQuotaTest.java
@@ -24,6 +24,8 @@
  */
 public class FullBackupQuotaTest extends BaseBackupCtsTest {
 
+    private static final String BACKUP_APP_NAME = "android.backup.app";
+
     // Should be the same as LocalTransport.FULL_BACKUP_SIZE_QUOTA
     private static final int LOCAL_TRANSPORT_BACKUP_QUOTA = 25 * 1024 * 1024;
     private static final int LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE = 30 * 1024 * 1024;
@@ -35,7 +37,7 @@
         exec("logcat --clear");
         exec("setprop log.tag." + APP_LOG_TAG +" VERBOSE");
         // Launch test app and create file exceeding limit for local transport
-        createTestFileOfSize(LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE);
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE);
 
         // Request backup and wait for quota exceeded event in logcat
         exec("bmgr backupnow " + BACKUP_APP_NAME);
diff --git a/tests/backup/src/android/backup/cts/KeyValueLifecycleTest.java b/tests/backup/src/android/backup/cts/KeyValueLifecycleTest.java
new file mode 100644
index 0000000..420c723
--- /dev/null
+++ b/tests/backup/src/android/backup/cts/KeyValueLifecycleTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.backup.cts;
+
+/**
+ * Verifies that key methods are called in expected order during backup / restore.
+ */
+public class KeyValueLifecycleTest extends BaseBackupCtsTest {
+
+    private static final String BACKUP_APP_NAME = "android.backup.kvapp";
+
+    private static final int LOCAL_TRANSPORT_CONFORMING_FILE_SIZE = 5 * 1024;
+
+    public void testExpectedMethodsCalledInOrder() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        exec("logcat --clear");
+        exec("setprop log.tag." + APP_LOG_TAG +" VERBOSE");
+
+        // Make sure there's something to backup
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_CONFORMING_FILE_SIZE);
+
+        // Request backup and wait for it to complete
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+        assertTrue("Backup agent not destroyed", waitForLogcat("onDestroy", 10));
+
+        verifyContainsInOrder(execLogcat(),
+            "onCreate",
+            "Backup requested",
+            "onDestroy");
+
+        exec("logcat --clear");
+
+        // Now request restore and wait for it to complete
+        exec("bmgr restore " + BACKUP_APP_NAME);
+        assertTrue("Backup agent not destroyed", waitForLogcat("onDestroy", 10));
+
+        verifyContainsInOrder(execLogcat(),
+            "onCreate",
+            "Restore requested",
+            "onRestoreFinished",
+            "onDestroy");
+    }
+
+    private void verifyContainsInOrder(String message, String... substrings) {
+        int currentIndex = 0;
+        for (String substring : substrings) {
+            int substringIndex = message.indexOf(substring, currentIndex);
+            if (substringIndex < 0) {
+                fail("Didn't find '" + substring + "' in expected order");
+            }
+            currentIndex = substringIndex + substring.length();
+        }
+    };
+
+    private String execLogcat() throws Exception {
+        return exec("logcat -v brief -d " + APP_LOG_TAG + ":* *:S");
+    }
+}
diff --git a/tests/backup/src/android/backup/cts/KeyValueQuotaTest.java b/tests/backup/src/android/backup/cts/KeyValueQuotaTest.java
new file mode 100644
index 0000000..9647d07
--- /dev/null
+++ b/tests/backup/src/android/backup/cts/KeyValueQuotaTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.backup.cts;
+
+/**
+ * Verifies receiving quotaExceeded() callback on full backup.
+ *
+ * Uses test app that creates large file and receives the callback.
+ * {@link com.android.internal.backup.LocalTransport} is used, it has size quota 25MB.
+ */
+public class KeyValueQuotaTest extends BaseBackupCtsTest {
+
+    private static final String BACKUP_APP_NAME = "android.backup.kvapp";
+
+    // Should be the same as LocalTransport. KEY_VALUE_BACKUP_SIZE_QUOTA
+    private static final int LOCAL_TRANSPORT_BACKUP_QUOTA = 5 * 1024 * 1024;
+    private static final int LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE = 6 * 1024 * 1024;
+
+    public void testQuotaExceeded() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        exec("logcat --clear");
+        exec("setprop log.tag." + APP_LOG_TAG +" VERBOSE");
+        // Launch test app and create file exceeding limit for local transport
+        createTestFileOfSize(BACKUP_APP_NAME, LOCAL_TRANSPORT_EXCEEDING_FILE_SIZE);
+
+        // Request backup and wait for quota exceeded event in logcat
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+        assertTrue("Quota exceeded event is not received", waitForLogcat("Quota exceeded!", 10));
+    }
+
+    public void testQuotaReported() throws Exception {
+        if (!isBackupSupported()) {
+            return;
+        }
+        exec("logcat --clear");
+        exec("bmgr backupnow " + BACKUP_APP_NAME);
+        assertTrue("Quota not reported correctly",
+                waitForLogcat("quota is " + LOCAL_TRANSPORT_BACKUP_QUOTA, 10));
+    }
+
+}