summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/Android.mk52
-rw-r--r--tests/common/test_constants.h25
-rw-r--r--tests/component/applypatch_test.cpp392
-rw-r--r--tests/component/verifier_test.cpp178
-rw-r--r--tests/testdata/alter-footer.zip (renamed from testdata/alter-footer.zip)bin4009 -> 4009 bytes
-rw-r--r--tests/testdata/alter-metadata.zip (renamed from testdata/alter-metadata.zip)bin4009 -> 4009 bytes
-rw-r--r--tests/testdata/fake-eocd.zip (renamed from testdata/fake-eocd.zip)bin4313 -> 4313 bytes
-rw-r--r--tests/testdata/jarsigned.zip (renamed from testdata/jarsigned.zip)bin2271 -> 2271 bytes
-rw-r--r--tests/testdata/new.filebin0 -> 1388877 bytes
-rw-r--r--tests/testdata/old.filebin0 -> 1348051 bytes
-rw-r--r--tests/testdata/otasigned.zip (renamed from testdata/otasigned.zip)bin4009 -> 4009 bytes
-rw-r--r--tests/testdata/otasigned_ecdsa_sha256.zip (renamed from testdata/otasigned_ecdsa_sha256.zip)bin3085 -> 3085 bytes
-rw-r--r--tests/testdata/otasigned_f4.zip (renamed from testdata/otasigned_f4.zip)bin5195 -> 5195 bytes
-rw-r--r--tests/testdata/otasigned_f4_sha256.zip (renamed from testdata/otasigned_f4_sha256.zip)bin5319 -> 5319 bytes
-rw-r--r--tests/testdata/otasigned_sha256.zip (renamed from testdata/otasigned_sha256.zip)bin5326 -> 5326 bytes
-rw-r--r--tests/testdata/patch.bsdiffbin0 -> 57476 bytes
-rw-r--r--tests/testdata/random.zip (renamed from testdata/random.zip)bin1024 -> 1024 bytes
-rw-r--r--tests/testdata/test_f4.pk8 (renamed from testdata/test_f4.pk8)bin1217 -> 1217 bytes
-rw-r--r--tests/testdata/test_f4.x509.pem (renamed from testdata/test_f4.x509.pem)0
-rw-r--r--tests/testdata/test_f4_sha256.x509.pem (renamed from testdata/test_f4_sha256.x509.pem)0
-rw-r--r--tests/testdata/test_key_e3.txt1
-rw-r--r--tests/testdata/test_key_ec.txt1
-rw-r--r--tests/testdata/test_key_f4.txt1
-rw-r--r--tests/testdata/testkey.pk8 (renamed from testdata/testkey.pk8)bin1217 -> 1217 bytes
-rw-r--r--tests/testdata/testkey.x509.pem (renamed from testdata/testkey.x509.pem)0
-rw-r--r--tests/testdata/testkey_ecdsa.pk8 (renamed from testdata/testkey_ecdsa.pk8)bin138 -> 138 bytes
-rw-r--r--tests/testdata/testkey_ecdsa.x509.pem (renamed from testdata/testkey_ecdsa.x509.pem)0
-rw-r--r--tests/testdata/testkey_sha256.x509.pem (renamed from testdata/testkey_sha256.x509.pem)0
-rw-r--r--tests/testdata/unsigned.zip (renamed from testdata/unsigned.zip)bin376 -> 376 bytes
-rw-r--r--tests/unit/asn1_decoder_test.cpp (renamed from tests/asn1_decoder_test.cpp)0
-rw-r--r--tests/unit/locale_test.cpp29
-rw-r--r--tests/unit/recovery_test.cpp92
32 files changed, 767 insertions, 4 deletions
diff --git a/tests/Android.mk b/tests/Android.mk
index 02a272a24..a66991b21 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -16,10 +16,54 @@
LOCAL_PATH := $(call my-dir)
+# Unit tests
include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_MODULE := recovery_unit_test
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_STATIC_LIBRARIES := libverifier
-LOCAL_SRC_FILES := asn1_decoder_test.cpp
-LOCAL_MODULE := asn1_decoder_test
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
+LOCAL_STATIC_LIBRARIES := \
+ libverifier \
+ libminui
+
+LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp
+LOCAL_SRC_FILES += unit/recovery_test.cpp
+LOCAL_SRC_FILES += unit/locale_test.cpp
+LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_SHARED_LIBRARIES := liblog
+include $(BUILD_NATIVE_TEST)
+
+# Component tests
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_MODULE := recovery_component_test
+LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_SRC_FILES := \
+ component/verifier_test.cpp \
+ component/applypatch_test.cpp
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := \
+ libapplypatch \
+ libotafault \
+ libmtdutils \
+ libbase \
+ libverifier \
+ libcrypto_static \
+ libminui \
+ libminzip \
+ libcutils \
+ libbz \
+ libz \
+ libc
+
+testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery
+testdata_files := $(call find-subdir-files, testdata/*)
+
+GEN := $(addprefix $(testdata_out_path)/, $(testdata_files))
+$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
+$(GEN): $(testdata_out_path)/% : $(LOCAL_PATH)/%
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
include $(BUILD_NATIVE_TEST)
diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h
new file mode 100644
index 000000000..3490f6805
--- /dev/null
+++ b/tests/common/test_constants.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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 agree 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.
+ */
+#ifndef _OTA_TEST_CONSTANTS_H
+#define _OTA_TEST_CONSTANTS_H
+
+#if defined(__LP64__)
+#define NATIVE_TEST_PATH "/nativetest64"
+#else
+#define NATIVE_TEST_PATH "/nativetest"
+#endif
+
+#endif
diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp
new file mode 100644
index 000000000..b44ddd17c
--- /dev/null
+++ b/tests/component/applypatch_test.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2016 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 agree 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.
+ */
+
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+
+#include "applypatch/applypatch.h"
+#include "common/test_constants.h"
+#include "openssl/sha.h"
+#include "print_sha1.h"
+
+static const std::string DATA_PATH = getenv("ANDROID_DATA");
+static const std::string TESTDATA_PATH = "/recovery/testdata";
+static const std::string WORK_FS = "/data";
+
+static std::string sha1sum(const std::string& fname) {
+ uint8_t digest[SHA_DIGEST_LENGTH];
+ std::string data;
+ android::base::ReadFileToString(fname, &data);
+
+ SHA1((const uint8_t*)data.c_str(), data.size(), digest);
+ return print_sha1(digest);
+}
+
+static void mangle_file(const std::string& fname) {
+ FILE* fh = fopen(&fname[0], "w");
+ int r;
+ for (int i=0; i < 1024; i++) {
+ r = rand();
+ fwrite(&r, sizeof(short), 1, fh);
+ }
+ fclose(fh);
+}
+
+static bool file_cmp(std::string& f1, std::string& f2) {
+ std::string c1;
+ std::string c2;
+ android::base::ReadFileToString(f1, &c1);
+ android::base::ReadFileToString(f2, &c2);
+ return c1 == c2;
+}
+
+static std::string from_testdata_base(const std::string fname) {
+ return android::base::StringPrintf("%s%s%s/%s",
+ &DATA_PATH[0],
+ &NATIVE_TEST_PATH[0],
+ &TESTDATA_PATH[0],
+ &fname[0]);
+}
+
+class ApplyPatchTest : public ::testing::Test {
+ public:
+ static void SetUpTestCase() {
+ // set up files
+ old_file = from_testdata_base("old.file");
+ new_file = from_testdata_base("new.file");
+ patch_file = from_testdata_base("patch.bsdiff");
+ rand_file = "/cache/applypatch_test_rand.file";
+ cache_file = "/cache/saved.file";
+
+ // write stuff to rand_file
+ android::base::WriteStringToFile("hello", rand_file);
+
+ // set up SHA constants
+ old_sha1 = sha1sum(old_file);
+ new_sha1 = sha1sum(new_file);
+ srand(time(NULL));
+ bad_sha1_a = android::base::StringPrintf("%040x", rand());
+ bad_sha1_b = android::base::StringPrintf("%040x", rand());
+
+ struct stat st;
+ stat(&new_file[0], &st);
+ new_size = st.st_size;
+ }
+
+ static std::string old_file;
+ static std::string new_file;
+ static std::string rand_file;
+ static std::string cache_file;
+ static std::string patch_file;
+
+ static std::string old_sha1;
+ static std::string new_sha1;
+ static std::string bad_sha1_a;
+ static std::string bad_sha1_b;
+
+ static size_t new_size;
+};
+
+std::string ApplyPatchTest::old_file;
+std::string ApplyPatchTest::new_file;
+
+static void cp(std::string src, std::string tgt) {
+ std::string cmd = android::base::StringPrintf("cp %s %s",
+ &src[0],
+ &tgt[0]);
+ system(&cmd[0]);
+}
+
+static void backup_old() {
+ cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
+}
+
+static void restore_old() {
+ cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
+}
+
+class ApplyPatchCacheTest : public ApplyPatchTest {
+ public:
+ virtual void SetUp() {
+ backup_old();
+ }
+
+ virtual void TearDown() {
+ restore_old();
+ }
+};
+
+class ApplyPatchFullTest : public ApplyPatchCacheTest {
+ public:
+ static void SetUpTestCase() {
+ ApplyPatchTest::SetUpTestCase();
+ unsigned long free_kb = FreeSpaceForFile(&WORK_FS[0]);
+ ASSERT_GE(free_kb * 1024, new_size * 3 / 2);
+ output_f = new TemporaryFile();
+ output_loc = std::string(output_f->path);
+
+ struct FileContents fc;
+
+ ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc));
+ Value* patch1 = new Value();
+ patch1->type = VAL_BLOB;
+ patch1->size = fc.data.size();
+ patch1->data = static_cast<char*>(malloc(fc.data.size()));
+ memcpy(patch1->data, fc.data.data(), fc.data.size());
+ patches.push_back(patch1);
+
+ ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
+ Value* patch2 = new Value();
+ patch2->type = VAL_BLOB;
+ patch2->size = fc.st.st_size;
+ patch2->data = static_cast<char*>(malloc(fc.data.size()));
+ memcpy(patch2->data, fc.data.data(), fc.data.size());
+ patches.push_back(patch2);
+ }
+ static void TearDownTestCase() {
+ delete output_f;
+ for (auto it = patches.begin(); it != patches.end(); ++it) {
+ free((*it)->data);
+ delete *it;
+ }
+ patches.clear();
+ }
+
+ static std::vector<Value*> patches;
+ static TemporaryFile* output_f;
+ static std::string output_loc;
+};
+
+class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
+ public:
+ virtual void SetUp() {
+ ApplyPatchCacheTest::SetUp();
+ cp(cache_file, "/cache/reallysaved.file");
+ }
+
+ virtual void TearDown() {
+ cp("/cache/reallysaved.file", cache_file);
+ ApplyPatchCacheTest::TearDown();
+ }
+};
+
+std::string ApplyPatchTest::rand_file;
+std::string ApplyPatchTest::patch_file;
+std::string ApplyPatchTest::cache_file;
+std::string ApplyPatchTest::old_sha1;
+std::string ApplyPatchTest::new_sha1;
+std::string ApplyPatchTest::bad_sha1_a;
+std::string ApplyPatchTest::bad_sha1_b;
+
+size_t ApplyPatchTest::new_size;
+
+std::vector<Value*> ApplyPatchFullTest::patches;
+TemporaryFile* ApplyPatchFullTest::output_f;
+std::string ApplyPatchFullTest::output_loc;
+
+TEST_F(ApplyPatchTest, CheckModeSingle) {
+ char* s = &old_sha1[0];
+ ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
+}
+
+TEST_F(ApplyPatchTest, CheckModeMultiple) {
+ char* argv[3] = {
+ &bad_sha1_a[0],
+ &old_sha1[0],
+ &bad_sha1_b[0]
+ };
+ ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
+}
+
+TEST_F(ApplyPatchTest, CheckModeFailure) {
+ char* argv[2] = {
+ &bad_sha1_a[0],
+ &bad_sha1_b[0]
+ };
+ ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
+}
+
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
+ mangle_file(old_file);
+ char* s = &old_sha1[0];
+ ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
+}
+
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
+ mangle_file(old_file);
+ char* argv[3] = {
+ &bad_sha1_a[0],
+ &old_sha1[0],
+ &bad_sha1_b[0]
+ };
+ ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
+}
+
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
+ mangle_file(old_file);
+ char* argv[2] = {
+ &bad_sha1_a[0],
+ &bad_sha1_b[0]
+ };
+ ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
+}
+
+TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
+ unlink(&old_file[0]);
+ char* s = &old_sha1[0];
+ ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
+}
+
+TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
+ unlink(&old_file[0]);
+ char* argv[3] = {
+ &bad_sha1_a[0],
+ &old_sha1[0],
+ &bad_sha1_b[0]
+ };
+ ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
+}
+
+TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
+ unlink(&old_file[0]);
+ char* argv[2] = {
+ &bad_sha1_a[0],
+ &bad_sha1_b[0]
+ };
+ ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
+}
+
+TEST_F(ApplyPatchFullTest, ApplyInPlace) {
+ std::vector<char*> sha1s;
+ sha1s.push_back(&bad_sha1_a[0]);
+ sha1s.push_back(&old_sha1[0]);
+
+ int ap_result = applypatch(&old_file[0],
+ "-",
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_EQ(0, ap_result);
+ ASSERT_TRUE(file_cmp(old_file, new_file));
+ // reapply, applypatch is idempotent so it should succeed
+ ap_result = applypatch(&old_file[0],
+ "-",
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_EQ(0, ap_result);
+ ASSERT_TRUE(file_cmp(old_file, new_file));
+}
+
+TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
+ std::vector<char*> sha1s;
+ sha1s.push_back(&bad_sha1_a[0]);
+ sha1s.push_back(&old_sha1[0]);
+ int ap_result = applypatch(&old_file[0],
+ &output_loc[0],
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_EQ(0, ap_result);
+ ASSERT_TRUE(file_cmp(output_loc, new_file));
+ ap_result = applypatch(&old_file[0],
+ &output_loc[0],
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_EQ(0, ap_result);
+ ASSERT_TRUE(file_cmp(output_loc, new_file));
+}
+
+TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
+ mangle_file(old_file);
+ std::vector<char*> sha1s;
+ sha1s.push_back(&bad_sha1_a[0]);
+ sha1s.push_back(&old_sha1[0]);
+ int ap_result = applypatch(&old_file[0],
+ &output_loc[0],
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_EQ(0, ap_result);
+ ASSERT_TRUE(file_cmp(output_loc, new_file));
+ ap_result = applypatch(&old_file[0],
+ &output_loc[0],
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_EQ(0, ap_result);
+ ASSERT_TRUE(file_cmp(output_loc, new_file));
+}
+
+TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
+ mangle_file(old_file);
+ mangle_file(cache_file);
+
+ std::vector<char*> sha1s;
+ sha1s.push_back(&bad_sha1_a[0]);
+ sha1s.push_back(&old_sha1[0]);
+ int ap_result = applypatch(&old_file[0],
+ &output_loc[0],
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_NE(0, ap_result);
+ ASSERT_FALSE(file_cmp(output_loc, new_file));
+ ap_result = applypatch(&old_file[0],
+ &output_loc[0],
+ &new_sha1[0],
+ new_size,
+ 2,
+ sha1s.data(),
+ patches.data(),
+ nullptr);
+ ASSERT_NE(0, ap_result);
+ ASSERT_FALSE(file_cmp(output_loc, new_file));
+}
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
new file mode 100644
index 000000000..780ff2816
--- /dev/null
+++ b/tests/component/verifier_test.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2009 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 agree 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <openssl/sha.h>
+
+#include <android-base/stringprintf.h>
+
+#include "common.h"
+#include "common/test_constants.h"
+#include "minzip/SysUtil.h"
+#include "ui.h"
+#include "verifier.h"
+
+static const char* DATA_PATH = getenv("ANDROID_DATA");
+static const char* TESTDATA_PATH = "/recovery/testdata/";
+
+RecoveryUI* ui = NULL;
+
+class MockUI : public RecoveryUI {
+ void Init() { }
+ void SetStage(int, int) { }
+ void SetLocale(const char*) { }
+ void SetBackground(Icon icon) { }
+ void SetSystemUpdateText(bool security_update) { }
+
+ void SetProgressType(ProgressType determinate) { }
+ void ShowProgress(float portion, float seconds) { }
+ void SetProgress(float fraction) { }
+
+ void ShowText(bool visible) { }
+ bool IsTextVisible() { return false; }
+ bool WasTextEverVisible() { return false; }
+ void Print(const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ void PrintOnScreenOnly(const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ void ShowFile(const char*) { }
+
+ void StartMenu(const char* const * headers, const char* const * items,
+ int initial_selection) { }
+ int SelectMenu(int sel) { return 0; }
+ void EndMenu() { }
+};
+
+void
+ui_print(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+}
+
+class VerifierTest : public testing::TestWithParam<std::vector<std::string>> {
+ public:
+ MemMapping memmap;
+ std::vector<Certificate> certs;
+
+ virtual void SetUp() {
+ std::vector<std::string> args = GetParam();
+ std::string package =
+ android::base::StringPrintf("%s%s%s%s", DATA_PATH, NATIVE_TEST_PATH,
+ TESTDATA_PATH, args[0].c_str());
+ if (sysMapFile(package.c_str(), &memmap) != 0) {
+ FAIL() << "Failed to mmap " << package << ": " << strerror(errno)
+ << "\n";
+ }
+
+ for (auto it = ++(args.cbegin()); it != args.cend(); ++it) {
+ if (it->substr(it->length() - 3, it->length()) == "256") {
+ if (certs.empty()) {
+ FAIL() << "May only specify -sha256 after key type\n";
+ }
+ certs.back().hash_len = SHA256_DIGEST_LENGTH;
+ } else {
+ std::string public_key_file = android::base::StringPrintf(
+ "%s%s%stest_key_%s.txt", DATA_PATH, NATIVE_TEST_PATH,
+ TESTDATA_PATH, it->c_str());
+ ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
+ certs.back().hash_len = SHA_DIGEST_LENGTH;
+ }
+ }
+ if (certs.empty()) {
+ std::string public_key_file = android::base::StringPrintf(
+ "%s%s%stest_key_e3.txt", DATA_PATH, NATIVE_TEST_PATH,
+ TESTDATA_PATH);
+ ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
+ certs.back().hash_len = SHA_DIGEST_LENGTH;
+ }
+ }
+
+ static void SetUpTestCase() {
+ ui = new MockUI();
+ }
+};
+
+class VerifierSuccessTest : public VerifierTest {
+};
+
+class VerifierFailureTest : public VerifierTest {
+};
+
+TEST_P(VerifierSuccessTest, VerifySucceed) {
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS);
+}
+
+TEST_P(VerifierFailureTest, VerifyFailure) {
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE);
+}
+
+INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "e3"}),
+ std::vector<std::string>({"otasigned_f4.zip", "f4"}),
+ std::vector<std::string>({"otasigned_sha256.zip", "e3", "sha256"}),
+ std::vector<std::string>({"otasigned_f4_sha256.zip", "f4", "sha256"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "ec", "sha256"})));
+
+INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "f4", "e3"}),
+ std::vector<std::string>({"otasigned_f4.zip", "ec", "f4"}),
+ std::vector<std::string>({"otasigned_sha256.zip", "ec", "e3", "e3", "sha256"}),
+ std::vector<std::string>({"otasigned_f4_sha256.zip", "ec", "sha256", "e3", "f4", "sha256"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "f4", "sha256", "e3", "ec", "sha256"})));
+
+INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "f4"}),
+ std::vector<std::string>({"otasigned_f4.zip", "e3"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "e3", "sha256"})));
+
+INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest,
+ ::testing::Values(
+ std::vector<std::string>({"otasigned.zip", "e3", "sha256"}),
+ std::vector<std::string>({"otasigned_f4.zip", "f4", "sha256"}),
+ std::vector<std::string>({"otasigned_sha256.zip"}),
+ std::vector<std::string>({"otasigned_f4_sha256.zip", "f4"}),
+ std::vector<std::string>({"otasigned_ecdsa_sha256.zip"})));
+
+INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest,
+ ::testing::Values(
+ std::vector<std::string>({"random.zip"}),
+ std::vector<std::string>({"fake-eocd.zip"}),
+ std::vector<std::string>({"alter-metadata.zip"}),
+ std::vector<std::string>({"alter-footer.zip"})));
diff --git a/testdata/alter-footer.zip b/tests/testdata/alter-footer.zip
index f497ec000..f497ec000 100644
--- a/testdata/alter-footer.zip
+++ b/tests/testdata/alter-footer.zip
Binary files differ
diff --git a/testdata/alter-metadata.zip b/tests/testdata/alter-metadata.zip
index 1c71fbc49..1c71fbc49 100644
--- a/testdata/alter-metadata.zip
+++ b/tests/testdata/alter-metadata.zip
Binary files differ
diff --git a/testdata/fake-eocd.zip b/tests/testdata/fake-eocd.zip
index 15dc0a946..15dc0a946 100644
--- a/testdata/fake-eocd.zip
+++ b/tests/testdata/fake-eocd.zip
Binary files differ
diff --git a/testdata/jarsigned.zip b/tests/testdata/jarsigned.zip
index 8b1ef8bdd..8b1ef8bdd 100644
--- a/testdata/jarsigned.zip
+++ b/tests/testdata/jarsigned.zip
Binary files differ
diff --git a/tests/testdata/new.file b/tests/testdata/new.file
new file mode 100644
index 000000000..cdeb8fd50
--- /dev/null
+++ b/tests/testdata/new.file
Binary files differ
diff --git a/tests/testdata/old.file b/tests/testdata/old.file
new file mode 100644
index 000000000..166c8732e
--- /dev/null
+++ b/tests/testdata/old.file
Binary files differ
diff --git a/testdata/otasigned.zip b/tests/testdata/otasigned.zip
index a6bc53e41..a6bc53e41 100644
--- a/testdata/otasigned.zip
+++ b/tests/testdata/otasigned.zip
Binary files differ
diff --git a/testdata/otasigned_ecdsa_sha256.zip b/tests/testdata/otasigned_ecdsa_sha256.zip
index 999fcdd0f..999fcdd0f 100644
--- a/testdata/otasigned_ecdsa_sha256.zip
+++ b/tests/testdata/otasigned_ecdsa_sha256.zip
Binary files differ
diff --git a/testdata/otasigned_f4.zip b/tests/testdata/otasigned_f4.zip
index dd1e4dd40..dd1e4dd40 100644
--- a/testdata/otasigned_f4.zip
+++ b/tests/testdata/otasigned_f4.zip
Binary files differ
diff --git a/testdata/otasigned_f4_sha256.zip b/tests/testdata/otasigned_f4_sha256.zip
index 3af408c40..3af408c40 100644
--- a/testdata/otasigned_f4_sha256.zip
+++ b/tests/testdata/otasigned_f4_sha256.zip
Binary files differ
diff --git a/testdata/otasigned_sha256.zip b/tests/testdata/otasigned_sha256.zip
index 0ed4409b3..0ed4409b3 100644
--- a/testdata/otasigned_sha256.zip
+++ b/tests/testdata/otasigned_sha256.zip
Binary files differ
diff --git a/tests/testdata/patch.bsdiff b/tests/testdata/patch.bsdiff
new file mode 100644
index 000000000..b78d38573
--- /dev/null
+++ b/tests/testdata/patch.bsdiff
Binary files differ
diff --git a/testdata/random.zip b/tests/testdata/random.zip
index 18c0b3b9f..18c0b3b9f 100644
--- a/testdata/random.zip
+++ b/tests/testdata/random.zip
Binary files differ
diff --git a/testdata/test_f4.pk8 b/tests/testdata/test_f4.pk8
index 3052613c5..3052613c5 100644
--- a/testdata/test_f4.pk8
+++ b/tests/testdata/test_f4.pk8
Binary files differ
diff --git a/testdata/test_f4.x509.pem b/tests/testdata/test_f4.x509.pem
index 814abcf99..814abcf99 100644
--- a/testdata/test_f4.x509.pem
+++ b/tests/testdata/test_f4.x509.pem
diff --git a/testdata/test_f4_sha256.x509.pem b/tests/testdata/test_f4_sha256.x509.pem
index 9d5376b45..9d5376b45 100644
--- a/testdata/test_f4_sha256.x509.pem
+++ b/tests/testdata/test_f4_sha256.x509.pem
diff --git a/tests/testdata/test_key_e3.txt b/tests/testdata/test_key_e3.txt
new file mode 100644
index 000000000..53f5297bd
--- /dev/null
+++ b/tests/testdata/test_key_e3.txt
@@ -0,0 +1 @@
+{64,0xc926ad21,{1795090719,2141396315,950055447,2581568430,4268923165,1920809988,546586521,3498997798,1776797858,3740060814,1805317999,1429410244,129622599,1422441418,1783893377,1222374759,2563319927,323993566,28517732,609753416,1826472888,215237850,4261642700,4049082591,3228462402,774857746,154822455,2497198897,2758199418,3019015328,2794777644,87251430,2534927978,120774784,571297800,3695899472,2479925187,3811625450,3401832990,2394869647,3267246207,950095497,555058928,414729973,1136544882,3044590084,465547824,4058146728,2731796054,1689838846,3890756939,1048029507,895090649,247140249,178744550,3547885223,3165179243,109881576,3944604415,1044303212,3772373029,2985150306,3737520932,3599964420},{3437017481,3784475129,2800224972,3086222688,251333580,2131931323,512774938,325948880,2657486437,2102694287,3820568226,792812816,1026422502,2053275343,2800889200,3113586810,165549746,4273519969,4065247892,1902789247,772932719,3941848426,3652744109,216871947,3164400649,1942378755,3996765851,1055777370,964047799,629391717,2232744317,3910558992,191868569,2758883837,3682816752,2997714732,2702529250,3570700455,3776873832,3924067546,3555689545,2758825434,1323144535,61311905,1997411085,376844204,213777604,4077323584,9135381,1625809335,2804742137,2952293945,1117190829,4237312782,1825108855,3013147971,1111251351,2568837572,1684324211,2520978805,367251975,810756730,2353784344,1175080310}}
diff --git a/tests/testdata/test_key_ec.txt b/tests/testdata/test_key_ec.txt
new file mode 100644
index 000000000..72b4395d9
--- /dev/null
+++ b/tests/testdata/test_key_ec.txt
@@ -0,0 +1 @@
+v5 {32,{36,250,86,214,202,22,20,147,198,120,2,28,76,190,78,23,106,35,24,96,86,22,186,69,132,93,192,232,0,213,14,103},{222,154,23,13,125,130,22,76,146,185,140,159,138,255,105,143,32,16,27,72,175,145,141,121,233,184,77,24,217,141,132,181}}
diff --git a/tests/testdata/test_key_f4.txt b/tests/testdata/test_key_f4.txt
new file mode 100644
index 000000000..54ddbbad1
--- /dev/null
+++ b/tests/testdata/test_key_f4.txt
@@ -0,0 +1 @@
+v2 {64,0xc9bd1f21,{293133087,3210546773,865313125,250921607,3158780490,943703457,1242806226,2986289859,2942743769,2457906415,2719374299,1783459420,149579627,3081531591,3440738617,2788543742,2758457512,1146764939,3699497403,2446203424,1744968926,1159130537,2370028300,3978231572,3392699980,1487782451,1180150567,2841334302,3753960204,961373345,3333628321,748825784,2978557276,1566596926,1613056060,2600292737,1847226629,50398611,1890374404,2878700735,2286201787,1401186359,619285059,731930817,2340993166,1156490245,2992241729,151498140,318782170,3480838990,2100383433,4223552555,3628927011,4247846280,1759029513,4215632601,2719154626,3490334597,1751299340,3487864726,3668753795,4217506054,3748782284,3150295088},{1772626313,445326068,3477676155,1758201194,2986784722,491035581,3922936562,702212696,2979856666,3324974564,2488428922,3056318590,1626954946,664714029,398585816,3964097931,3356701905,2298377729,2040082097,3025491477,539143308,3348777868,2995302452,3602465520,212480763,2691021393,1307177300,704008044,2031136606,1054106474,3838318865,2441343869,1477566916,700949900,2534790355,3353533667,336163563,4106790558,2701448228,1571536379,1103842411,3623110423,1635278839,1577828979,910322800,715583630,138128831,1017877531,2289162787,447994798,1897243165,4121561445,4150719842,2131821093,2262395396,3305771534,980753571,3256525190,3128121808,1072869975,3507939515,4229109952,118381341,2209831334}}
diff --git a/testdata/testkey.pk8 b/tests/testdata/testkey.pk8
index 586c1bd5c..586c1bd5c 100644
--- a/testdata/testkey.pk8
+++ b/tests/testdata/testkey.pk8
Binary files differ
diff --git a/testdata/testkey.x509.pem b/tests/testdata/testkey.x509.pem
index e242d83e2..e242d83e2 100644
--- a/testdata/testkey.x509.pem
+++ b/tests/testdata/testkey.x509.pem
diff --git a/testdata/testkey_ecdsa.pk8 b/tests/testdata/testkey_ecdsa.pk8
index 9a521c8cf..9a521c8cf 100644
--- a/testdata/testkey_ecdsa.pk8
+++ b/tests/testdata/testkey_ecdsa.pk8
Binary files differ
diff --git a/testdata/testkey_ecdsa.x509.pem b/tests/testdata/testkey_ecdsa.x509.pem
index b12283645..b12283645 100644
--- a/testdata/testkey_ecdsa.x509.pem
+++ b/tests/testdata/testkey_ecdsa.x509.pem
diff --git a/testdata/testkey_sha256.x509.pem b/tests/testdata/testkey_sha256.x509.pem
index 002ce8968..002ce8968 100644
--- a/testdata/testkey_sha256.x509.pem
+++ b/tests/testdata/testkey_sha256.x509.pem
diff --git a/testdata/unsigned.zip b/tests/testdata/unsigned.zip
index 24e3eadac..24e3eadac 100644
--- a/testdata/unsigned.zip
+++ b/tests/testdata/unsigned.zip
Binary files differ
diff --git a/tests/asn1_decoder_test.cpp b/tests/unit/asn1_decoder_test.cpp
index af96d87d2..af96d87d2 100644
--- a/tests/asn1_decoder_test.cpp
+++ b/tests/unit/asn1_decoder_test.cpp
diff --git a/tests/unit/locale_test.cpp b/tests/unit/locale_test.cpp
new file mode 100644
index 000000000..0e515f8c1
--- /dev/null
+++ b/tests/unit/locale_test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "minui/minui.h"
+
+TEST(LocaleTest, Misc) {
+ EXPECT_TRUE(matches_locale("zh_CN", "zh_CN_#Hans"));
+ EXPECT_TRUE(matches_locale("zh", "zh_CN_#Hans"));
+ EXPECT_FALSE(matches_locale("zh_HK", "zh_CN_#Hans"));
+ EXPECT_TRUE(matches_locale("en_GB", "en_GB"));
+ EXPECT_TRUE(matches_locale("en", "en_GB"));
+ EXPECT_FALSE(matches_locale("en_GB", "en"));
+ EXPECT_FALSE(matches_locale("en_GB", "en_US"));
+}
diff --git a/tests/unit/recovery_test.cpp b/tests/unit/recovery_test.cpp
new file mode 100644
index 000000000..f397f258e
--- /dev/null
+++ b/tests/unit/recovery_test.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <log/logger.h>
+#include <private/android_logger.h>
+
+static const char myFilename[] = "/data/misc/recovery/inject.txt";
+static const char myContent[] = "Hello World\nWelcome to my recovery\n";
+
+// Failure is expected on systems that do not deliver either the
+// recovery-persist or recovery-refresh executables. Tests also require
+// a reboot sequence of test to truly verify.
+
+static ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
+ const char *buf, size_t len, void *arg) {
+ EXPECT_EQ(LOG_ID_SYSTEM, logId);
+ EXPECT_EQ(ANDROID_LOG_INFO, prio);
+ EXPECT_EQ(0, NULL == strstr(myFilename,filename));
+ EXPECT_EQ(0, strcmp(myContent, buf));
+ EXPECT_EQ(sizeof(myContent), len);
+ EXPECT_EQ(0, NULL != arg);
+ return len;
+}
+
+// recovery.refresh - May fail. Requires recovery.inject, two reboots,
+// then expect success after second reboot.
+TEST(recovery, refresh) {
+ EXPECT_EQ(0, access("/system/bin/recovery-refresh", F_OK));
+
+ ssize_t ret = __android_log_pmsg_file_read(
+ LOG_ID_SYSTEM, ANDROID_LOG_INFO, "recovery/", __pmsg_fn, NULL);
+ if (ret == -ENOENT) {
+ EXPECT_LT(0, __android_log_pmsg_file_write(
+ LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+ myFilename, myContent, sizeof(myContent)));
+ fprintf(stderr, "injected test data, "
+ "requires two intervening reboots "
+ "to check for replication\n");
+ }
+ EXPECT_EQ((ssize_t)sizeof(myContent), ret);
+}
+
+// recovery.persist - Requires recovery.inject, then a reboot, then
+// expect success after for this test on that boot.
+TEST(recovery, persist) {
+ EXPECT_EQ(0, access("/system/bin/recovery-persist", F_OK));
+
+ ssize_t ret = __android_log_pmsg_file_read(
+ LOG_ID_SYSTEM, ANDROID_LOG_INFO, "recovery/", __pmsg_fn, NULL);
+ if (ret == -ENOENT) {
+ EXPECT_LT(0, __android_log_pmsg_file_write(
+ LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+ myFilename, myContent, sizeof(myContent)));
+ fprintf(stderr, "injected test data, "
+ "requires intervening reboot "
+ "to check for storage\n");
+ }
+
+ int fd = open(myFilename, O_RDONLY);
+ EXPECT_LE(0, fd);
+
+ char buf[sizeof(myContent) + 32];
+ ret = read(fd, buf, sizeof(buf));
+ close(fd);
+ EXPECT_EQ(ret, (ssize_t)sizeof(myContent));
+ EXPECT_EQ(0, strcmp(myContent, buf));
+ if (fd >= 0) {
+ fprintf(stderr, "Removing persistent test data, "
+ "check if reconstructed on reboot\n");
+ }
+ EXPECT_EQ(0, unlink(myFilename));
+}