From e1a16af3ea497c8b4df62cec99bf36bde28df409 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 4 Feb 2016 11:30:42 -0800 Subject: verifier_test: Suppress the unused parameter warnings. Change-Id: I51fec30114c0a31efc9c2ac8472654baf8bb3e84 --- tests/component/verifier_test.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 7f7b1b448..71fa028ca 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -138,13 +138,13 @@ class MockUI : public RecoveryUI { void Init() { } void SetStage(int, int) { } void SetLocale(const char*) { } - void SetBackground(Icon icon) { } + void SetBackground(Icon /*icon*/) { } - void SetProgressType(ProgressType determinate) { } - void ShowProgress(float portion, float seconds) { } - void SetProgress(float fraction) { } + void SetProgressType(ProgressType /*determinate*/) { } + void ShowProgress(float /*portion*/, float /*seconds*/) { } + void SetProgress(float /*fraction*/) { } - void ShowText(bool visible) { } + void ShowText(bool /*visible*/) { } bool IsTextVisible() { return false; } bool WasTextEverVisible() { return false; } void Print(const char* fmt, ...) { @@ -161,9 +161,10 @@ class MockUI : public RecoveryUI { } void ShowFile(const char*) { } - void StartMenu(const char* const * headers, const char* const * items, - int initial_selection) { } - int SelectMenu(int sel) { return 0; } + void StartMenu(const char* const* /*headers*/, + const char* const* /*items*/, + int /*initial_selection*/) { } + int SelectMenu(int /*sel*/) { return 0; } void EndMenu() { } }; -- cgit v1.2.3 From d5a14c6a492d8609b2ce9c621fa9fe489fc45cdc Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Fri, 5 Feb 2016 11:24:27 -0800 Subject: Change on-device directory for recovery test data Test data needs to go outside the gtest module. Change-Id: Ic444ca838cbafa651ec97ff8730129da84fafc09 --- tests/Android.mk | 2 +- tests/component/verifier_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 3f3c433eb..262fb8bfd 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -43,7 +43,7 @@ LOCAL_STATIC_LIBRARIES := \ libcutils \ libc -testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery testdata_files := $(call find-subdir-files, testdata/*) GEN := $(addprefix $(testdata_out_path)/, $(testdata_files)) diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 7f7b1b448..c54aa111f 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -42,7 +42,7 @@ #endif static const char* DATA_PATH = getenv("ANDROID_DATA"); -static const char* TESTDATA_PATH = "/recovery_component_test/testdata/"; +static const char* TESTDATA_PATH = "/recovery/testdata/"; // This is build/target/product/security/testkey.x509.pem after being // dumped out by dumpkey.jar. -- cgit v1.2.3 From a4f701af93a5a739f34823cde0c493dfbc63537a Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 9 Mar 2016 14:58:16 -0800 Subject: recovery: use __android_log_pmsg_file_write for log files - Add call to __android_log_pmsg_file_write for recovery logging. - Add call to refresh pmsg if we reboot back into recovery and then allow overwrite of those logs. - Add a new one-time executable recovery-refresh that refreshes pmsg in post-fs phase of init. We rely on pmsg eventually scrolling off to age the content after recovery-persist has done its job. - Add a new one-time executable recovery-persist that transfers from pmsg to /data/misc/recovery/ directory if /cache is not mounted in post-fs-data phase of init. - Build and appropriately trigger the above two as required if BOARD_CACHEIMAGE_PARTITION_SIZE is undefined. - Add some simple unit tests NB: Test failure is expected on systems that do not deliver either the recovery-persist or recovery-refresh executables, e.g. systems with /cache. Tests also require a timely reboot sequence of test to truly verify, tests provide guidance on stderr to direct. Bug: 27176738 Change-Id: I17bb95980234984f6b2087fd5941b0a3126b706b --- tests/Android.mk | 2 + tests/unit/recovery_test.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 tests/unit/recovery_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 262fb8bfd..8f55fc0df 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -23,7 +23,9 @@ LOCAL_MODULE := recovery_unit_test LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_STATIC_LIBRARIES := libverifier LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp +LOCAL_SRC_FILES += unit/recovery_test.cpp LOCAL_C_INCLUDES := bootable/recovery +LOCAL_SHARED_LIBRARIES := liblog include $(BUILD_NATIVE_TEST) # Component tests 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 +#include +#include +#include + +#include +#include +#include +#include + +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)); +} -- cgit v1.2.3 From 452df6d99c81c4eeee3d2c7b2171901e8b7bc54a Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Mon, 4 Apr 2016 16:17:01 +0200 Subject: Convert recovery to use BoringSSL instead of mincrypt. This changes the verification code in bootable/recovery to use BoringSSL instead of mincrypt. Change-Id: I37b37d84b22e81c32ac180cd1240c02150ddf3a7 --- tests/Android.mk | 3 +- tests/component/verifier_test.cpp | 131 +++++++------------------------------- tests/testdata/test_key_e3.txt | 1 + tests/testdata/test_key_ec.txt | 1 + tests/testdata/test_key_f4.txt | 1 + 5 files changed, 28 insertions(+), 109 deletions(-) create mode 100644 tests/testdata/test_key_e3.txt create mode 100644 tests/testdata/test_key_ec.txt create mode 100644 tests/testdata/test_key_f4.txt (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 8f55fc0df..7b004b2a0 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -39,7 +39,8 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_STATIC_LIBRARIES := \ libbase \ libverifier \ - libmincrypt \ + libcrypto_utils_static \ + libcrypto_static \ libminui \ libminzip \ libcutils \ diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index d6f1e0bb9..b5d70327e 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -19,18 +19,18 @@ #include #include #include -#include #include +#include #include #include #include +#include + #include #include "common.h" -#include "mincrypt/sha.h" -#include "mincrypt/sha256.h" #include "minzip/SysUtil.h" #include "ui.h" #include "verifier.h" @@ -44,94 +44,6 @@ static const char* DATA_PATH = getenv("ANDROID_DATA"); static const char* TESTDATA_PATH = "/recovery/testdata/"; -// This is build/target/product/security/testkey.x509.pem after being -// dumped out by dumpkey.jar. -RSAPublicKey test_key = - { 64, 0xc926ad21, - { 0x6afee91fu, 0x7fa31d5bu, 0x38a0b217u, 0x99df9baeu, - 0xfe72991du, 0x727d3c04u, 0x20943f99u, 0xd08e7826u, - 0x69e7c8a2u, 0xdeeccc8eu, 0x6b9af76fu, 0x553311c4u, - 0x07b9e247u, 0x54c8bbcau, 0x6a540d81u, 0x48dbf567u, - 0x98c92877u, 0x134fbfdeu, 0x01b32564u, 0x24581948u, - 0x6cddc3b8u, 0x0cd444dau, 0xfe0381ccu, 0xf15818dfu, - 0xc06e6d42u, 0x2e2f6412u, 0x093a6737u, 0x94d83b31u, - 0xa466c87au, 0xb3f284a0u, 0xa694ec2cu, 0x053359e6u, - 0x9717ee6au, 0x0732e080u, 0x220d5008u, 0xdc4af350u, - 0x93d0a7c3u, 0xe330c9eau, 0xcac3da1eu, 0x8ebecf8fu, - 0xc2be387fu, 0x38a14e89u, 0x211586f0u, 0x18b846f5u, - 0x43be4c72u, 0xb578c204u, 0x1bbfb230u, 0xf1e267a8u, - 0xa2d3e656u, 0x64b8e4feu, 0xe7e83d4bu, 0x3e77a943u, - 0x3559ffd9u, 0x0ebb0f99u, 0x0aa76ce6u, 0xd3786ea7u, - 0xbca8cd6bu, 0x068ca8e8u, 0xeb1de2ffu, 0x3e3ecd6cu, - 0xe0d9d825u, 0xb1edc762u, 0xdec60b24u, 0xd6931904u}, - { 0xccdcb989u, 0xe19281f9u, 0xa6e80accu, 0xb7f40560u, - 0x0efb0bccu, 0x7f12b0bbu, 0x1e90531au, 0x136d95d0u, - 0x9e660665u, 0x7d54918fu, 0xe3b93ea2u, 0x2f415d10u, - 0x3d2df6e6u, 0x7a627ecfu, 0xa6f22d70u, 0xb995907au, - 0x09de16b2u, 0xfeb8bd61u, 0xf24ec294u, 0x716a427fu, - 0x2e12046fu, 0xeaf3d56au, 0xd9b873adu, 0x0ced340bu, - 0xbc9cec09u, 0x73c65903u, 0xee39ce9bu, 0x3eede25au, - 0x397633b7u, 0x2583c165u, 0x8514f97du, 0xe9166510u, - 0x0b6fae99u, 0xa47139fdu, 0xdb8352f0u, 0xb2ad7f2cu, - 0xa11552e2u, 0xd4d490a7u, 0xe11e8568u, 0xe9e484dau, - 0xd3ef8449u, 0xa47055dau, 0x4edd9557u, 0x03a78ba1u, - 0x770e130du, 0x16762facu, 0x0cbdfcc4u, 0xf3070540u, - 0x008b6515u, 0x60e7e1b7u, 0xa72cf7f9u, 0xaff86e39u, - 0x4296faadu, 0xfc90430eu, 0x6cc8f377u, 0xb398fd43u, - 0x423c5997u, 0x991d59c4u, 0x6464bf73u, 0x96431575u, - 0x15e3d207u, 0x30532a7au, 0x8c4be618u, 0x460a4d76u }, - 3 - }; - -RSAPublicKey test_f4_key = - { 64, 0xc9bd1f21, - { 0x1178db1fu, 0xbf5d0e55u, 0x3393a165u, 0x0ef4c287u, - 0xbc472a4au, 0x383fc5a1u, 0x4a13b7d2u, 0xb1ff2ac3u, - 0xaf66b4d9u, 0x9280acefu, 0xa2165bdbu, 0x6a4d6e5cu, - 0x08ea676bu, 0xb7ac70c7u, 0xcd158139u, 0xa635ccfeu, - 0xa46ab8a8u, 0x445a3e8bu, 0xdc81d9bbu, 0x91ce1a20u, - 0x68021cdeu, 0x4516eda9u, 0x8d43c30cu, 0xed1eff14u, - 0xca387e4cu, 0x58adc233u, 0x4657ab27u, 0xa95b521eu, - 0xdfc0e30cu, 0x394d64a1u, 0xc6b321a1u, 0x2ca22cb8u, - 0xb1892d5cu, 0x5d605f3eu, 0x6025483cu, 0x9afd5181u, - 0x6e1a7105u, 0x03010593u, 0x70acd304u, 0xab957cbfu, - 0x8844abbbu, 0x53846837u, 0x24e98a43u, 0x2ba060c1u, - 0x8b88b88eu, 0x44eea405u, 0xb259fc41u, 0x0907ad9cu, - 0x13003adau, 0xcf79634eu, 0x7d314ec9u, 0xfbbe4c2bu, - 0xd84d0823u, 0xfd30fd88u, 0x68d8a909u, 0xfb4572d9u, - 0xa21301c2u, 0xd00a4785u, 0x6862b50cu, 0xcfe49796u, - 0xdaacbd83u, 0xfb620906u, 0xdf71e0ccu, 0xbbc5b030u }, - { 0x69a82189u, 0x1a8b22f4u, 0xcf49207bu, 0x68cc056au, - 0xb206b7d2u, 0x1d449bbdu, 0xe9d342f2u, 0x29daea58u, - 0xb19d011au, 0xc62f15e4u, 0x9452697au, 0xb62bb87eu, - 0x60f95cc2u, 0x279ebb2du, 0x17c1efd8u, 0xec47558bu, - 0xc81334d1u, 0x88fe7601u, 0x79992eb1u, 0xb4555615u, - 0x2022ac8cu, 0xc79a4b8cu, 0xb288b034u, 0xd6b942f0u, - 0x0caa32fbu, 0xa065ba51u, 0x4de9f154u, 0x29f64f6cu, - 0x7910af5eu, 0x3ed4636au, 0xe4c81911u, 0x9183f37du, - 0x5811e1c4u, 0x29c7a58cu, 0x9715d4d3u, 0xc7e2dce3u, - 0x140972ebu, 0xf4c8a69eu, 0xa104d424u, 0x5dabbdfbu, - 0x41cb4c6bu, 0xd7f44717u, 0x61785ff7u, 0x5e0bc273u, - 0x36426c70u, 0x2aa6f08eu, 0x083badbfu, 0x3cab941bu, - 0x8871da23u, 0x1ab3dbaeu, 0x7115a21du, 0xf5aa0965u, - 0xf766f562u, 0x7f110225u, 0x86d96a04u, 0xc50a120eu, - 0x3a751ca3u, 0xc21aa186u, 0xba7359d0u, 0x3ff2b257u, - 0xd116e8bbu, 0xfc1318c0u, 0x070e5b1du, 0x83b759a6u }, - 65537 - }; - -ECPublicKey test_ec_key = - { - { - {0xd656fa24u, 0x931416cau, 0x1c0278c6u, 0x174ebe4cu, - 0x6018236au, 0x45ba1656u, 0xe8c05d84u, 0x670ed500u} - }, - { - {0x0d179adeu, 0x4c16827du, 0x9f8cb992u, 0x8f69ff8au, - 0x481b1020u, 0x798d91afu, 0x184db8e9u, 0xb5848dd9u} - } - }; - RecoveryUI* ui = NULL; class MockUI : public RecoveryUI { @@ -183,31 +95,34 @@ class VerifierTest : public testing::TestWithParam> { virtual void SetUp() { std::vector args = GetParam(); - std::string package = android::base::StringPrintf("%s%s%s%s", DATA_PATH, NATIVE_TEST_PATH, - TESTDATA_PATH, args[0].c_str()); + 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_SIZE; - } else if (*it == "ec") { - certs.emplace_back(SHA_DIGEST_SIZE, Certificate::EC, - nullptr, std::unique_ptr(new ECPublicKey(test_ec_key))); - } else if (*it == "e3") { - certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, - std::unique_ptr(new RSAPublicKey(test_key)), nullptr); - } else if (*it == "f4") { - certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, - std::unique_ptr(new RSAPublicKey(test_f4_key)), nullptr); + 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()) { - certs.emplace_back(SHA_DIGEST_SIZE, Certificate::RSA, - std::unique_ptr(new RSAPublicKey(test_key)), nullptr); - } - if (sysMapFile(package.c_str(), &memmap) != 0) { - FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n"; + 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; } } 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}} -- cgit v1.2.3 From ab2fb94bf48483d761ba3aa85e0acf851895566f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 15 Jun 2016 21:15:43 -0700 Subject: tests: Remove obsolete MTD support. Track the change in commit 63a319201fc0f5c34c1c62b446527e06f57f8d40 and fix builds. Bug: http://b/29250988 Change-Id: Iad5be953e102020931649629afc980d585ed2931 --- tests/Android.mk | 1 - 1 file changed, 1 deletion(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 4509c420f..279a6cb49 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -46,7 +46,6 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_STATIC_LIBRARIES := \ libapplypatch \ libotafault \ - libmtdutils \ libbase \ libverifier \ libcrypto_utils_static \ -- cgit v1.2.3 From 5af4b1901dcc1b0654971415e3d8c12eb18b92fd Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 1 Aug 2016 11:31:43 -0700 Subject: Clean up verifier testcases. A Certificate is a pair of an RSAPublicKey and a particular hash. So v1 and v3 differ in the hash algorithm (SHA-1 vs SHA-256), similarly for v2 and v4. In verifier testcases, we used to load v1/v2 keys with an explicit argument of "sha256" to test the v3/v4 keys. This CL switches to loading v3/v4 keys directly and lets load_keys() to handle that, which is the actual flow we use in practice. Also remove the "fallback to v1 key" in the testcases, which is not the actual behavior. Bug: 30415901 Test: Run the verifier_test component test on device. Change-Id: I3a2baa64826f1b6c4c367a560090df384c4521bb --- tests/component/verifier_test.cpp | 67 ++++++++++++------------------ tests/testdata/otasigned.zip | Bin 4009 -> 0 bytes tests/testdata/otasigned_ecdsa_sha256.zip | Bin 3085 -> 0 bytes tests/testdata/otasigned_f4.zip | Bin 5195 -> 0 bytes tests/testdata/otasigned_f4_sha256.zip | Bin 5319 -> 0 bytes tests/testdata/otasigned_sha256.zip | Bin 5326 -> 0 bytes tests/testdata/otasigned_v1.zip | Bin 0 -> 4009 bytes tests/testdata/otasigned_v2.zip | Bin 0 -> 5195 bytes tests/testdata/otasigned_v3.zip | Bin 0 -> 5326 bytes tests/testdata/otasigned_v4.zip | Bin 0 -> 5319 bytes tests/testdata/otasigned_v5.zip | Bin 0 -> 3085 bytes tests/testdata/test_f4.pk8 | Bin 1217 -> 0 bytes tests/testdata/test_f4.x509.pem | 25 ----------- tests/testdata/test_f4_sha256.x509.pem | 25 ----------- tests/testdata/test_key_e3.txt | 1 - tests/testdata/test_key_ec.txt | 1 - tests/testdata/test_key_f4.txt | 1 - tests/testdata/testkey.pk8 | Bin 1217 -> 0 bytes tests/testdata/testkey.x509.pem | 27 ------------ tests/testdata/testkey_ecdsa.pk8 | Bin 138 -> 0 bytes tests/testdata/testkey_ecdsa.x509.pem | 10 ----- tests/testdata/testkey_sha256.x509.pem | 27 ------------ tests/testdata/testkey_v1.pk8 | Bin 0 -> 1217 bytes tests/testdata/testkey_v1.txt | 1 + tests/testdata/testkey_v1.x509.pem | 27 ++++++++++++ tests/testdata/testkey_v2.pk8 | Bin 0 -> 1217 bytes tests/testdata/testkey_v2.txt | 1 + tests/testdata/testkey_v2.x509.pem | 25 +++++++++++ tests/testdata/testkey_v3.pk8 | 1 + tests/testdata/testkey_v3.txt | 1 + tests/testdata/testkey_v3.x509.pem | 27 ++++++++++++ tests/testdata/testkey_v4.pk8 | 1 + tests/testdata/testkey_v4.txt | 1 + tests/testdata/testkey_v4.x509.pem | 25 +++++++++++ tests/testdata/testkey_v5.pk8 | Bin 0 -> 138 bytes tests/testdata/testkey_v5.txt | 1 + tests/testdata/testkey_v5.x509.pem | 10 +++++ 37 files changed, 147 insertions(+), 158 deletions(-) delete mode 100644 tests/testdata/otasigned.zip delete mode 100644 tests/testdata/otasigned_ecdsa_sha256.zip delete mode 100644 tests/testdata/otasigned_f4.zip delete mode 100644 tests/testdata/otasigned_f4_sha256.zip delete mode 100644 tests/testdata/otasigned_sha256.zip create mode 100644 tests/testdata/otasigned_v1.zip create mode 100644 tests/testdata/otasigned_v2.zip create mode 100644 tests/testdata/otasigned_v3.zip create mode 100644 tests/testdata/otasigned_v4.zip create mode 100644 tests/testdata/otasigned_v5.zip delete mode 100644 tests/testdata/test_f4.pk8 delete mode 100644 tests/testdata/test_f4.x509.pem delete mode 100644 tests/testdata/test_f4_sha256.x509.pem delete mode 100644 tests/testdata/test_key_e3.txt delete mode 100644 tests/testdata/test_key_ec.txt delete mode 100644 tests/testdata/test_key_f4.txt delete mode 100644 tests/testdata/testkey.pk8 delete mode 100644 tests/testdata/testkey.x509.pem delete mode 100644 tests/testdata/testkey_ecdsa.pk8 delete mode 100644 tests/testdata/testkey_ecdsa.x509.pem delete mode 100644 tests/testdata/testkey_sha256.x509.pem create mode 100644 tests/testdata/testkey_v1.pk8 create mode 100644 tests/testdata/testkey_v1.txt create mode 100644 tests/testdata/testkey_v1.x509.pem create mode 100644 tests/testdata/testkey_v2.pk8 create mode 100644 tests/testdata/testkey_v2.txt create mode 100644 tests/testdata/testkey_v2.x509.pem create mode 120000 tests/testdata/testkey_v3.pk8 create mode 100644 tests/testdata/testkey_v3.txt create mode 100644 tests/testdata/testkey_v3.x509.pem create mode 120000 tests/testdata/testkey_v4.pk8 create mode 100644 tests/testdata/testkey_v4.txt create mode 100644 tests/testdata/testkey_v4.x509.pem create mode 100644 tests/testdata/testkey_v5.pk8 create mode 100644 tests/testdata/testkey_v5.txt create mode 100644 tests/testdata/testkey_v5.x509.pem (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index b5d70327e..2a78173d8 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -99,30 +99,14 @@ class VerifierTest : public testing::TestWithParam> { 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"; + 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); + "%s%s%stestkey_%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; } } @@ -147,37 +131,38 @@ TEST_P(VerifierFailureTest, VerifyFailure) { INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest, ::testing::Values( - std::vector({"otasigned.zip", "e3"}), - std::vector({"otasigned_f4.zip", "f4"}), - std::vector({"otasigned_sha256.zip", "e3", "sha256"}), - std::vector({"otasigned_f4_sha256.zip", "f4", "sha256"}), - std::vector({"otasigned_ecdsa_sha256.zip", "ec", "sha256"}))); + std::vector({"otasigned_v1.zip", "v1"}), + std::vector({"otasigned_v2.zip", "v2"}), + std::vector({"otasigned_v3.zip", "v3"}), + std::vector({"otasigned_v4.zip", "v4"}), + std::vector({"otasigned_v5.zip", "v5"}))); INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest, ::testing::Values( - std::vector({"otasigned.zip", "f4", "e3"}), - std::vector({"otasigned_f4.zip", "ec", "f4"}), - std::vector({"otasigned_sha256.zip", "ec", "e3", "e3", "sha256"}), - std::vector({"otasigned_f4_sha256.zip", "ec", "sha256", "e3", "f4", "sha256"}), - std::vector({"otasigned_ecdsa_sha256.zip", "f4", "sha256", "e3", "ec", "sha256"}))); + std::vector({"otasigned_v1.zip", "v1", "v2"}), + std::vector({"otasigned_v2.zip", "v5", "v2"}), + std::vector({"otasigned_v3.zip", "v5", "v1", "v3"}), + std::vector({"otasigned_v4.zip", "v5", "v1", "v4"}), + std::vector({"otasigned_v5.zip", "v4", "v1", "v5"}))); INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest, ::testing::Values( - std::vector({"otasigned.zip", "f4"}), - std::vector({"otasigned_f4.zip", "e3"}), - std::vector({"otasigned_ecdsa_sha256.zip", "e3", "sha256"}))); + std::vector({"otasigned_v1.zip", "v2"}), + std::vector({"otasigned_v2.zip", "v1"}), + std::vector({"otasigned_v3.zip", "v5"}), + std::vector({"otasigned_v4.zip", "v5"}), + std::vector({"otasigned_v5.zip", "v3"}))); INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest, ::testing::Values( - std::vector({"otasigned.zip", "e3", "sha256"}), - std::vector({"otasigned_f4.zip", "f4", "sha256"}), - std::vector({"otasigned_sha256.zip"}), - std::vector({"otasigned_f4_sha256.zip", "f4"}), - std::vector({"otasigned_ecdsa_sha256.zip"}))); + std::vector({"otasigned_v1.zip", "v3"}), + std::vector({"otasigned_v2.zip", "v4"}), + std::vector({"otasigned_v3.zip", "v1"}), + std::vector({"otasigned_v4.zip", "v2"}))); INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest, ::testing::Values( - std::vector({"random.zip"}), - std::vector({"fake-eocd.zip"}), - std::vector({"alter-metadata.zip"}), - std::vector({"alter-footer.zip"}))); + std::vector({"random.zip", "v1"}), + std::vector({"fake-eocd.zip", "v1"}), + std::vector({"alter-metadata.zip", "v1"}), + std::vector({"alter-footer.zip", "v1"}))); diff --git a/tests/testdata/otasigned.zip b/tests/testdata/otasigned.zip deleted file mode 100644 index a6bc53e41..000000000 Binary files a/tests/testdata/otasigned.zip and /dev/null differ diff --git a/tests/testdata/otasigned_ecdsa_sha256.zip b/tests/testdata/otasigned_ecdsa_sha256.zip deleted file mode 100644 index 999fcdd0f..000000000 Binary files a/tests/testdata/otasigned_ecdsa_sha256.zip and /dev/null differ diff --git a/tests/testdata/otasigned_f4.zip b/tests/testdata/otasigned_f4.zip deleted file mode 100644 index dd1e4dd40..000000000 Binary files a/tests/testdata/otasigned_f4.zip and /dev/null differ diff --git a/tests/testdata/otasigned_f4_sha256.zip b/tests/testdata/otasigned_f4_sha256.zip deleted file mode 100644 index 3af408c40..000000000 Binary files a/tests/testdata/otasigned_f4_sha256.zip and /dev/null differ diff --git a/tests/testdata/otasigned_sha256.zip b/tests/testdata/otasigned_sha256.zip deleted file mode 100644 index 0ed4409b3..000000000 Binary files a/tests/testdata/otasigned_sha256.zip and /dev/null differ diff --git a/tests/testdata/otasigned_v1.zip b/tests/testdata/otasigned_v1.zip new file mode 100644 index 000000000..a6bc53e41 Binary files /dev/null and b/tests/testdata/otasigned_v1.zip differ diff --git a/tests/testdata/otasigned_v2.zip b/tests/testdata/otasigned_v2.zip new file mode 100644 index 000000000..dd1e4dd40 Binary files /dev/null and b/tests/testdata/otasigned_v2.zip differ diff --git a/tests/testdata/otasigned_v3.zip b/tests/testdata/otasigned_v3.zip new file mode 100644 index 000000000..0ed4409b3 Binary files /dev/null and b/tests/testdata/otasigned_v3.zip differ diff --git a/tests/testdata/otasigned_v4.zip b/tests/testdata/otasigned_v4.zip new file mode 100644 index 000000000..3af408c40 Binary files /dev/null and b/tests/testdata/otasigned_v4.zip differ diff --git a/tests/testdata/otasigned_v5.zip b/tests/testdata/otasigned_v5.zip new file mode 100644 index 000000000..999fcdd0f Binary files /dev/null and b/tests/testdata/otasigned_v5.zip differ diff --git a/tests/testdata/test_f4.pk8 b/tests/testdata/test_f4.pk8 deleted file mode 100644 index 3052613c5..000000000 Binary files a/tests/testdata/test_f4.pk8 and /dev/null differ diff --git a/tests/testdata/test_f4.x509.pem b/tests/testdata/test_f4.x509.pem deleted file mode 100644 index 814abcf99..000000000 --- a/tests/testdata/test_f4.x509.pem +++ /dev/null @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW -aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT -B1Rlc3QxMjMwHhcNMTIwNzI1MTg1NzAzWhcNMzkxMjExMTg1NzAzWjBvMQswCQYD -VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g -VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD -EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x -4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x -TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs -0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX -qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V -gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT -oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS -GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 -YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G -A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN -AQEFBQADggEBAHqnXHtE+h3hvGmHh24GT51vGAYLc68WUUtCVlMIU85zQ757wlxZ -BmRypZ1i9hSqnXj5n+mETV5rFX3g2gvdAPVHkRycuDa2aUdZSE8cW4Z6qYFx6SaD -e+3SyXokpUquW64RuHJrf/yd/FnGjneBe3Qpm2reuzGWNH90qZGdbsfNaCm5kx2L -X+ZNHM3CcGMLaphY5++sM0JxSEcju5EK33ZYgLf4YdlbyMp8LDFVNd7ff0SFi9fF -0ZlAsJWoS3QmVCj2744BFdsCu7UHpnYpG6X3MT4SHAawdOaT5zSuaCl2xx6H0O7t -w/Fvbl/KVD1ZmLHgBKjDMNSh0OB9mSsDWpw= ------END CERTIFICATE----- diff --git a/tests/testdata/test_f4_sha256.x509.pem b/tests/testdata/test_f4_sha256.x509.pem deleted file mode 100644 index 9d5376b45..000000000 --- a/tests/testdata/test_f4_sha256.x509.pem +++ /dev/null @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBCwUAMG8xCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW -aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT -B1Rlc3QxMjMwHhcNMTMwNDEwMTcyMzUyWhcNMTMwNTEwMTcyMzUyWjBvMQswCQYD -VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g -VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD -EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x -4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x -TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs -0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX -qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V -gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT -oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS -GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 -YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G -A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN -AQELBQADggEBAKWWQ9S0V9wWjrMJe8exj1gklwD1Ysi0vi+h2tfixahelrpsNkWi -EFjoUSHEkW9ThLmtui646uAlwSiWtSn1XkGGmIJ3s+gmAFUcMc0CaK0dgoq/M9zn -fQ0Vkzc1tK4MLsf+CbPDywPycb6+T3dBkerbWn9GUpjGl1ANWlciXZZ3657m61sL -HhwUOBxbZZ6sYP4ed2SVCf45GgMyJ0VoUg5yI2JzPAgOkGfeEIPVXE1M94edJY4G -8eHYvXovJZwXvKFI+ZyS0KBPx8cpfw89RB9qmkxqNBIm8qWb3qBiuBEIPj+NF/7w -sC/Fv8NNXkVquy0xa0qdyJBABzWE18zGcXs= ------END CERTIFICATE----- diff --git a/tests/testdata/test_key_e3.txt b/tests/testdata/test_key_e3.txt deleted file mode 100644 index 53f5297bd..000000000 --- a/tests/testdata/test_key_e3.txt +++ /dev/null @@ -1 +0,0 @@ -{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 deleted file mode 100644 index 72b4395d9..000000000 --- a/tests/testdata/test_key_ec.txt +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 54ddbbad1..000000000 --- a/tests/testdata/test_key_f4.txt +++ /dev/null @@ -1 +0,0 @@ -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/tests/testdata/testkey.pk8 b/tests/testdata/testkey.pk8 deleted file mode 100644 index 586c1bd5c..000000000 Binary files a/tests/testdata/testkey.pk8 and /dev/null differ diff --git a/tests/testdata/testkey.x509.pem b/tests/testdata/testkey.x509.pem deleted file mode 100644 index e242d83e2..000000000 --- a/tests/testdata/testkey.x509.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD -VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g -VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE -AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe -Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET -MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G -A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p -ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI -hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM -qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 -wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy -4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU -RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s -zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw -HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ -AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE -CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH -QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG -CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud -EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa -J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y -LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe -+ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX -31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr -sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0= ------END CERTIFICATE----- diff --git a/tests/testdata/testkey_ecdsa.pk8 b/tests/testdata/testkey_ecdsa.pk8 deleted file mode 100644 index 9a521c8cf..000000000 Binary files a/tests/testdata/testkey_ecdsa.pk8 and /dev/null differ diff --git a/tests/testdata/testkey_ecdsa.x509.pem b/tests/testdata/testkey_ecdsa.x509.pem deleted file mode 100644 index b12283645..000000000 --- a/tests/testdata/testkey_ecdsa.x509.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBezCCASACCQC4g5wurPSmtzAKBggqhkjOPQQDAjBFMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMB4XDTEzMTAwODIxMTAxM1oXDTE0MTAwODIxMTAxM1owRTELMAkGA1UE -BhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp -ZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGcO1QDowF2E -RboWVmAYI2oXTr5MHAJ4xpMUFsrWVvoktYSN2RhNuOl5jZGvSBsQII9p/4qfjLmS -TBaCfQ0Xmt4wCgYIKoZIzj0EAwIDSQAwRgIhAIJjWmZAwngc2VcHUhYp2oSLoCQ+ -P+7AtbAn5242AqfOAiEAghO0t6jTKs0LUhLJrQwbOkHyZMVdZaG2vcwV9y9H5Qc= ------END CERTIFICATE----- diff --git a/tests/testdata/testkey_sha256.x509.pem b/tests/testdata/testkey_sha256.x509.pem deleted file mode 100644 index 002ce8968..000000000 --- a/tests/testdata/testkey_sha256.x509.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD -VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g -VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE -AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe -Fw0xMzA0MTAxODA1MzZaFw0xMzA1MTAxODA1MzZaMIGUMQswCQYDVQQGEwJVUzET -MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G -A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p -ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI -hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM -qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 -wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy -4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU -RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s -zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw -HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ -AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE -CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH -QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG -CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud -EwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKRVj9hOaozH1W8Wb4CNj7sCWixh -UMMZJXkxUtvUVHZGefp6MdtYiD/ZM7YRwZphm9aNhkykbHJdZ3lPzeL2csCa+sDQ -8sIzGu0/aD6p4zgIKQZmz0mZHqPGbHoLWOmA9EexRCFZ7vO/kO56ZbyhfFz2DI3S -Yez65CabErOFhNX6WukSPbV3zfsHRDD5JUStb/ko6t99HXsvIO0Ax9poj60PpCC1 -SiFzHZUY9mOnUfJFs+3NWCwKtP9nho3mZ3pJ1i+SeF6JiqbE3KHl4CDBeVGcu3CK -fiUZ8e8iXVN471Cgc5GD6Ud1pS7ifNZJsKhbETQ63KmvHCLRPi4NmP67uDE= ------END CERTIFICATE----- diff --git a/tests/testdata/testkey_v1.pk8 b/tests/testdata/testkey_v1.pk8 new file mode 100644 index 000000000..586c1bd5c Binary files /dev/null and b/tests/testdata/testkey_v1.pk8 differ diff --git a/tests/testdata/testkey_v1.txt b/tests/testdata/testkey_v1.txt new file mode 100644 index 000000000..53f5297bd --- /dev/null +++ b/tests/testdata/testkey_v1.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/testkey_v1.x509.pem b/tests/testdata/testkey_v1.x509.pem new file mode 100644 index 000000000..e242d83e2 --- /dev/null +++ b/tests/testdata/testkey_v1.x509.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE +AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G +A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI +hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM +qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 +wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy +4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU +RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s +zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw +HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ +AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH +QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG +CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa +J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y +LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe ++ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX +31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr +sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0= +-----END CERTIFICATE----- diff --git a/tests/testdata/testkey_v2.pk8 b/tests/testdata/testkey_v2.pk8 new file mode 100644 index 000000000..3052613c5 Binary files /dev/null and b/tests/testdata/testkey_v2.pk8 differ diff --git a/tests/testdata/testkey_v2.txt b/tests/testdata/testkey_v2.txt new file mode 100644 index 000000000..54ddbbad1 --- /dev/null +++ b/tests/testdata/testkey_v2.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/tests/testdata/testkey_v2.x509.pem b/tests/testdata/testkey_v2.x509.pem new file mode 100644 index 000000000..814abcf99 --- /dev/null +++ b/tests/testdata/testkey_v2.x509.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW +aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT +B1Rlc3QxMjMwHhcNMTIwNzI1MTg1NzAzWhcNMzkxMjExMTg1NzAzWjBvMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD +EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x +4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x +TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs +0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX +qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V +gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT +oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS +GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 +YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G +A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQEFBQADggEBAHqnXHtE+h3hvGmHh24GT51vGAYLc68WUUtCVlMIU85zQ757wlxZ +BmRypZ1i9hSqnXj5n+mETV5rFX3g2gvdAPVHkRycuDa2aUdZSE8cW4Z6qYFx6SaD +e+3SyXokpUquW64RuHJrf/yd/FnGjneBe3Qpm2reuzGWNH90qZGdbsfNaCm5kx2L +X+ZNHM3CcGMLaphY5++sM0JxSEcju5EK33ZYgLf4YdlbyMp8LDFVNd7ff0SFi9fF +0ZlAsJWoS3QmVCj2744BFdsCu7UHpnYpG6X3MT4SHAawdOaT5zSuaCl2xx6H0O7t +w/Fvbl/KVD1ZmLHgBKjDMNSh0OB9mSsDWpw= +-----END CERTIFICATE----- diff --git a/tests/testdata/testkey_v3.pk8 b/tests/testdata/testkey_v3.pk8 new file mode 120000 index 000000000..18ecf9815 --- /dev/null +++ b/tests/testdata/testkey_v3.pk8 @@ -0,0 +1 @@ +testkey_v1.pk8 \ No newline at end of file diff --git a/tests/testdata/testkey_v3.txt b/tests/testdata/testkey_v3.txt new file mode 100644 index 000000000..3208571a5 --- /dev/null +++ b/tests/testdata/testkey_v3.txt @@ -0,0 +1 @@ +v3 {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/testkey_v3.x509.pem b/tests/testdata/testkey_v3.x509.pem new file mode 100644 index 000000000..002ce8968 --- /dev/null +++ b/tests/testdata/testkey_v3.x509.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE +AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xMzA0MTAxODA1MzZaFw0xMzA1MTAxODA1MzZaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G +A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI +hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM +qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 +wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy +4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU +RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s +zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw +HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ +AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH +QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG +CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKRVj9hOaozH1W8Wb4CNj7sCWixh +UMMZJXkxUtvUVHZGefp6MdtYiD/ZM7YRwZphm9aNhkykbHJdZ3lPzeL2csCa+sDQ +8sIzGu0/aD6p4zgIKQZmz0mZHqPGbHoLWOmA9EexRCFZ7vO/kO56ZbyhfFz2DI3S +Yez65CabErOFhNX6WukSPbV3zfsHRDD5JUStb/ko6t99HXsvIO0Ax9poj60PpCC1 +SiFzHZUY9mOnUfJFs+3NWCwKtP9nho3mZ3pJ1i+SeF6JiqbE3KHl4CDBeVGcu3CK +fiUZ8e8iXVN471Cgc5GD6Ud1pS7ifNZJsKhbETQ63KmvHCLRPi4NmP67uDE= +-----END CERTIFICATE----- diff --git a/tests/testdata/testkey_v4.pk8 b/tests/testdata/testkey_v4.pk8 new file mode 120000 index 000000000..683b9a3f1 --- /dev/null +++ b/tests/testdata/testkey_v4.pk8 @@ -0,0 +1 @@ +testkey_v2.pk8 \ No newline at end of file diff --git a/tests/testdata/testkey_v4.txt b/tests/testdata/testkey_v4.txt new file mode 100644 index 000000000..532cbd51a --- /dev/null +++ b/tests/testdata/testkey_v4.txt @@ -0,0 +1 @@ +v4 {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/tests/testdata/testkey_v4.x509.pem b/tests/testdata/testkey_v4.x509.pem new file mode 100644 index 000000000..9d5376b45 --- /dev/null +++ b/tests/testdata/testkey_v4.x509.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBCwUAMG8xCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW +aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT +B1Rlc3QxMjMwHhcNMTMwNDEwMTcyMzUyWhcNMTMwNTEwMTcyMzUyWjBvMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD +EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x +4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x +TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs +0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX +qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V +gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT +oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS +GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 +YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G +A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQELBQADggEBAKWWQ9S0V9wWjrMJe8exj1gklwD1Ysi0vi+h2tfixahelrpsNkWi +EFjoUSHEkW9ThLmtui646uAlwSiWtSn1XkGGmIJ3s+gmAFUcMc0CaK0dgoq/M9zn +fQ0Vkzc1tK4MLsf+CbPDywPycb6+T3dBkerbWn9GUpjGl1ANWlciXZZ3657m61sL +HhwUOBxbZZ6sYP4ed2SVCf45GgMyJ0VoUg5yI2JzPAgOkGfeEIPVXE1M94edJY4G +8eHYvXovJZwXvKFI+ZyS0KBPx8cpfw89RB9qmkxqNBIm8qWb3qBiuBEIPj+NF/7w +sC/Fv8NNXkVquy0xa0qdyJBABzWE18zGcXs= +-----END CERTIFICATE----- diff --git a/tests/testdata/testkey_v5.pk8 b/tests/testdata/testkey_v5.pk8 new file mode 100644 index 000000000..9a521c8cf Binary files /dev/null and b/tests/testdata/testkey_v5.pk8 differ diff --git a/tests/testdata/testkey_v5.txt b/tests/testdata/testkey_v5.txt new file mode 100644 index 000000000..72b4395d9 --- /dev/null +++ b/tests/testdata/testkey_v5.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/testkey_v5.x509.pem b/tests/testdata/testkey_v5.x509.pem new file mode 100644 index 000000000..b12283645 --- /dev/null +++ b/tests/testdata/testkey_v5.x509.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBezCCASACCQC4g5wurPSmtzAKBggqhkjOPQQDAjBFMQswCQYDVQQGEwJBVTET +MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMB4XDTEzMTAwODIxMTAxM1oXDTE0MTAwODIxMTAxM1owRTELMAkGA1UE +BhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGcO1QDowF2E +RboWVmAYI2oXTr5MHAJ4xpMUFsrWVvoktYSN2RhNuOl5jZGvSBsQII9p/4qfjLmS +TBaCfQ0Xmt4wCgYIKoZIzj0EAwIDSQAwRgIhAIJjWmZAwngc2VcHUhYp2oSLoCQ+ +P+7AtbAn5242AqfOAiEAghO0t6jTKs0LUhLJrQwbOkHyZMVdZaG2vcwV9y9H5Qc= +-----END CERTIFICATE----- -- cgit v1.2.3 From 073164f24b212685c181c8620f0397d13e9d79c0 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Fri, 5 Aug 2016 15:59:05 -0700 Subject: Fix references to libcrypto_utils_static. Bug: http://b/30708454 Change-Id: I7a5048beff1d8b783a9683dcb4a79606a77f20ee --- tests/Android.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 7b004b2a0..a683395fc 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -39,8 +39,8 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_STATIC_LIBRARIES := \ libbase \ libverifier \ - libcrypto_utils_static \ - libcrypto_static \ + libcrypto_utils \ + libcrypto \ libminui \ libminzip \ libcutils \ -- cgit v1.2.3 From 8b23811d2ac5c056ff49f2ab4fca3447a9fdca42 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Fri, 26 Aug 2016 14:54:29 -0700 Subject: Fix clang-tidy warnings in bootable/recovery. * Use const reference type for read-only parameters. Bug: 30407689 * Use faster overloaded string find function. Bug: 30411878 * Add parentheses around macro parameters. Bug: 28705665 Test: build with WITH_TIDY=1 Change-Id: I4e8e5748bfa4ae89871f1fb5fa4624d372530d75 --- tests/component/applypatch_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index b44ddd17c..2f7cb02f4 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -65,7 +65,7 @@ static bool file_cmp(std::string& f1, std::string& f2) { return c1 == c2; } -static std::string from_testdata_base(const std::string fname) { +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], -- cgit v1.2.3 From 7b0ad9c638176dc364dabb65b363536055a0ea9c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 5 Aug 2016 18:00:04 -0700 Subject: Switch recovery to libbase logging Clean up the recovery image and switch to libbase logging. Bug: 28191554 Change-Id: Icd999c3cc832f0639f204b5c36cea8afe303ad35 Merged-In: Icd999c3cc832f0639f204b5c36cea8afe303ad35 --- tests/Android.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 971e5d0f0..633b3c451 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -46,7 +46,6 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_STATIC_LIBRARIES := \ libapplypatch \ libotafault \ - libbase \ libverifier \ libcrypto_utils \ libcrypto \ @@ -55,7 +54,9 @@ LOCAL_STATIC_LIBRARIES := \ libcutils \ libbz \ libz \ - libc + libc \ + libbase \ + liblog testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery testdata_files := $(call find-subdir-files, testdata/*) -- cgit v1.2.3 From 7aa88748f6ec4e53333d1a15747bc44826ccc410 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 28 Sep 2016 11:42:17 -0700 Subject: Turn on -Werror for recovery Also remove the 0xff comparison when validating the bootloader message fields. As the fields won't be erased to 0xff after we remove the MTD support. Bug: 28202046 Test: The recovery folder compiles for aosp_x86-eng Change-Id: Ibb30ea1b2b28676fb08c7e92a1e5f7b6ef3247ab --- tests/Android.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 633b3c451..0754c7acf 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -19,6 +19,7 @@ LOCAL_PATH := $(call my-dir) # Unit tests include $(CLEAR_VARS) LOCAL_CLANG := true +LOCAL_CFLAGS := -Werror LOCAL_MODULE := recovery_unit_test LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_STATIC_LIBRARIES := \ @@ -35,7 +36,7 @@ include $(BUILD_NATIVE_TEST) # Component tests include $(CLEAR_VARS) LOCAL_CLANG := true -LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-unused-parameter -Werror LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := recovery_component_test LOCAL_C_INCLUDES := bootable/recovery -- cgit v1.2.3 From d770d2e7afd8a909156447c2b79d8739228279d7 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 3 Oct 2016 15:26:06 -0700 Subject: edify: Move the testcases to gtest. Now they live in tests/component/edify_test.cpp. Also rename edify/main.cpp to edify/edify_parser.cpp. It becomes a host-side debugging tool that validates the input edify script. However, it supports edify builtin functions only and doesn't recognize the ones defined via updater. Test: recovery_component_test passes on device. Change-Id: Ib94a787bf15098a9cc078d256b6a6dc96ff12b2e --- tests/Android.mk | 2 + tests/component/edify_test.cpp | 156 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 tests/component/edify_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 0754c7acf..19cb80940 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -41,11 +41,13 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := recovery_component_test LOCAL_C_INCLUDES := bootable/recovery LOCAL_SRC_FILES := \ + component/edify_test.cpp \ component/verifier_test.cpp \ component/applypatch_test.cpp LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_STATIC_LIBRARIES := \ libapplypatch \ + libedify \ libotafault \ libverifier \ libcrypto_utils \ diff --git a/tests/component/edify_test.cpp b/tests/component/edify_test.cpp new file mode 100644 index 000000000..ded8540a0 --- /dev/null +++ b/tests/component/edify_test.cpp @@ -0,0 +1,156 @@ +/* + * 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 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 + +#include + +#include "edify/expr.h" + +static void expect(const char* expr_str, const char* expected) { + Expr* e; + int error_count; + EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0); + + State state; + state.cookie = nullptr; + state.errmsg = nullptr; + state.script = strdup(expr_str); + + char* result = Evaluate(&state, e); + + if (expected == nullptr) { + EXPECT_EQ(result, nullptr); + } else { + EXPECT_STREQ(result, expected); + } + + free(state.errmsg); + free(state.script); + free(result); +} + +class EdifyTest : public ::testing::Test { + protected: + virtual void SetUp() { + RegisterBuiltins(); + FinishRegistration(); + } +}; + +TEST_F(EdifyTest, parsing) { + expect("a", "a"); + expect("\"a\"", "a"); + expect("\"\\x61\"", "a"); + expect("# this is a comment\n" + " a\n" + " \n", + "a"); +} + +TEST_F(EdifyTest, sequence) { + // sequence operator + expect("a; b; c", "c"); +} + +TEST_F(EdifyTest, concat) { + // string concat operator + expect("a + b", "ab"); + expect("a + \n \"b\"", "ab"); + expect("a + b +\nc\n", "abc"); + + // string concat function + expect("concat(a, b)", "ab"); + expect("concat(a,\n \"b\")", "ab"); + expect("concat(a + b,\nc,\"d\")", "abcd"); + expect("\"concat\"(a + b,\nc,\"d\")", "abcd"); +} + +TEST_F(EdifyTest, logical) { + // logical and + expect("a && b", "b"); + expect("a && \"\"", ""); + expect("\"\" && b", ""); + expect("\"\" && \"\"", ""); + expect("\"\" && abort()", ""); // test short-circuiting + expect("t && abort()", nullptr); + + // logical or + expect("a || b", "a"); + expect("a || \"\"", "a"); + expect("\"\" || b", "b"); + expect("\"\" || \"\"", ""); + expect("a || abort()", "a"); // test short-circuiting + expect("\"\" || abort()", NULL); + + // logical not + expect("!a", ""); + expect("! \"\"", "t"); + expect("!!a", "t"); +} + +TEST_F(EdifyTest, precedence) { + // precedence + expect("\"\" == \"\" && b", "b"); + expect("a + b == ab", "t"); + expect("ab == a + b", "t"); + expect("a + (b == ab)", "a"); + expect("(ab == a) + b", "b"); +} + +TEST_F(EdifyTest, substring) { + // substring function + expect("is_substring(cad, abracadabra)", "t"); + expect("is_substring(abrac, abracadabra)", "t"); + expect("is_substring(dabra, abracadabra)", "t"); + expect("is_substring(cad, abracxadabra)", ""); + expect("is_substring(abrac, axbracadabra)", ""); + expect("is_substring(dabra, abracadabrxa)", ""); +} + +TEST_F(EdifyTest, ifelse) { + // ifelse function + expect("ifelse(t, yes, no)", "yes"); + expect("ifelse(!t, yes, no)", "no"); + expect("ifelse(t, yes, abort())", "yes"); + expect("ifelse(!t, abort(), no)", "no"); +} + +TEST_F(EdifyTest, if_statement) { + // if "statements" + expect("if t then yes else no endif", "yes"); + expect("if \"\" then yes else no endif", "no"); + expect("if \"\" then yes endif", ""); + expect("if \"\"; t then yes endif", "yes"); +} + +TEST_F(EdifyTest, comparison) { + // numeric comparisons + expect("less_than_int(3, 14)", "t"); + expect("less_than_int(14, 3)", ""); + expect("less_than_int(x, 3)", ""); + expect("less_than_int(3, x)", ""); + expect("greater_than_int(3, 14)", ""); + expect("greater_than_int(14, 3)", "t"); + expect("greater_than_int(x, 3)", ""); + expect("greater_than_int(3, x)", ""); +} + +TEST_F(EdifyTest, big_string) { + // big string + expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str()); +} + -- cgit v1.2.3 From fee79a4532e9ef27b9dae4b02f2d06fa932e8c95 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 4 Oct 2016 08:58:24 -0700 Subject: recovery: drop log/logger.h private/android_logger.h contains all we need. Test: compile Bug: 26552300 Bug: 31289077 Bug: 31456426 Change-Id: I6714d730372dc81f784e7f9dfee8a33848643a5d --- tests/unit/recovery_test.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'tests') diff --git a/tests/unit/recovery_test.cpp b/tests/unit/recovery_test.cpp index f397f258e..28b845fb9 100644 --- a/tests/unit/recovery_test.cpp +++ b/tests/unit/recovery_test.cpp @@ -21,7 +21,6 @@ #include #include -#include #include static const char myFilename[] = "/data/misc/recovery/inject.txt"; -- cgit v1.2.3 From 59dcb9cbea8fb70ab933fd10d35582b08cd13f37 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 3 Oct 2016 18:06:46 -0700 Subject: edify: Move State.script and State.errmsg to std::string. This way we kill a few strdup() and free() calls. Test: 1. recovery_component_test still passes; 2. Applying an update with the new updater works; 3. The error code in a script with abort("E310: xyz") is recorded into last_install correctly. Change-Id: Ibda4da5937346e058a0d7cc81764d6f02920010a --- tests/component/edify_test.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/component/edify_test.cpp b/tests/component/edify_test.cpp index ded8540a0..ede2ecb0a 100644 --- a/tests/component/edify_test.cpp +++ b/tests/component/edify_test.cpp @@ -25,10 +25,7 @@ static void expect(const char* expr_str, const char* expected) { int error_count; EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0); - State state; - state.cookie = nullptr; - state.errmsg = nullptr; - state.script = strdup(expr_str); + State state(expr_str, nullptr); char* result = Evaluate(&state, e); @@ -38,8 +35,6 @@ static void expect(const char* expr_str, const char* expected) { EXPECT_STREQ(result, expected); } - free(state.errmsg); - free(state.script); free(result); } -- cgit v1.2.3 From 0c7839ac14a00f32d740c23ddf6df65f2757ece5 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 10 Oct 2016 15:48:37 -0700 Subject: Refactor libupdater into a seperate module. So that we can write native tests for updater functions. This CL adds a testcase for getprop() function. Test: mmma bootable/recovery; Run recovery_component_test on device. Change-Id: Iff4c1ff63c5c71aded2f9686fed6b71cc298c228 --- tests/Android.mk | 28 ++++++++++++---- tests/component/updater_test.cpp | 71 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 tests/component/updater_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 19cb80940..ef822d1d1 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -41,25 +41,41 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := recovery_component_test LOCAL_C_INCLUDES := bootable/recovery LOCAL_SRC_FILES := \ + component/applypatch_test.cpp \ component/edify_test.cpp \ - component/verifier_test.cpp \ - component/applypatch_test.cpp + component/updater_test.cpp \ + component/verifier_test.cpp LOCAL_FORCE_STATIC_EXECUTABLE := true + +tune2fs_static_libraries := \ + libext2_com_err \ + libext2_blkid \ + libext2_quota \ + libext2_uuid_static \ + libext2_e2p \ + libext2fs + LOCAL_STATIC_LIBRARIES := \ libapplypatch \ libedify \ libotafault \ + libupdater \ libverifier \ - libcrypto_utils \ - libcrypto \ libminui \ libminzip \ + libmounts \ + liblog \ + libselinux \ + libext4_utils_static \ + libsparse_static \ + libcrypto_utils \ + libcrypto \ libcutils \ libbz \ libz \ - libc \ libbase \ - liblog + libtune2fs \ + $(tune2fs_static_libraries) testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery testdata_files := $(call find-subdir-files, testdata/*) diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp new file mode 100644 index 000000000..ec9c29035 --- /dev/null +++ b/tests/component/updater_test.cpp @@ -0,0 +1,71 @@ +/* + * 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 + +#include +#include + +#include "edify/expr.h" +#include "error_code.h" +#include "updater/install.h" + +struct selabel_handle *sehandle = nullptr; + +static void expect(const char* expected, const char* expr_str, + ErrorCode error_code, CauseCode cause_code) { + Expr* e; + int error_count; + EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0); + + State state(expr_str, nullptr); + + char* result = Evaluate(&state, e); + + if (expected == nullptr) { + EXPECT_EQ(nullptr, result); + } else { + EXPECT_STREQ(expected, result); + } + + EXPECT_EQ(error_code, state.error_code); + EXPECT_EQ(cause_code, state.cause_code); + + free(result); +} + +class UpdaterTest : public ::testing::Test { + protected: + virtual void SetUp() { + RegisterBuiltins(); + RegisterInstallFunctions(); + FinishRegistration(); + } +}; + +TEST_F(UpdaterTest, getprop) { + expect(android::base::GetProperty("ro.product.device", "").c_str(), + "getprop(\"ro.product.device\")", + kNoError, kNoCause); + + expect(android::base::GetProperty("ro.build.fingerprint", "").c_str(), + "getprop(\"ro.build.fingerprint\")", + kNoError, kNoCause); + + // getprop() accepts only one parameter. + expect(nullptr, "getprop()", kNoError, kArgsParsingFailure); + expect(nullptr, "getprop(\"arg1\", \"arg2\")", kNoError, kArgsParsingFailure); +} -- cgit v1.2.3 From 361342cbd2af4bbf74ac9e91ddfb2a973220a106 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 8 Feb 2016 11:15:50 -0800 Subject: updater: Kill the duplicate PrintSha1() in install.cpp. Also add a testcase for sha1_check(). Test: mmma bootable/recovery; recovery_component_test passes. Change-Id: I4d06d551a771aec84e460148544f68b247a7e721 --- tests/component/updater_test.cpp | 43 +++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index ec9c29035..bd6534b3b 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -25,8 +25,7 @@ struct selabel_handle *sehandle = nullptr; -static void expect(const char* expected, const char* expr_str, - ErrorCode error_code, CauseCode cause_code) { +static void expect(const char* expected, const char* expr_str, CauseCode cause_code) { Expr* e; int error_count; EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0); @@ -41,7 +40,10 @@ static void expect(const char* expected, const char* expr_str, EXPECT_STREQ(expected, result); } - EXPECT_EQ(error_code, state.error_code); + // Error code is set in updater/updater.cpp only, by parsing State.errmsg. + EXPECT_EQ(kNoError, state.error_code); + + // Cause code should always be available. EXPECT_EQ(cause_code, state.cause_code); free(result); @@ -59,13 +61,40 @@ class UpdaterTest : public ::testing::Test { TEST_F(UpdaterTest, getprop) { expect(android::base::GetProperty("ro.product.device", "").c_str(), "getprop(\"ro.product.device\")", - kNoError, kNoCause); + kNoCause); expect(android::base::GetProperty("ro.build.fingerprint", "").c_str(), "getprop(\"ro.build.fingerprint\")", - kNoError, kNoCause); + kNoCause); // getprop() accepts only one parameter. - expect(nullptr, "getprop()", kNoError, kArgsParsingFailure); - expect(nullptr, "getprop(\"arg1\", \"arg2\")", kNoError, kArgsParsingFailure); + expect(nullptr, "getprop()", kArgsParsingFailure); + expect(nullptr, "getprop(\"arg1\", \"arg2\")", kArgsParsingFailure); +} + +TEST_F(UpdaterTest, sha1_check) { + // sha1_check(data) returns the SHA-1 of the data. + expect("81fe8bfe87576c3ecb22426f8e57847382917acf", "sha1_check(\"abcd\")", kNoCause); + expect("da39a3ee5e6b4b0d3255bfef95601890afd80709", "sha1_check(\"\")", kNoCause); + + // sha1_check(data, sha1_hex, [sha1_hex, ...]) returns the matched SHA-1. + expect("81fe8bfe87576c3ecb22426f8e57847382917acf", + "sha1_check(\"abcd\", \"81fe8bfe87576c3ecb22426f8e57847382917acf\")", + kNoCause); + + expect("81fe8bfe87576c3ecb22426f8e57847382917acf", + "sha1_check(\"abcd\", \"wrong_sha1\", \"81fe8bfe87576c3ecb22426f8e57847382917acf\")", + kNoCause); + + // Or "" if there's no match. + expect("", + "sha1_check(\"abcd\", \"wrong_sha1\")", + kNoCause); + + expect("", + "sha1_check(\"abcd\", \"wrong_sha1\", \"wrong_sha2\")", + kNoCause); + + // sha1_check() expects at least one argument. + expect(nullptr, "sha1_check()", kArgsParsingFailure); } -- cgit v1.2.3 From 39119ad8ecd00a9c19fb173c78cb4a8d22a4540a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 10 Oct 2016 22:52:18 -0700 Subject: edify: Some clean-ups to libedify. - Remove dead declarations in expr.h: SetError(), GetError(), ClearError(). - Remove the declaration of Build() out of expr.h. - Use std::unordered_map to implement RegisterFunction() and FindFunction(); kill FinishRegistration(). - Add a testcase for calling unknown functions. Test: mmma bootable/recovery; recovery_component_test passes. Change-Id: I9af6825ae677f92b22d716a4a5682f58522af03b --- tests/component/edify_test.cpp | 28 +++++++++++++++++++++++----- tests/component/updater_test.cpp | 1 - 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/component/edify_test.cpp b/tests/component/edify_test.cpp index ede2ecb0a..a4dbb9fbe 100644 --- a/tests/component/edify_test.cpp +++ b/tests/component/edify_test.cpp @@ -22,17 +22,18 @@ static void expect(const char* expr_str, const char* expected) { Expr* e; - int error_count; - EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0); + int error_count = 0; + EXPECT_EQ(0, parse_string(expr_str, &e, &error_count)); + EXPECT_EQ(0, error_count); State state(expr_str, nullptr); char* result = Evaluate(&state, e); if (expected == nullptr) { - EXPECT_EQ(result, nullptr); + EXPECT_EQ(nullptr, result); } else { - EXPECT_STREQ(result, expected); + EXPECT_STREQ(expected, result); } free(result); @@ -42,7 +43,6 @@ class EdifyTest : public ::testing::Test { protected: virtual void SetUp() { RegisterBuiltins(); - FinishRegistration(); } }; @@ -149,3 +149,21 @@ TEST_F(EdifyTest, big_string) { expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str()); } +TEST_F(EdifyTest, unknown_function) { + // unknown function + const char* script1 = "unknown_function()"; + Expr* expr; + int error_count = 0; + EXPECT_EQ(1, parse_string(script1, &expr, &error_count)); + EXPECT_EQ(1, error_count); + + const char* script2 = "abc; unknown_function()"; + error_count = 0; + EXPECT_EQ(1, parse_string(script2, &expr, &error_count)); + EXPECT_EQ(1, error_count); + + const char* script3 = "unknown_function1() || yes"; + error_count = 0; + EXPECT_EQ(1, parse_string(script3, &expr, &error_count)); + EXPECT_EQ(1, error_count); +} diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index bd6534b3b..64a6b37ce 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -54,7 +54,6 @@ class UpdaterTest : public ::testing::Test { virtual void SetUp() { RegisterBuiltins(); RegisterInstallFunctions(); - FinishRegistration(); } }; -- cgit v1.2.3 From aced5d9e4e438ba478ce54f9217166b8ab7cc24f Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 12 Oct 2016 10:55:04 -0700 Subject: Change StringValue to use std::string Changing the field of 'Value' in edify to std::string from char*. Meanwhile cleaning up the users of 'Value' and switching them to cpp style. Test: compontent tests passed. Bug: 31713288 Change-Id: Iec5a7d601b1e4ca40935bf1c70d325dafecec235 --- tests/component/applypatch_test.cpp | 132 ++++++++++++++++-------------------- tests/component/edify_test.cpp | 8 +-- tests/component/updater_test.cpp | 8 +-- 3 files changed, 67 insertions(+), 81 deletions(-) (limited to 'tests') diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index 2f7cb02f4..75f2e1014 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -153,25 +153,16 @@ class ApplyPatchFullTest : public ApplyPatchCacheTest { 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(malloc(fc.data.size())); - memcpy(patch1->data, fc.data.data(), fc.data.size()); + Value* patch1 = new Value(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())); 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(malloc(fc.data.size())); - memcpy(patch2->data, fc.data.data(), fc.data.size()); + Value* patch2 = new Value(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())); 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(); @@ -210,88 +201,87 @@ 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)); + std::vector sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeMultiple) { - char* argv[3] = { - &bad_sha1_a[0], - &old_sha1[0], - &bad_sha1_b[0] + std::vector sha1s = { + bad_sha1_a, + old_sha1, + bad_sha1_b }; - ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv)); + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeFailure) { - char* argv[2] = { - &bad_sha1_a[0], - &bad_sha1_b[0] + std::vector sha1s = { + bad_sha1_a, + bad_sha1_b }; - ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv)); + ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) { mangle_file(old_file); - char* s = &old_sha1[0]; - ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s)); + std::vector sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) { mangle_file(old_file); - char* argv[3] = { - &bad_sha1_a[0], - &old_sha1[0], - &bad_sha1_b[0] + std::vector sha1s = { + bad_sha1_a, + old_sha1, + bad_sha1_b }; - ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv)); + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) { mangle_file(old_file); - char* argv[2] = { - &bad_sha1_a[0], - &bad_sha1_b[0] + std::vector sha1s = { + bad_sha1_a, + bad_sha1_b }; - ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv)); + ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) { unlink(&old_file[0]); - char* s = &old_sha1[0]; - ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s)); + std::vector sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) { unlink(&old_file[0]); - char* argv[3] = { - &bad_sha1_a[0], - &old_sha1[0], - &bad_sha1_b[0] + std::vector sha1s = { + bad_sha1_a, + old_sha1, + bad_sha1_b }; - ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv)); + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) { unlink(&old_file[0]); - char* argv[2] = { - &bad_sha1_a[0], - &bad_sha1_b[0] + std::vector sha1s = { + bad_sha1_a, + bad_sha1_b }; - ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv)); + ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchFullTest, ApplyInPlace) { - std::vector sha1s; - sha1s.push_back(&bad_sha1_a[0]); - sha1s.push_back(&old_sha1[0]); - + std::vector sha1s = { + bad_sha1_a, + old_sha1 + }; int ap_result = applypatch(&old_file[0], "-", &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_EQ(0, ap_result); @@ -301,8 +291,7 @@ TEST_F(ApplyPatchFullTest, ApplyInPlace) { "-", &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_EQ(0, ap_result); @@ -310,15 +299,15 @@ TEST_F(ApplyPatchFullTest, ApplyInPlace) { } TEST_F(ApplyPatchFullTest, ApplyInNewLocation) { - std::vector sha1s; - sha1s.push_back(&bad_sha1_a[0]); - sha1s.push_back(&old_sha1[0]); + std::vector sha1s = { + bad_sha1_a, + old_sha1 + }; int ap_result = applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_EQ(0, ap_result); @@ -327,8 +316,7 @@ TEST_F(ApplyPatchFullTest, ApplyInNewLocation) { &output_loc[0], &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_EQ(0, ap_result); @@ -337,15 +325,15 @@ TEST_F(ApplyPatchFullTest, ApplyInNewLocation) { TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) { mangle_file(old_file); - std::vector sha1s; - sha1s.push_back(&bad_sha1_a[0]); - sha1s.push_back(&old_sha1[0]); + std::vector sha1s = { + bad_sha1_a, + old_sha1 + }; int ap_result = applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_EQ(0, ap_result); @@ -354,8 +342,7 @@ TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) { &output_loc[0], &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_EQ(0, ap_result); @@ -366,15 +353,15 @@ TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) { mangle_file(old_file); mangle_file(cache_file); - std::vector sha1s; - sha1s.push_back(&bad_sha1_a[0]); - sha1s.push_back(&old_sha1[0]); + std::vector sha1s = { + bad_sha1_a, + old_sha1 + }; int ap_result = applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_NE(0, ap_result); @@ -383,8 +370,7 @@ TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) { &output_loc[0], &new_sha1[0], new_size, - 2, - sha1s.data(), + sha1s, patches.data(), nullptr); ASSERT_NE(0, ap_result); diff --git a/tests/component/edify_test.cpp b/tests/component/edify_test.cpp index a4dbb9fbe..287e40cc6 100644 --- a/tests/component/edify_test.cpp +++ b/tests/component/edify_test.cpp @@ -28,15 +28,15 @@ static void expect(const char* expr_str, const char* expected) { State state(expr_str, nullptr); - char* result = Evaluate(&state, e); + std::string result; + bool status = Evaluate(&state, e, &result); if (expected == nullptr) { - EXPECT_EQ(nullptr, result); + EXPECT_FALSE(status); } else { - EXPECT_STREQ(expected, result); + EXPECT_STREQ(expected, result.c_str()); } - free(result); } class EdifyTest : public ::testing::Test { diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index 64a6b37ce..a859f11c1 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -32,12 +32,13 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c State state(expr_str, nullptr); - char* result = Evaluate(&state, e); + std::string result; + bool status = Evaluate(&state, e, &result); if (expected == nullptr) { - EXPECT_EQ(nullptr, result); + EXPECT_FALSE(status); } else { - EXPECT_STREQ(expected, result); + EXPECT_STREQ(expected, result.c_str()); } // Error code is set in updater/updater.cpp only, by parsing State.errmsg. @@ -46,7 +47,6 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c // Cause code should always be available. EXPECT_EQ(cause_code, state.cause_code); - free(result); } class UpdaterTest : public ::testing::Test { -- cgit v1.2.3 From 8cf5c8f60f51049278b08ae4cbc31df397b651fd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 8 Sep 2016 20:10:11 -0700 Subject: Replace minzip with libziparchive Clean up the duplicated codes that handle the zip files in bootable/recovery; and rename the library of the remaining utility functions to libotautil. Test: Update package installed successfully on angler. Bug: 19472796 Change-Id: Iea8962fcf3004473cb0322b6bb3a9ea3ca7f679e --- tests/Android.mk | 11 +++- tests/component/verifier_test.cpp | 3 +- tests/testdata/ziptest_dummy-update.zip | Bin 0 -> 1090065 bytes tests/testdata/ziptest_valid.zip | Bin 0 -> 758 bytes tests/unit/zip_test.cpp | 93 ++++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 tests/testdata/ziptest_dummy-update.zip create mode 100644 tests/testdata/ziptest_valid.zip create mode 100644 tests/unit/zip_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index ef822d1d1..abe6b6d68 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -24,11 +24,18 @@ LOCAL_MODULE := recovery_unit_test LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_STATIC_LIBRARIES := \ libverifier \ - libminui + libminui \ + libotautil \ + libziparchive \ + libutils \ + libz \ + libselinux \ + libbase LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp LOCAL_SRC_FILES += unit/recovery_test.cpp LOCAL_SRC_FILES += unit/locale_test.cpp +LOCAL_SRC_FILES += unit/zip_test.cpp LOCAL_C_INCLUDES := bootable/recovery LOCAL_SHARED_LIBRARIES := liblog include $(BUILD_NATIVE_TEST) @@ -62,7 +69,7 @@ LOCAL_STATIC_LIBRARIES := \ libupdater \ libverifier \ libminui \ - libminzip \ + libotautil \ libmounts \ liblog \ libselinux \ diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 6a3eebf29..7f9a71408 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -29,10 +29,11 @@ #include #include +#include #include "common.h" #include "common/test_constants.h" -#include "minzip/SysUtil.h" +#include "otautil/SysUtil.h" #include "ui.h" #include "verifier.h" diff --git a/tests/testdata/ziptest_dummy-update.zip b/tests/testdata/ziptest_dummy-update.zip new file mode 100644 index 000000000..6976bf155 Binary files /dev/null and b/tests/testdata/ziptest_dummy-update.zip differ diff --git a/tests/testdata/ziptest_valid.zip b/tests/testdata/ziptest_valid.zip new file mode 100644 index 000000000..9e7cb7800 Binary files /dev/null and b/tests/testdata/ziptest_valid.zip differ diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp new file mode 100644 index 000000000..b617446b8 --- /dev/null +++ b/tests/unit/zip_test.cpp @@ -0,0 +1,93 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static const std::string DATA_PATH(getenv("ANDROID_DATA")); +static const std::string TESTDATA_PATH("/recovery/testdata/"); + +static const std::vector kATxtContents { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + '\n' +}; + +static const std::vector kBTxtContents { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + '\n' +}; + +TEST(otazip, ExtractPackageRecursive) { + TemporaryDir td; + ASSERT_NE(td.path, nullptr); + ZipArchiveHandle handle; + std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_valid.zip"; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + // Extract the whole package into a temp directory. + ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr); + // Make sure all the files are extracted correctly. + std::string path(td.path); + android::base::unique_fd fd(open((path + "/a.txt").c_str(), O_RDONLY)); + ASSERT_NE(fd, -1); + std::vector read_data; + read_data.resize(kATxtContents.size()); + // The content of the file is the same as expected. + ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size())); + ASSERT_EQ(0, memcmp(read_data.data(), kATxtContents.data(), kATxtContents.size())); + + fd.reset(open((path + "/b.txt").c_str(), O_RDONLY)); + ASSERT_NE(fd, -1); + fd.reset(open((path + "/b/c.txt").c_str(), O_RDONLY)); + ASSERT_NE(fd, -1); + fd.reset(open((path + "/b/d.txt").c_str(), O_RDONLY)); + ASSERT_NE(fd, -1); + read_data.resize(kBTxtContents.size()); + ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size())); + ASSERT_EQ(0, memcmp(read_data.data(), kBTxtContents.data(), kBTxtContents.size())); +} + +TEST(otazip, OpenFromMemory) { + MemMapping map; + std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_dummy-update.zip"; + ASSERT_EQ(0, sysMapFile(zip_path.c_str(), &map)); + // Map an update package into memory and open the archive from there. + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_path.c_str(), &handle)); + static constexpr const char* BINARY_PATH = "META-INF/com/google/android/update-binary"; + ZipString binary_path(BINARY_PATH); + ZipEntry binary_entry; + // Make sure the package opens correctly and its entry can be read. + ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry)); + TemporaryFile tmp_binary; + ASSERT_NE(-1, tmp_binary.fd); + ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd)); +} + -- cgit v1.2.3 From a5fd5abe80ea5650bc0b638fc693884df5eaaa89 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 18 Oct 2016 15:18:22 -0700 Subject: Add a unit test for applypatch_check If no sha1 is specified, applypatch_check should pass as long as the file content loads successfully. Add a unit case acccordingly. Test: Unit tests passed Bug: 32243751 Change-Id: I8c013be67c197d2935e11cf6acc59fb9b943cfd9 --- tests/component/applypatch_test.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tests') diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index 75f2e1014..908a9f5f5 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -200,6 +200,11 @@ std::vector ApplyPatchFullTest::patches; TemporaryFile* ApplyPatchFullTest::output_f; std::string ApplyPatchFullTest::output_loc; +TEST_F(ApplyPatchTest, CheckModeSkip) { + std::vector sha1s; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); +} + TEST_F(ApplyPatchTest, CheckModeSingle) { std::vector sha1s = { old_sha1 }; ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); -- cgit v1.2.3 From f1338fbf4104f000e41b4f84f705db72096da324 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 25 Oct 2016 15:05:40 -0700 Subject: tests: Generate testdata for 2nd arch. We currently only copy the testdata to $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery, which fails the tests generated for 2nd arch (TARGET_2ND_ARCH). For example, on angler /data/nativetest/recovery_component_test/recovery_component_test fails due to missing testdata. Bug: 32123241 Test: Both of /data/nativetest/recovery... and /data/nativetest64/recovery... work on angler. Change-Id: Ib76264b4408d01c08b2619c8ac84b2476ea5a8bc --- tests/Android.mk | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index abe6b6d68..3d05386b0 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -84,13 +84,24 @@ LOCAL_STATIC_LIBRARIES := \ libtune2fs \ $(tune2fs_static_libraries) -testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery testdata_files := $(call find-subdir-files, testdata/*) +testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery 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) + +ifdef TARGET_2ND_ARCH +testdata_out_path_2nd_arch := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/recovery +GEN_2ND_ARCH := $(addprefix $(testdata_out_path_2nd_arch)/, $(testdata_files)) +$(GEN_2ND_ARCH): PRIVATE_PATH := $(LOCAL_PATH) +$(GEN_2ND_ARCH): PRIVATE_CUSTOM_TOOL = cp $< $@ +$(GEN_2ND_ARCH): $(testdata_out_path_2nd_arch)/% : $(LOCAL_PATH)/% + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN_2ND_ARCH) +endif # TARGET_2ND_ARCH + include $(BUILD_NATIVE_TEST) -- cgit v1.2.3 From fada91ccf2b31d69d72899388b1833186d763d1a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 27 Oct 2016 18:16:06 -0700 Subject: applypatch: Switch the parameter of Value** to std::vector. Test: Unit tests and install-recovery.sh pass on angler and dragon. Change-Id: I328e6554edca667cf850f5584ebf1ac211e3d4d1 --- tests/component/applypatch_test.cpp | 264 +++++++++++++++++++----------------- 1 file changed, 138 insertions(+), 126 deletions(-) (limited to 'tests') diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index 908a9f5f5..e09c1e7ba 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -23,102 +23,98 @@ #include #include +#include #include +#include #include #include #include +#include #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]; +static void sha1sum(const std::string& fname, std::string* sha1) { + ASSERT_NE(nullptr, sha1); + std::string data; - android::base::ReadFileToString(fname, &data); + ASSERT_TRUE(android::base::ReadFileToString(fname, &data)); - SHA1((const uint8_t*)data.c_str(), data.size(), digest); - return print_sha1(digest); + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(data.c_str()), data.size(), digest); + *sha1 = 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); + std::string content; + content.reserve(1024); + for (size_t i = 0; i < 1024; i++) { + content[i] = rand() % 256; } - fclose(fh); + ASSERT_TRUE(android::base::WriteStringToFile(content, fname)); } -static bool file_cmp(std::string& f1, std::string& f2) { +static bool file_cmp(const std::string& f1, const std::string& f2) { std::string c1; - std::string c2; android::base::ReadFileToString(f1, &c1); + std::string c2; 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]); + return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname; } 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; + 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 + ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file)); + + // set up SHA constants + sha1sum(old_file, &old_sha1); + sha1sum(new_file, &new_sha1); + 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]); +static void cp(const std::string& src, const std::string& tgt) { + std::string cmd = "cp " + src + " " + tgt; system(&cmd[0]); } @@ -131,59 +127,55 @@ static void restore_old() { } class ApplyPatchCacheTest : public ApplyPatchTest { - public: - virtual void SetUp() { - backup_old(); - } - - virtual void TearDown() { - restore_old(); - } + 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(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())); - patches.push_back(patch1); - - ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc)); - Value* patch2 = new Value(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())); - patches.push_back(patch2); - } - static void TearDownTestCase() { - delete output_f; - for (auto it = patches.begin(); it != patches.end(); ++it) { - delete *it; - } - patches.clear(); - } - - static std::vector patches; - static TemporaryFile* output_f; - static std::string output_loc; + public: + static void SetUpTestCase() { + ApplyPatchTest::SetUpTestCase(); + + output_f = new TemporaryFile(); + output_loc = std::string(output_f->path); + + struct FileContents fc; + + ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc)); + patches.push_back( + std::make_unique(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); + + ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc)); + patches.push_back( + std::make_unique(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); + } + + static void TearDownTestCase() { + delete output_f; + } + + static std::vector> 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(); - } + 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; @@ -196,7 +188,7 @@ std::string ApplyPatchTest::bad_sha1_b; size_t ApplyPatchTest::new_size; -std::vector ApplyPatchFullTest::patches; +std::vector> ApplyPatchFullTest::patches; TemporaryFile* ApplyPatchFullTest::output_f; std::string ApplyPatchFullTest::output_loc; @@ -287,7 +279,7 @@ TEST_F(ApplyPatchFullTest, ApplyInPlace) { &new_sha1[0], new_size, sha1s, - patches.data(), + patches, nullptr); ASSERT_EQ(0, ap_result); ASSERT_TRUE(file_cmp(old_file, new_file)); @@ -297,7 +289,7 @@ TEST_F(ApplyPatchFullTest, ApplyInPlace) { &new_sha1[0], new_size, sha1s, - patches.data(), + patches, nullptr); ASSERT_EQ(0, ap_result); ASSERT_TRUE(file_cmp(old_file, new_file)); @@ -308,75 +300,95 @@ TEST_F(ApplyPatchFullTest, ApplyInNewLocation) { bad_sha1_a, old_sha1 }; - int ap_result = applypatch(&old_file[0], + // Apply bsdiff patch to new location. + ASSERT_EQ(0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); + patches, + nullptr)); ASSERT_TRUE(file_cmp(output_loc, new_file)); - ap_result = applypatch(&old_file[0], + + // Reapply to the same location. + ASSERT_EQ(0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); + patches, + nullptr)); ASSERT_TRUE(file_cmp(output_loc, new_file)); } TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) { - mangle_file(old_file); std::vector sha1s = { bad_sha1_a, old_sha1 }; + // Apply bsdiff patch to new location with corrupted source. + mangle_file(old_file); int ap_result = applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, - patches.data(), + patches, nullptr); ASSERT_EQ(0, ap_result); ASSERT_TRUE(file_cmp(output_loc, new_file)); + + // Reapply bsdiff patch to new location with corrupted source. ap_result = applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, - patches.data(), + patches, 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 sha1s = { bad_sha1_a, old_sha1 }; + + // Apply bsdiff patch to new location with corrupted source and copy (no new file). + // Expected to fail. + mangle_file(old_file); + mangle_file(cache_file); int ap_result = applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, - patches.data(), + patches, + nullptr); + ASSERT_NE(0, ap_result); + ASSERT_FALSE(file_cmp(output_loc, new_file)); + + // Expected to fail again on retry. + ap_result = applypatch(&old_file[0], + &output_loc[0], + &new_sha1[0], + new_size, + sha1s, + patches, nullptr); ASSERT_NE(0, ap_result); ASSERT_FALSE(file_cmp(output_loc, new_file)); + + // Expected to fail with incorrect new file. + mangle_file(output_loc); ap_result = applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, - patches.data(), + patches, nullptr); ASSERT_NE(0, ap_result); ASSERT_FALSE(file_cmp(output_loc, new_file)); -- cgit v1.2.3 From 36c35119526023c9e28ec22915b26b1bf7da6bc3 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 25 Oct 2016 14:17:26 -0700 Subject: applypatch: Add testcases for applypatch executable. Refactor applypatch/main.cpp into libapplypatch_modes so that we can add testcases. Some changes to applypatch/main.cpp: - Replace char** argv with const char**; - Use android::base::Split() to split ":"; - Use android::base::ParseUInt(). Bug: 32383590 Test: Unit tests pass, install-recovery.sh works. Change-Id: I44e7bfa5ab717d439ea1d0ee9ddb7b2c40bb95a4 --- tests/Android.mk | 3 +- tests/component/applypatch_test.cpp | 578 ++++++++++++++----------- tests/testdata/bonus.file | Bin 0 -> 557334 bytes tests/testdata/boot.img | Bin 0 -> 783655 bytes tests/testdata/recovery-from-boot-with-bonus.p | Bin 0 -> 381615 bytes tests/testdata/recovery-from-boot.p | Bin 0 -> 5404 bytes tests/testdata/recovery.img | Bin 0 -> 529707 bytes 7 files changed, 324 insertions(+), 257 deletions(-) create mode 100644 tests/testdata/bonus.file create mode 100644 tests/testdata/boot.img create mode 100644 tests/testdata/recovery-from-boot-with-bonus.p create mode 100644 tests/testdata/recovery-from-boot.p create mode 100644 tests/testdata/recovery.img (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 3d05386b0..461d6ef76 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -43,7 +43,7 @@ include $(BUILD_NATIVE_TEST) # Component tests include $(CLEAR_VARS) LOCAL_CLANG := true -LOCAL_CFLAGS += -Wno-unused-parameter -Werror +LOCAL_CFLAGS := -Werror LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := recovery_component_test LOCAL_C_INCLUDES := bootable/recovery @@ -63,6 +63,7 @@ tune2fs_static_libraries := \ libext2fs LOCAL_STATIC_LIBRARIES := \ + libapplypatch_modes \ libapplypatch \ libedify \ libotafault \ diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index e09c1e7ba..f95ebed5d 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -33,149 +33,155 @@ #include #include "applypatch/applypatch.h" +#include "applypatch/applypatch_modes.h" #include "common/test_constants.h" #include "print_sha1.h" static const std::string DATA_PATH = getenv("ANDROID_DATA"); static const std::string TESTDATA_PATH = "/recovery/testdata"; -static void sha1sum(const std::string& fname, std::string* sha1) { - ASSERT_NE(nullptr, sha1); +static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) { + ASSERT_NE(nullptr, sha1); - std::string data; - ASSERT_TRUE(android::base::ReadFileToString(fname, &data)); + std::string data; + ASSERT_TRUE(android::base::ReadFileToString(fname, &data)); - uint8_t digest[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast(data.c_str()), data.size(), digest); - *sha1 = print_sha1(digest); + if (fsize != nullptr) { + *fsize = data.size(); + } + + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(data.c_str()), data.size(), digest); + *sha1 = print_sha1(digest); } static void mangle_file(const std::string& fname) { - std::string content; - content.reserve(1024); - for (size_t i = 0; i < 1024; i++) { - content[i] = rand() % 256; - } - ASSERT_TRUE(android::base::WriteStringToFile(content, fname)); + std::string content; + content.reserve(1024); + for (size_t i = 0; i < 1024; i++) { + content[i] = rand() % 256; + } + ASSERT_TRUE(android::base::WriteStringToFile(content, fname)); } static bool file_cmp(const std::string& f1, const std::string& f2) { - std::string c1; - android::base::ReadFileToString(f1, &c1); - std::string c2; - android::base::ReadFileToString(f2, &c2); - return c1 == c2; + std::string c1; + android::base::ReadFileToString(f1, &c1); + std::string c2; + android::base::ReadFileToString(f2, &c2); + return c1 == c2; } static std::string from_testdata_base(const std::string& fname) { - return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname; + return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname; } 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 - ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file)); - - // set up SHA constants - sha1sum(old_file, &old_sha1); - sha1sum(new_file, &new_sha1); - 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; + 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 + ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file)); + + // set up SHA constants + sha1sum(old_file, &old_sha1); + sha1sum(new_file, &new_sha1); + srand(time(nullptr)); + 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(const std::string& src, const std::string& tgt) { - std::string cmd = "cp " + src + " " + tgt; - system(&cmd[0]); + std::string cmd = "cp " + src + " " + tgt; + system(cmd.c_str()); } static void backup_old() { - cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file); + cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file); } static void restore_old() { - cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file); + cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file); } class ApplyPatchCacheTest : public ApplyPatchTest { - public: - virtual void SetUp() { - backup_old(); - } - - virtual void TearDown() { - restore_old(); - } + public: + virtual void SetUp() { + backup_old(); + } + + virtual void TearDown() { + restore_old(); + } }; class ApplyPatchFullTest : public ApplyPatchCacheTest { - public: - static void SetUpTestCase() { - ApplyPatchTest::SetUpTestCase(); + public: + static void SetUpTestCase() { + ApplyPatchTest::SetUpTestCase(); - output_f = new TemporaryFile(); - output_loc = std::string(output_f->path); + output_f = new TemporaryFile(); + output_loc = std::string(output_f->path); - struct FileContents fc; + struct FileContents fc; - ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc)); - patches.push_back( - std::make_unique(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); + ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc)); + patches.push_back( + std::make_unique(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); - ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc)); - patches.push_back( - std::make_unique(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); - } + ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc)); + patches.push_back( + std::make_unique(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); + } - static void TearDownTestCase() { - delete output_f; - } + static void TearDownTestCase() { + delete output_f; + patches.clear(); + } - static std::vector> patches; - static TemporaryFile* output_f; - static std::string output_loc; + static std::vector> 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(); - } + 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; @@ -193,203 +199,263 @@ TemporaryFile* ApplyPatchFullTest::output_f; std::string ApplyPatchFullTest::output_loc; TEST_F(ApplyPatchTest, CheckModeSkip) { - std::vector sha1s; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + std::vector sha1s; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeSingle) { - std::vector sha1s = { old_sha1 }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + std::vector sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeMultiple) { - std::vector sha1s = { - bad_sha1_a, - old_sha1, - bad_sha1_b - }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + std::vector sha1s = { bad_sha1_a, old_sha1, bad_sha1_b }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeFailure) { - std::vector sha1s = { - bad_sha1_a, - bad_sha1_b - }; - ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); + std::vector sha1s = { bad_sha1_a, bad_sha1_b }; + ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) { - mangle_file(old_file); - std::vector sha1s = { old_sha1 }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + mangle_file(old_file); + std::vector sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) { - mangle_file(old_file); - std::vector sha1s = { - bad_sha1_a, - old_sha1, - bad_sha1_b - }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + mangle_file(old_file); + std::vector sha1s = { bad_sha1_a, old_sha1, bad_sha1_b }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) { - mangle_file(old_file); - std::vector sha1s = { - bad_sha1_a, - bad_sha1_b - }; - ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); + mangle_file(old_file); + std::vector sha1s = { bad_sha1_a, bad_sha1_b }; + ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) { - unlink(&old_file[0]); - std::vector sha1s = { old_sha1 }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + unlink(&old_file[0]); + std::vector sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) { - unlink(&old_file[0]); - std::vector sha1s = { - bad_sha1_a, - old_sha1, - bad_sha1_b - }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + unlink(&old_file[0]); + std::vector sha1s = { bad_sha1_a, old_sha1, bad_sha1_b }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) { - unlink(&old_file[0]); - std::vector sha1s = { - bad_sha1_a, - bad_sha1_b - }; - ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); + unlink(&old_file[0]); + std::vector sha1s = { bad_sha1_a, bad_sha1_b }; + ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchFullTest, ApplyInPlace) { - std::vector sha1s = { - bad_sha1_a, - old_sha1 - }; - int ap_result = applypatch(&old_file[0], - "-", - &new_sha1[0], - new_size, - sha1s, - patches, - 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, - sha1s, - patches, - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(old_file, new_file)); + std::vector sha1s = { bad_sha1_a, old_sha1 }; + ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_TRUE(file_cmp(old_file, new_file)); + + // reapply, applypatch is idempotent so it should succeed + ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_TRUE(file_cmp(old_file, new_file)); } TEST_F(ApplyPatchFullTest, ApplyInNewLocation) { - std::vector sha1s = { - bad_sha1_a, - old_sha1 - }; - // Apply bsdiff patch to new location. - ASSERT_EQ(0, applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches, - nullptr)); - ASSERT_TRUE(file_cmp(output_loc, new_file)); - - // Reapply to the same location. - ASSERT_EQ(0, applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches, - nullptr)); - ASSERT_TRUE(file_cmp(output_loc, new_file)); + std::vector sha1s = { bad_sha1_a, old_sha1 }; + // Apply bsdiff patch to new location. + ASSERT_EQ( + 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_TRUE(file_cmp(output_loc, new_file)); + + // Reapply to the same location. + ASSERT_EQ( + 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_TRUE(file_cmp(output_loc, new_file)); } TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) { - std::vector sha1s = { - bad_sha1_a, - old_sha1 - }; - // Apply bsdiff patch to new location with corrupted source. - mangle_file(old_file); - int ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches, - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(output_loc, new_file)); - - // Reapply bsdiff patch to new location with corrupted source. - ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches, - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(output_loc, new_file)); + std::vector sha1s = { bad_sha1_a, old_sha1 }; + // Apply bsdiff patch to new location with corrupted source. + mangle_file(old_file); + ASSERT_EQ( + 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_TRUE(file_cmp(output_loc, new_file)); + + // Reapply bsdiff patch to new location with corrupted source. + ASSERT_EQ( + 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_TRUE(file_cmp(output_loc, new_file)); } TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) { - std::vector sha1s = { - bad_sha1_a, - old_sha1 - }; - - // Apply bsdiff patch to new location with corrupted source and copy (no new file). - // Expected to fail. - mangle_file(old_file); - mangle_file(cache_file); - int ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches, - nullptr); - ASSERT_NE(0, ap_result); - ASSERT_FALSE(file_cmp(output_loc, new_file)); - - // Expected to fail again on retry. - ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches, - nullptr); - ASSERT_NE(0, ap_result); - ASSERT_FALSE(file_cmp(output_loc, new_file)); - - // Expected to fail with incorrect new file. - mangle_file(output_loc); - ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches, - nullptr); - ASSERT_NE(0, ap_result); - ASSERT_FALSE(file_cmp(output_loc, new_file)); + std::vector sha1s = { bad_sha1_a, old_sha1 }; + + // Apply bsdiff patch to new location with corrupted source and copy (no new file). + // Expected to fail. + mangle_file(old_file); + mangle_file(cache_file); + ASSERT_NE( + 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_FALSE(file_cmp(output_loc, new_file)); + + // Expected to fail again on retry. + ASSERT_NE( + 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_FALSE(file_cmp(output_loc, new_file)); + + // Expected to fail with incorrect new file. + mangle_file(output_loc); + ASSERT_NE( + 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); + ASSERT_FALSE(file_cmp(output_loc, new_file)); +} + +TEST(ApplyPatchModes, InvalidArgs) { + // At least two args (including the filename). + ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" })); + + // Unrecognized args. + ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" })); +} + +TEST(ApplyPatchModes, PatchMode) { + std::string boot_img = from_testdata_base("boot.img"); + size_t boot_img_size; + std::string boot_img_sha1; + sha1sum(boot_img, &boot_img_sha1, &boot_img_size); + + std::string recovery_img = from_testdata_base("recovery.img"); + size_t recovery_img_size; + std::string recovery_img_sha1; + sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size); + + std::string bonus_file = from_testdata_base("bonus.file"); + + // applypatch -b : + TemporaryFile tmp1; + std::vector args = { + "applypatch", + "-b", + bonus_file.c_str(), + boot_img.c_str(), + tmp1.path, + recovery_img_sha1.c_str(), + std::to_string(recovery_img_size).c_str(), + (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str() + }; + ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); + + // applypatch : + TemporaryFile tmp2; + std::vector args2 = { + "applypatch", + boot_img.c_str(), + tmp2.path, + recovery_img_sha1.c_str(), + std::to_string(recovery_img_size).c_str(), + (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str() + }; + ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data())); + + // applypatch -b \ + // : : + TemporaryFile tmp3; + std::string bad_sha1_a = android::base::StringPrintf("%040x", rand()); + std::string bad_sha1_b = android::base::StringPrintf("%040x", rand()); + std::vector args3 = { + "applypatch", + "-b", + bonus_file.c_str(), + boot_img.c_str(), + tmp3.path, + recovery_img_sha1.c_str(), + std::to_string(recovery_img_size).c_str(), + (bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p")).c_str(), + (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str(), + (bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p")).c_str(), + }; + ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data())); +} + +TEST(ApplyPatchModes, PatchModeInvalidArgs) { + // Invalid bonus file. + ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" })); + + std::string bonus_file = from_testdata_base("bonus.file"); + // With bonus file, but missing args. + ASSERT_EQ(2, applypatch_modes(3, (const char* []){ "applypatch", "-b", bonus_file.c_str() })); + + std::string boot_img = from_testdata_base("boot.img"); + size_t boot_img_size; + std::string boot_img_sha1; + sha1sum(boot_img, &boot_img_sha1, &boot_img_size); + + std::string recovery_img = from_testdata_base("recovery.img"); + size_t recovery_img_size; + std::string recovery_img_sha1; + sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size); + + // Bonus file is not supported in flash mode. + // applypatch -b + TemporaryFile tmp4; + std::vector args4 = { + "applypatch", + "-b", + bonus_file.c_str(), + boot_img.c_str(), + tmp4.path, + recovery_img_sha1.c_str(), + std::to_string(recovery_img_size).c_str() }; + ASSERT_NE(0, applypatch_modes(args4.size(), args4.data())); + + // Failed to parse patch args. + TemporaryFile tmp5; + std::vector args5 = { + "applypatch", + boot_img.c_str(), + tmp5.path, + recovery_img_sha1.c_str(), + std::to_string(recovery_img_size).c_str(), + ("invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str(), + }; + ASSERT_NE(0, applypatch_modes(args5.size(), args5.data())); + + // Target size cannot be zero. + TemporaryFile tmp6; + std::vector args6 = { + "applypatch", + boot_img.c_str(), + tmp6.path, + recovery_img_sha1.c_str(), + "0", // target size + (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str() + }; + ASSERT_NE(0, applypatch_modes(args6.size(), args6.data())); +} + +TEST(ApplyPatchModes, CheckModeInvalidArgs) { + // Insufficient args. + ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" })); +} + +TEST(ApplyPatchModes, SpaceModeInvalidArgs) { + // Insufficient args. + ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-s" })); + + // Invalid bytes arg. + ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "x" })); + + // 0 is invalid. + ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0" })); + + // 0x10 is fine. + ASSERT_EQ(0, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0x10" })); +} + +TEST(ApplyPatchModes, ShowLicenses) { + ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" })); } diff --git a/tests/testdata/bonus.file b/tests/testdata/bonus.file new file mode 100644 index 000000000..918ef8ac5 Binary files /dev/null and b/tests/testdata/bonus.file differ diff --git a/tests/testdata/boot.img b/tests/testdata/boot.img new file mode 100644 index 000000000..dd4897510 Binary files /dev/null and b/tests/testdata/boot.img differ diff --git a/tests/testdata/recovery-from-boot-with-bonus.p b/tests/testdata/recovery-from-boot-with-bonus.p new file mode 100644 index 000000000..08b6f55e4 Binary files /dev/null and b/tests/testdata/recovery-from-boot-with-bonus.p differ diff --git a/tests/testdata/recovery-from-boot.p b/tests/testdata/recovery-from-boot.p new file mode 100644 index 000000000..06f6c299f Binary files /dev/null and b/tests/testdata/recovery-from-boot.p differ diff --git a/tests/testdata/recovery.img b/tests/testdata/recovery.img new file mode 100644 index 000000000..b862e6f0c Binary files /dev/null and b/tests/testdata/recovery.img differ -- cgit v1.2.3 From 4102b281324eca22cd4ef0922a79949ec6cf846e Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 2 Nov 2016 16:17:17 -0700 Subject: tests: Set up testdata path for continuous native tests. continuous_native_tests expects the testdata under DATA/ in continuous_native_tests.zip. This CL packs a copy of the testdata into continuous_native_tests.zip as DATA/nativetest/recovery/testdata (via LOCAL_PICKUP_FILES). This CL also removes the extra copy for nativetest64. Testdata will always stay at /data/nativetest/recovery/testdata, even for 64-bit version. Otherwise we will unnecessarily get four copies (two for data/ and another two for DATA/). Bug: 32123241 Test: mmma bootable/recovery && adb sync data. On bullhead, /data/nativetest/recovery_component_test/recovery_component_test works; /data/nativetest64/recovery_component_test/recovery_component_test works. Test: m continuous_native_test; DATA/nativetest/recovery/testdata exists. Change-Id: Ifefa0309de7af23c77654e8e450848ca2da218c2 --- tests/Android.mk | 21 ++++++++++++--------- tests/common/test_constants.h | 15 +++++++++------ tests/component/applypatch_test.cpp | 7 ------- tests/component/verifier_test.cpp | 11 ++--------- 4 files changed, 23 insertions(+), 31 deletions(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 461d6ef76..8f19992b6 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -87,7 +87,8 @@ LOCAL_STATIC_LIBRARIES := \ testdata_files := $(call find-subdir-files, testdata/*) -testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery +# The testdata files that will go to $OUT/data/nativetest/recovery. +testdata_out_path := $(TARGET_OUT_DATA)/nativetest/recovery GEN := $(addprefix $(testdata_out_path)/, $(testdata_files)) $(GEN): PRIVATE_PATH := $(LOCAL_PATH) $(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@ @@ -95,14 +96,16 @@ $(GEN): $(testdata_out_path)/% : $(LOCAL_PATH)/% $(transform-generated-source) LOCAL_GENERATED_SOURCES += $(GEN) -ifdef TARGET_2ND_ARCH -testdata_out_path_2nd_arch := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/recovery -GEN_2ND_ARCH := $(addprefix $(testdata_out_path_2nd_arch)/, $(testdata_files)) -$(GEN_2ND_ARCH): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN_2ND_ARCH): PRIVATE_CUSTOM_TOOL = cp $< $@ -$(GEN_2ND_ARCH): $(testdata_out_path_2nd_arch)/% : $(LOCAL_PATH)/% +# A copy of the testdata to be packed into continuous_native_tests.zip. +testdata_continuous_zip_prefix := \ + $(call intermediates-dir-for,PACKAGING,recovery_component_test)/DATA +testdata_continuous_zip_path := $(testdata_continuous_zip_prefix)/nativetest/recovery +GEN := $(addprefix $(testdata_continuous_zip_path)/, $(testdata_files)) +$(GEN): PRIVATE_PATH := $(LOCAL_PATH) +$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@ +$(GEN): $(testdata_continuous_zip_path)/% : $(LOCAL_PATH)/% $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN_2ND_ARCH) -endif # TARGET_2ND_ARCH +LOCAL_GENERATED_SOURCES += $(GEN) +LOCAL_PICKUP_FILES := $(testdata_continuous_zip_prefix) include $(BUILD_NATIVE_TEST) diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h index 3490f6805..97e74a3c2 100644 --- a/tests/common/test_constants.h +++ b/tests/common/test_constants.h @@ -13,13 +13,16 @@ * 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 +#include + +static const char* data_root = getenv("ANDROID_DATA"); + +static std::string from_testdata_base(const std::string& fname) { + return std::string(data_root) + "/nativetest/recovery/testdata/" + fname; +} -#endif +#endif // _OTA_TEST_CONSTANTS_H diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index f95ebed5d..1a0b19113 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -37,9 +37,6 @@ #include "common/test_constants.h" #include "print_sha1.h" -static const std::string DATA_PATH = getenv("ANDROID_DATA"); -static const std::string TESTDATA_PATH = "/recovery/testdata"; - static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) { ASSERT_NE(nullptr, sha1); @@ -72,10 +69,6 @@ static bool file_cmp(const std::string& f1, const std::string& f2) { return c1 == c2; } -static std::string from_testdata_base(const std::string& fname) { - return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname; -} - class ApplyPatchTest : public ::testing::Test { public: static void SetUpTestCase() { diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 7f9a71408..60a78f5c3 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -37,9 +37,6 @@ #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 { @@ -92,17 +89,13 @@ class VerifierTest : public testing::TestWithParam> { virtual void SetUp() { std::vector args = GetParam(); - std::string package = - android::base::StringPrintf("%s%s%s%s", DATA_PATH, NATIVE_TEST_PATH, - TESTDATA_PATH, args[0].c_str()); + std::string package = from_testdata_base(args[0]); if (sysMapFile(package.c_str(), &memmap) != 0) { FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n"; } for (auto it = ++(args.cbegin()); it != args.cend(); ++it) { - std::string public_key_file = android::base::StringPrintf( - "%s%s%stestkey_%s.txt", DATA_PATH, NATIVE_TEST_PATH, - TESTDATA_PATH, it->c_str()); + std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt"); ASSERT_TRUE(load_keys(public_key_file.c_str(), certs)); } } -- cgit v1.2.3 From 51d516e913753a3a1416130b215591e309f0eb2c Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 14:49:01 -0700 Subject: updater: Fix an off-by-1 bug in file_getprop(). Also add a testcase for file_getprop(). Test: recovery_component_test passes. Change-Id: I8eb2f9a5702b43997ac9f4b29665eea087b1c146 --- tests/component/updater_test.cpp | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index a859f11c1..bd1df558e 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -16,7 +16,9 @@ #include +#include #include +#include #include #include "edify/expr.h" @@ -97,3 +99,51 @@ TEST_F(UpdaterTest, sha1_check) { // sha1_check() expects at least one argument. expect(nullptr, "sha1_check()", kArgsParsingFailure); } + +TEST_F(UpdaterTest, file_getprop) { + // file_getprop() expects two arguments. + expect(nullptr, "file_getprop()", kArgsParsingFailure); + expect(nullptr, "file_getprop(\"arg1\")", kArgsParsingFailure); + expect(nullptr, "file_getprop(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + // File doesn't exist. + expect(nullptr, "file_getprop(\"/doesntexist\", \"key1\")", kFileGetPropFailure); + + // Reject too large files (current limit = 65536). + TemporaryFile temp_file1; + std::string buffer(65540, '\0'); + ASSERT_TRUE(android::base::WriteStringToFile(buffer, temp_file1.path)); + + // Read some keys. + TemporaryFile temp_file2; + std::string content("ro.product.name=tardis\n" + "# comment\n\n\n" + "ro.product.model\n" + "ro.product.board = magic \n"); + ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file2.path)); + + std::string script1("file_getprop(\"" + std::string(temp_file2.path) + + "\", \"ro.product.name\")"); + expect("tardis", script1.c_str(), kNoCause); + + std::string script2("file_getprop(\"" + std::string(temp_file2.path) + + "\", \"ro.product.board\")"); + expect("magic", script2.c_str(), kNoCause); + + // No match. + std::string script3("file_getprop(\"" + std::string(temp_file2.path) + + "\", \"ro.product.wrong\")"); + expect("", script3.c_str(), kNoCause); + + std::string script4("file_getprop(\"" + std::string(temp_file2.path) + + "\", \"ro.product.name=\")"); + expect("", script4.c_str(), kNoCause); + + std::string script5("file_getprop(\"" + std::string(temp_file2.path) + + "\", \"ro.product.nam\")"); + expect("", script5.c_str(), kNoCause); + + std::string script6("file_getprop(\"" + std::string(temp_file2.path) + + "\", \"ro.product.model\")"); + expect("", script6.c_str(), kNoCause); +} -- cgit v1.2.3 From 0831d0b592b2b4abb317a785d0b27e443b8a83db Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 23:25:04 -0700 Subject: updater: Fix a bug in DeleteFn(). Also add a testcase for delete() function. Test: recovery_component_test passes. Change-Id: I064d1ad4693c3ed339d0a69eabadd08a61a2ea86 --- tests/component/updater_test.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index bd1df558e..337769e6b 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -147,3 +147,36 @@ TEST_F(UpdaterTest, file_getprop) { "\", \"ro.product.model\")"); expect("", script6.c_str(), kNoCause); } + +TEST_F(UpdaterTest, delete) { + // Delete none. + expect("0", "delete()", kNoCause); + expect("0", "delete(\"/doesntexist\")", kNoCause); + expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\")", kNoCause); + expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\", \"/doesntexist3\")", kNoCause); + + // Delete one file. + TemporaryFile temp_file1; + ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); + std::string script1("delete(\"" + std::string(temp_file1.path) + "\")"); + expect("1", script1.c_str(), kNoCause); + + // Delete two files. + TemporaryFile temp_file2; + ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file2.path)); + TemporaryFile temp_file3; + ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file3.path)); + std::string script2("delete(\"" + std::string(temp_file2.path) + "\", \"" + + std::string(temp_file3.path) + "\")"); + expect("2", script2.c_str(), kNoCause); + + // Delete already deleted files. + expect("0", script2.c_str(), kNoCause); + + // Delete one out of three. + TemporaryFile temp_file4; + ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file4.path)); + std::string script3("delete(\"/doesntexist1\", \"" + std::string(temp_file4.path) + + "\", \"/doesntexist2\")"); + expect("1", script3.c_str(), kNoCause); +} -- cgit v1.2.3 From a659d79b923cfce21f13519747d2f16048290849 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 23:25:04 -0700 Subject: updater: Add a testcase for RenameFn(). Test: recovery_component_test passes. Change-Id: Iba5a0fdf6c79e2bed6b30b8fc19a306c1ab29d8a --- tests/component/updater_test.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index 337769e6b..f922933cd 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -180,3 +180,32 @@ TEST_F(UpdaterTest, delete) { "\", \"/doesntexist2\")"); expect("1", script3.c_str(), kNoCause); } + +TEST_F(UpdaterTest, rename) { + // rename() expects two arguments. + expect(nullptr, "rename()", kArgsParsingFailure); + expect(nullptr, "rename(\"arg1\")", kArgsParsingFailure); + expect(nullptr, "rename(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + // src_name or dst_name cannot be empty. + expect(nullptr, "rename(\"\", \"arg2\")", kArgsParsingFailure); + expect(nullptr, "rename(\"arg1\", \"\")", kArgsParsingFailure); + + // File doesn't exist (both of src and dst). + expect(nullptr, "rename(\"/doesntexist\", \"/doesntexisteither\")" , kFileRenameFailure); + + // Can't create parent directory. + TemporaryFile temp_file1; + ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); + std::string script1("rename(\"" + std::string(temp_file1.path) + "\", \"/proc/0/file1\")"); + expect(nullptr, script1.c_str(), kFileRenameFailure); + + // Rename. + TemporaryFile temp_file2; + std::string script2("rename(\"" + std::string(temp_file1.path) + "\", \"" + + std::string(temp_file2.path) + "\")"); + expect(temp_file2.path, script2.c_str(), kNoCause); + + // Already renamed. + expect(temp_file2.path, script2.c_str(), kNoCause); +} -- cgit v1.2.3 From 0dfb7536bb3b923bc4378002ecc0da871c6de01f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 4 Nov 2016 15:15:52 -0700 Subject: tests: Fix unit/zip_test.cpp. It's accidentally broken when refactoring the testdata path. Also clean up the testcase a bit by simplying the file reading. Test: recovery_unit_test passes. Change-Id: I592a1cf5a4eb9a7a5f4eecbc6426baeedeb02781 --- tests/unit/zip_test.cpp | 109 ++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 59 deletions(-) (limited to 'tests') diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp index b617446b8..49729467d 100644 --- a/tests/unit/zip_test.cpp +++ b/tests/unit/zip_test.cpp @@ -16,78 +16,69 @@ #include #include -#include #include #include #include #include -#include -#include #include #include #include #include #include -static const std::string DATA_PATH(getenv("ANDROID_DATA")); -static const std::string TESTDATA_PATH("/recovery/testdata/"); - -static const std::vector kATxtContents { - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - '\n' -}; - -static const std::vector kBTxtContents { - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - '\n' -}; - -TEST(otazip, ExtractPackageRecursive) { - TemporaryDir td; - ASSERT_NE(td.path, nullptr); - ZipArchiveHandle handle; - std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_valid.zip"; - ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); - // Extract the whole package into a temp directory. - ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr); - // Make sure all the files are extracted correctly. - std::string path(td.path); - android::base::unique_fd fd(open((path + "/a.txt").c_str(), O_RDONLY)); - ASSERT_NE(fd, -1); - std::vector read_data; - read_data.resize(kATxtContents.size()); - // The content of the file is the same as expected. - ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size())); - ASSERT_EQ(0, memcmp(read_data.data(), kATxtContents.data(), kATxtContents.size())); - - fd.reset(open((path + "/b.txt").c_str(), O_RDONLY)); - ASSERT_NE(fd, -1); - fd.reset(open((path + "/b/c.txt").c_str(), O_RDONLY)); - ASSERT_NE(fd, -1); - fd.reset(open((path + "/b/d.txt").c_str(), O_RDONLY)); - ASSERT_NE(fd, -1); - read_data.resize(kBTxtContents.size()); - ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size())); - ASSERT_EQ(0, memcmp(read_data.data(), kBTxtContents.data(), kBTxtContents.size())); +#include "common/test_constants.h" + +static const std::string kATxtContents("abcdefghabcdefgh\n"); +static const std::string kBTxtContents("abcdefgh\n"); + +TEST(ZipTest, ExtractPackageRecursive) { + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // Extract the whole package into a temp directory. + TemporaryDir td; + ASSERT_NE(nullptr, td.path); + ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr); + + // Make sure all the files are extracted correctly. + std::string path(td.path); + ASSERT_EQ(0, access((path + "/a.txt").c_str(), O_RDONLY)); + ASSERT_EQ(0, access((path + "/b.txt").c_str(), O_RDONLY)); + ASSERT_EQ(0, access((path + "/b/c.txt").c_str(), O_RDONLY)); + ASSERT_EQ(0, access((path + "/b/d.txt").c_str(), O_RDONLY)); + + // The content of the file is the same as expected. + std::string content1; + ASSERT_TRUE(android::base::ReadFileToString(path + "/a.txt", &content1)); + ASSERT_EQ(kATxtContents, content1); + + std::string content2; + ASSERT_TRUE(android::base::ReadFileToString(path + "/b/d.txt", &content2)); + ASSERT_EQ(kBTxtContents, content2); } -TEST(otazip, OpenFromMemory) { - MemMapping map; - std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_dummy-update.zip"; - ASSERT_EQ(0, sysMapFile(zip_path.c_str(), &map)); - // Map an update package into memory and open the archive from there. - ZipArchiveHandle handle; - ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_path.c_str(), &handle)); - static constexpr const char* BINARY_PATH = "META-INF/com/google/android/update-binary"; - ZipString binary_path(BINARY_PATH); - ZipEntry binary_entry; - // Make sure the package opens correctly and its entry can be read. - ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry)); - TemporaryFile tmp_binary; - ASSERT_NE(-1, tmp_binary.fd); - ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd)); +TEST(ZipTest, OpenFromMemory) { + MemMapping map; + std::string zip_path = from_testdata_base("ziptest_dummy-update.zip"); + ASSERT_EQ(0, sysMapFile(zip_path.c_str(), &map)); + + // Map an update package into memory and open the archive from there. + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_path.c_str(), &handle)); + + static constexpr const char* BINARY_PATH = "META-INF/com/google/android/update-binary"; + ZipString binary_path(BINARY_PATH); + ZipEntry binary_entry; + // Make sure the package opens correctly and its entry can be read. + ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry)); + + TemporaryFile tmp_binary; + ASSERT_NE(-1, tmp_binary.fd); + ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd)); + + sysReleaseMap(&map); } -- cgit v1.2.3 From c3292f3fcbb3cd608cc19b7459751fa5bb64ab84 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 4 Nov 2016 10:52:13 -0700 Subject: otautil: Clean up SysUtil.cpp. Add unit testcases for sysMapFile(). Test: recovery_unit_test passes. Test: Build and use the new recovery image to sideload a package. Test: Build and use the new recovery image to install an update. Change-Id: I77d8f1ea151ab513865d992c256ba93a1fcb51a4 --- tests/Android.mk | 13 ++-- tests/unit/sysutil_test.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 tests/unit/sysutil_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 8f19992b6..86591f71d 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -18,7 +18,6 @@ LOCAL_PATH := $(call my-dir) # Unit tests include $(CLEAR_VARS) -LOCAL_CLANG := true LOCAL_CFLAGS := -Werror LOCAL_MODULE := recovery_unit_test LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk @@ -32,17 +31,19 @@ LOCAL_STATIC_LIBRARIES := \ libselinux \ libbase -LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp -LOCAL_SRC_FILES += unit/recovery_test.cpp -LOCAL_SRC_FILES += unit/locale_test.cpp -LOCAL_SRC_FILES += unit/zip_test.cpp +LOCAL_SRC_FILES := \ + unit/asn1_decoder_test.cpp \ + unit/locale_test.cpp \ + unit/recovery_test.cpp \ + unit/sysutil_test.cpp \ + unit/zip_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 := -Werror LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := recovery_component_test diff --git a/tests/unit/sysutil_test.cpp b/tests/unit/sysutil_test.cpp new file mode 100644 index 000000000..f4699664b --- /dev/null +++ b/tests/unit/sysutil_test.cpp @@ -0,0 +1,140 @@ +/* + * Copyright 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 + +#include + +#include +#include + +#include "otautil/SysUtil.h" + +TEST(SysUtilTest, InvalidArgs) { + MemMapping mapping; + + // Invalid argument. + ASSERT_EQ(-1, sysMapFile(nullptr, &mapping)); + ASSERT_EQ(-1, sysMapFile("/somefile", nullptr)); +} + +TEST(SysUtilTest, sysMapFileRegularFile) { + TemporaryFile temp_file1; + std::string content = "abc"; + ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file1.path)); + + // sysMapFile() should map the file to one range. + MemMapping mapping; + ASSERT_EQ(0, sysMapFile(temp_file1.path, &mapping)); + ASSERT_NE(nullptr, mapping.addr); + ASSERT_EQ(content.size(), mapping.length); + ASSERT_EQ(1U, mapping.ranges.size()); + + sysReleaseMap(&mapping); + ASSERT_EQ(0U, mapping.ranges.size()); +} + +TEST(SysUtilTest, sysMapFileBlockMap) { + // Create a file that has 10 blocks. + TemporaryFile package; + std::string content; + constexpr size_t file_size = 4096 * 10; + content.reserve(file_size); + ASSERT_TRUE(android::base::WriteStringToFile(content, package.path)); + + TemporaryFile block_map_file; + std::string filename = std::string("@") + block_map_file.path; + MemMapping mapping; + + // One range. + std::string block_map_content = std::string(package.path) + "\n40960 4096\n1\n0 10\n"; + ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path)); + + ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping)); + ASSERT_EQ(file_size, mapping.length); + ASSERT_EQ(1U, mapping.ranges.size()); + + // It's okay to not have the trailing '\n'. + block_map_content = std::string(package.path) + "\n40960 4096\n1\n0 10"; + ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path)); + + ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping)); + ASSERT_EQ(file_size, mapping.length); + ASSERT_EQ(1U, mapping.ranges.size()); + + // Or having multiple trailing '\n's. + block_map_content = std::string(package.path) + "\n40960 4096\n1\n0 10\n\n\n"; + ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path)); + + ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping)); + ASSERT_EQ(file_size, mapping.length); + ASSERT_EQ(1U, mapping.ranges.size()); + + // Multiple ranges. + block_map_content = std::string(package.path) + "\n40960 4096\n3\n0 3\n3 5\n5 10\n"; + ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path)); + + ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping)); + ASSERT_EQ(file_size, mapping.length); + ASSERT_EQ(3U, mapping.ranges.size()); + + sysReleaseMap(&mapping); + ASSERT_EQ(0U, mapping.ranges.size()); +} + +TEST(SysUtilTest, sysMapFileBlockMapInvalidBlockMap) { + MemMapping mapping; + TemporaryFile temp_file; + std::string filename = std::string("@") + temp_file.path; + + // Block map file is too short. + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n0\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + // Block map file has unexpected number of lines. + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n2\n0 1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + // Invalid size/blksize/range_count. + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\nabc 4096\n1\n0 1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n\n0 1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + // size/blksize/range_count don't match. + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n0 4096\n1\n0 1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 0\n1\n0 1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n0\n0 1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + // Invalid block dev path. + ASSERT_TRUE(android::base::WriteStringToFile("/doesntexist\n4096 4096\n1\n0 1\n", temp_file.path)); + ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping)); + + sysReleaseMap(&mapping); + ASSERT_EQ(0U, mapping.ranges.size()); +} -- cgit v1.2.3 From d75003d24c6e33befe041dd0cad7be3df199636c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 4 Nov 2016 11:31:29 -0700 Subject: Make make_parent() to take const argument Switch to use const std::string; and add corresponding tests. Bug: 32649858 Test: Component tests pass Change-Id: I640f3ec81f1481fa91aa310f8d4d96dac9649cb9 --- tests/component/updater_test.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index f922933cd..acc2b4040 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -208,4 +208,26 @@ TEST_F(UpdaterTest, rename) { // Already renamed. expect(temp_file2.path, script2.c_str(), kNoCause); + + // Parents create successfully. + TemporaryFile temp_file3; + TemporaryDir td; + std::string temp_dir = std::string(td.path) + "/aaa/bbb/a.txt"; + std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + + temp_dir + "\")"); + expect(temp_dir.c_str(), script3.c_str(), kNoCause); +} + +TEST_F(UpdaterTest, symlink) { + // symlink expects 1+ argument. + expect(nullptr, "symlink()", kArgsParsingFailure); + + // symlink should fail if src is an empty string. + TemporaryFile temp_file1; + std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")"); + expect(nullptr, script1.c_str(), kSymlinkFailure); + + // symlink failed to remove old src. + std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")"); + expect(nullptr, script2.c_str(), kSymlinkFailure); } -- cgit v1.2.3 From 5d8b53b248ac56cb8280d2d2d653f12c43a26abd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 7 Nov 2016 14:45:59 -0800 Subject: Move recovery_test.cpp out of unit test Move recovery-refresh/persist tests out because these tests need special steps to run. Also switch the constants to std::string. Test: recovery_manual_test passed on an A/B device Change-Id: I60b3ec6f094044945c3aafc1fae540896a6ddea6 --- tests/Android.mk | 13 +++++- tests/manual/recovery_test.cpp | 87 ++++++++++++++++++++++++++++++++++++++++ tests/unit/recovery_test.cpp | 91 ------------------------------------------ 3 files changed, 99 insertions(+), 92 deletions(-) create mode 100644 tests/manual/recovery_test.cpp delete mode 100644 tests/unit/recovery_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 86591f71d..e87a22964 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -34,7 +34,6 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_SRC_FILES := \ unit/asn1_decoder_test.cpp \ unit/locale_test.cpp \ - unit/recovery_test.cpp \ unit/sysutil_test.cpp \ unit/zip_test.cpp @@ -42,6 +41,18 @@ LOCAL_C_INCLUDES := bootable/recovery LOCAL_SHARED_LIBRARIES := liblog include $(BUILD_NATIVE_TEST) +# Manual tests +include $(CLEAR_VARS) +LOCAL_CLANG := true +LOCAL_CFLAGS := -Werror +LOCAL_MODULE := recovery_manual_test +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_STATIC_LIBRARIES := libbase + +LOCAL_SRC_FILES := manual/recovery_test.cpp +LOCAL_SHARED_LIBRARIES := liblog +include $(BUILD_NATIVE_TEST) + # Component tests include $(CLEAR_VARS) LOCAL_CFLAGS := -Werror diff --git a/tests/manual/recovery_test.cpp b/tests/manual/recovery_test.cpp new file mode 100644 index 000000000..e83849546 --- /dev/null +++ b/tests/manual/recovery_test.cpp @@ -0,0 +1,87 @@ +/* + * 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 +#include +#include +#include + +#include + +#include +#include +#include +#include + +static const std::string myFilename = "/data/misc/recovery/inject.txt"; +static const std::string 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_NE(std::string::npos, myFilename.find(filename)); + EXPECT_EQ(myContent, buf); + EXPECT_EQ(myContent.size(), len); + EXPECT_EQ(nullptr, 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, nullptr); + if (ret == -ENOENT) { + EXPECT_LT(0, __android_log_pmsg_file_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO, + myFilename.c_str(), myContent.c_str(), myContent.size())); + + fprintf(stderr, "injected test data, requires two intervening reboots " + "to check for replication\n"); + } + EXPECT_EQ(static_cast(myContent.size()), 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, nullptr); + if (ret == -ENOENT) { + EXPECT_LT(0, __android_log_pmsg_file_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO, + myFilename.c_str(), myContent.c_str(), myContent.size())); + + fprintf(stderr, "injected test data, requires intervening reboot " + "to check for storage\n"); + } + + std::string buf; + EXPECT_TRUE(android::base::ReadFileToString(myFilename, &buf)); + EXPECT_EQ(myContent, buf); + if (access(myFilename.c_str(), O_RDONLY) == 0) { + fprintf(stderr, "Removing persistent test data, " + "check if reconstructed on reboot\n"); + } + EXPECT_EQ(0, unlink(myFilename.c_str())); +} diff --git a/tests/unit/recovery_test.cpp b/tests/unit/recovery_test.cpp deleted file mode 100644 index 28b845fb9..000000000 --- a/tests/unit/recovery_test.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 -#include -#include -#include - -#include -#include -#include - -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)); -} -- cgit v1.2.3 From 8992902aab88b26b383d95dd7b35c17934b069d5 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 8 Nov 2016 20:51:31 -0800 Subject: updater: Add more testcase for symlink(). Clean up SymlinkFn() a bit. Also clean up the temp files created when running the tests; otherwise non-empty TemporaryDir won't be removed. Test: recovery_component_test passes. Change-Id: Id3844abebd168c40125c4dcec54e6ef680a83c3a --- tests/component/updater_test.cpp | 45 ++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index acc2b4040..973c19de3 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#include +#include +#include + #include #include @@ -212,10 +216,15 @@ TEST_F(UpdaterTest, rename) { // Parents create successfully. TemporaryFile temp_file3; TemporaryDir td; - std::string temp_dir = std::string(td.path) + "/aaa/bbb/a.txt"; - std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + - temp_dir + "\")"); - expect(temp_dir.c_str(), script3.c_str(), kNoCause); + std::string temp_dir(td.path); + std::string dst_file = temp_dir + "/aaa/bbb/a.txt"; + std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + dst_file + "\")"); + expect(dst_file.c_str(), script3.c_str(), kNoCause); + + // Clean up the temp files under td. + ASSERT_EQ(0, unlink(dst_file.c_str())); + ASSERT_EQ(0, rmdir((temp_dir + "/aaa/bbb").c_str())); + ASSERT_EQ(0, rmdir((temp_dir + "/aaa").c_str())); } TEST_F(UpdaterTest, symlink) { @@ -227,7 +236,31 @@ TEST_F(UpdaterTest, symlink) { std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")"); expect(nullptr, script1.c_str(), kSymlinkFailure); - // symlink failed to remove old src. - std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")"); + std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"src1\", \"\")"); expect(nullptr, script2.c_str(), kSymlinkFailure); + + // symlink failed to remove old src. + std::string script3("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")"); + expect(nullptr, script3.c_str(), kSymlinkFailure); + + // symlink can create symlinks. + TemporaryFile temp_file; + std::string content = "magicvalue"; + ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file.path)); + + TemporaryDir td; + std::string src1 = std::string(td.path) + "/symlink1"; + std::string src2 = std::string(td.path) + "/symlink2"; + std::string script4("symlink(\"" + std::string(temp_file.path) + "\", \"" + + src1 + "\", \"" + src2 + "\")"); + expect("t", script4.c_str(), kNoCause); + + // Verify the created symlinks. + struct stat sb; + ASSERT_TRUE(lstat(src1.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); + ASSERT_TRUE(lstat(src2.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); + + // Clean up the leftovers. + ASSERT_EQ(0, unlink(src1.c_str())); + ASSERT_EQ(0, unlink(src2.c_str())); } -- cgit v1.2.3 From ef0eb3b01b66fbbc97908667a3dd1e02d710cbb7 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 14 Nov 2016 21:29:52 -0800 Subject: updater: Fix the wrong return value for package_extract_file(). 'bool success = ExtractEntryToFile()' gives opposite result. Fix the issue and add testcases. Change the one-argument version of package_extract_file() to explicitly abort for non-existent zip entry. Note that this is NOT changing the behavior. Prior to this CL, it aborts from Evaluate() function, by giving a general cause code. Now it returns kPackageExtractFileFailure. BUg: 32903624 Test: recovery_component_test works. Change-Id: I7a273e9c0d9aaaf8c472b2c778f7b8d90362c24f --- tests/Android.mk | 2 + tests/common/test_constants.h | 9 ++++ tests/component/updater_test.cpp | 92 ++++++++++++++++++++++++++++++++-------- tests/unit/zip_test.cpp | 3 -- 4 files changed, 86 insertions(+), 20 deletions(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index e87a22964..fdc947028 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -92,6 +92,8 @@ LOCAL_STATIC_LIBRARIES := \ libcrypto \ libcutils \ libbz \ + libziparchive \ + libutils \ libz \ libbase \ libtune2fs \ diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h index 97e74a3c2..93e4ab5b2 100644 --- a/tests/common/test_constants.h +++ b/tests/common/test_constants.h @@ -19,6 +19,15 @@ #include +// Zip entries in ziptest_valid.zip. +static const std::string kATxtContents("abcdefghabcdefgh\n"); +static const std::string kBTxtContents("abcdefgh\n"); + +// echo -n -e "abcdefghabcdefgh\n" | sha1sum +static const std::string kATxtSha1Sum("32c96a03dc8cd20097940f351bca6261ee5a1643"); +// echo -n -e "abcdefgh\n" | sha1sum +static const std::string kBTxtSha1Sum("e414af7161c9554089f4106d6f1797ef14a73666"); + static const char* data_root = getenv("ANDROID_DATA"); static std::string from_testdata_base(const std::string& fname) { diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index 973c19de3..a029cf449 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -24,35 +24,40 @@ #include #include #include +#include +#include "common/test_constants.h" #include "edify/expr.h" #include "error_code.h" #include "updater/install.h" +#include "updater/updater.h" struct selabel_handle *sehandle = nullptr; -static void expect(const char* expected, const char* expr_str, CauseCode cause_code) { - Expr* e; - int error_count; - EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0); +static void expect(const char* expected, const char* expr_str, CauseCode cause_code, + UpdaterInfo* info = nullptr) { + Expr* e; + int error_count = 0; + ASSERT_EQ(0, parse_string(expr_str, &e, &error_count)); + ASSERT_EQ(0, error_count); - State state(expr_str, nullptr); + State state(expr_str, info); - std::string result; - bool status = Evaluate(&state, e, &result); + std::string result; + bool status = Evaluate(&state, e, &result); - if (expected == nullptr) { - EXPECT_FALSE(status); - } else { - EXPECT_STREQ(expected, result.c_str()); - } - - // Error code is set in updater/updater.cpp only, by parsing State.errmsg. - EXPECT_EQ(kNoError, state.error_code); + if (expected == nullptr) { + ASSERT_FALSE(status); + } else { + ASSERT_TRUE(status); + ASSERT_STREQ(expected, result.c_str()); + } - // Cause code should always be available. - EXPECT_EQ(cause_code, state.cause_code); + // Error code is set in updater/updater.cpp only, by parsing State.errmsg. + ASSERT_EQ(kNoError, state.error_code); + // Cause code should always be available. + ASSERT_EQ(cause_code, state.cause_code); } class UpdaterTest : public ::testing::Test { @@ -264,3 +269,56 @@ TEST_F(UpdaterTest, symlink) { ASSERT_EQ(0, unlink(src1.c_str())); ASSERT_EQ(0, unlink(src2.c_str())); } + +// TODO: Test extracting to block device. +TEST_F(UpdaterTest, package_extract_file) { + // package_extract_file expects 1 or 2 arguments. + expect(nullptr, "package_extract_file()", kArgsParsingFailure); + expect(nullptr, "package_extract_file(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // Need to set up the ziphandle. + UpdaterInfo updater_info; + updater_info.package_zip = handle; + + // Two-argument version. + TemporaryFile temp_file1; + std::string script("package_extract_file(\"a.txt\", \"" + std::string(temp_file1.path) + "\")"); + expect("t", script.c_str(), kNoCause, &updater_info); + + // Verify the extracted entry. + std::string data; + ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data)); + ASSERT_EQ(kATxtContents, data); + + // Now extract another entry to the same location, which should overwrite. + script = "package_extract_file(\"b.txt\", \"" + std::string(temp_file1.path) + "\")"; + expect("t", script.c_str(), kNoCause, &updater_info); + + ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data)); + ASSERT_EQ(kBTxtContents, data); + + // Missing zip entry. The two-argument version doesn't abort. + script = "package_extract_file(\"doesntexist\", \"" + std::string(temp_file1.path) + "\")"; + expect("", script.c_str(), kNoCause, &updater_info); + + // Extract to /dev/full should fail. + script = "package_extract_file(\"a.txt\", \"/dev/full\")"; + expect("", script.c_str(), kNoCause, &updater_info); + + // One-argument version. + script = "sha1_check(package_extract_file(\"a.txt\"))"; + expect(kATxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info); + + script = "sha1_check(package_extract_file(\"b.txt\"))"; + expect(kBTxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info); + + // Missing entry. The one-argument version aborts the evaluation. + script = "package_extract_file(\"doesntexist\")"; + expect(nullptr, script.c_str(), kPackageExtractFileFailure, &updater_info); + + CloseArchive(handle); +} diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp index 49729467d..ef0ee4c1d 100644 --- a/tests/unit/zip_test.cpp +++ b/tests/unit/zip_test.cpp @@ -30,9 +30,6 @@ #include "common/test_constants.h" -static const std::string kATxtContents("abcdefghabcdefgh\n"); -static const std::string kBTxtContents("abcdefgh\n"); - TEST(ZipTest, ExtractPackageRecursive) { std::string zip_path = from_testdata_base("ziptest_valid.zip"); ZipArchiveHandle handle; -- cgit v1.2.3 From d0f3088aa95e255b39ed4b83da6b08866c2c3e0c Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 23:52:01 -0700 Subject: updater: Add "write_value()" function. write_value(value, filename) writes 'value' to 'filename'. It can be used to tune device settings when applying an OTA package. For example, write_value("960000", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"). Bug: 32463933 Test: recovery_component_test passes. Test: Apply an OTA package that contains a call to write_value(), and check the result. Change-Id: Ib009ecb8a45a94353f10c59e2383fe1f49796e35 --- tests/component/updater_test.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index a029cf449..d34c0e54c 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -322,3 +322,36 @@ TEST_F(UpdaterTest, package_extract_file) { CloseArchive(handle); } + +TEST_F(UpdaterTest, write_value) { + // write_value() expects two arguments. + expect(nullptr, "write_value()", kArgsParsingFailure); + expect(nullptr, "write_value(\"arg1\")", kArgsParsingFailure); + expect(nullptr, "write_value(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + // filename cannot be empty. + expect(nullptr, "write_value(\"value\", \"\")", kArgsParsingFailure); + + // Write some value to file. + TemporaryFile temp_file; + std::string value = "magicvalue"; + std::string script("write_value(\"" + value + "\", \"" + std::string(temp_file.path) + "\")"); + expect("t", script.c_str(), kNoCause); + + // Verify the content. + std::string content; + ASSERT_TRUE(android::base::ReadFileToString(temp_file.path, &content)); + ASSERT_EQ(value, content); + + // Allow writing empty string. + script = "write_value(\"\", \"" + std::string(temp_file.path) + "\")"; + expect("t", script.c_str(), kNoCause); + + // Verify the content. + ASSERT_TRUE(android::base::ReadFileToString(temp_file.path, &content)); + ASSERT_EQ("", content); + + // It should fail gracefully when write fails. + script = "write_value(\"value\", \"/proc/0/file1\")"; + expect("", script.c_str(), kNoCause); +} -- cgit v1.2.3 From 1036d36542c452b8df0200d13029d172646a2719 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 17 Nov 2016 22:49:56 -0800 Subject: updater: Add testcase for package_extract_dir(). Test: recovery_component_test passes. Change-Id: I3af4707bc42c7331ca961be8b967a53de82ea25b --- tests/common/test_constants.h | 2 + tests/component/updater_test.cpp | 96 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) (limited to 'tests') diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h index 93e4ab5b2..f6b6922a4 100644 --- a/tests/common/test_constants.h +++ b/tests/common/test_constants.h @@ -22,6 +22,8 @@ // Zip entries in ziptest_valid.zip. static const std::string kATxtContents("abcdefghabcdefgh\n"); static const std::string kBTxtContents("abcdefgh\n"); +static const std::string kCTxtContents("abcdefghabcdefgh\n"); +static const std::string kDTxtContents("abcdefgh\n"); // echo -n -e "abcdefghabcdefgh\n" | sha1sum static const std::string kATxtSha1Sum("32c96a03dc8cd20097940f351bca6261ee5a1643"); diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index d34c0e54c..cd285729d 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -270,6 +270,102 @@ TEST_F(UpdaterTest, symlink) { ASSERT_EQ(0, unlink(src2.c_str())); } +TEST_F(UpdaterTest, package_extract_dir) { + // package_extract_dir expects 2 arguments. + expect(nullptr, "package_extract_dir()", kArgsParsingFailure); + expect(nullptr, "package_extract_dir(\"arg1\")", kArgsParsingFailure); + expect(nullptr, "package_extract_dir(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // Need to set up the ziphandle. + UpdaterInfo updater_info; + updater_info.package_zip = handle; + + // Extract "b/c.txt" and "b/d.txt" with package_extract_dir("b", ""). + TemporaryDir td; + std::string temp_dir(td.path); + std::string script("package_extract_dir(\"b\", \"" + temp_dir + "\")"); + expect("t", script.c_str(), kNoCause, &updater_info); + + // Verify. + std::string data; + std::string file_c = temp_dir + "/c.txt"; + ASSERT_TRUE(android::base::ReadFileToString(file_c, &data)); + ASSERT_EQ(kCTxtContents, data); + + std::string file_d = temp_dir + "/d.txt"; + ASSERT_TRUE(android::base::ReadFileToString(file_d, &data)); + ASSERT_EQ(kDTxtContents, data); + + // Modify the contents in order to retry. It's expected to be overwritten. + ASSERT_TRUE(android::base::WriteStringToFile("random", file_c)); + ASSERT_TRUE(android::base::WriteStringToFile("random", file_d)); + + // Extract again and verify. + expect("t", script.c_str(), kNoCause, &updater_info); + + ASSERT_TRUE(android::base::ReadFileToString(file_c, &data)); + ASSERT_EQ(kCTxtContents, data); + ASSERT_TRUE(android::base::ReadFileToString(file_d, &data)); + ASSERT_EQ(kDTxtContents, data); + + // Clean up the temp files under td. + ASSERT_EQ(0, unlink(file_c.c_str())); + ASSERT_EQ(0, unlink(file_d.c_str())); + + // Extracting "b/" (with slash) should give the same result. + script = "package_extract_dir(\"b/\", \"" + temp_dir + "\")"; + expect("t", script.c_str(), kNoCause, &updater_info); + + ASSERT_TRUE(android::base::ReadFileToString(file_c, &data)); + ASSERT_EQ(kCTxtContents, data); + ASSERT_TRUE(android::base::ReadFileToString(file_d, &data)); + ASSERT_EQ(kDTxtContents, data); + + ASSERT_EQ(0, unlink(file_c.c_str())); + ASSERT_EQ(0, unlink(file_d.c_str())); + + // Extracting "" is allowed. The entries will carry the path name. + script = "package_extract_dir(\"\", \"" + temp_dir + "\")"; + expect("t", script.c_str(), kNoCause, &updater_info); + + std::string file_a = temp_dir + "/a.txt"; + ASSERT_TRUE(android::base::ReadFileToString(file_a, &data)); + ASSERT_EQ(kATxtContents, data); + std::string file_b = temp_dir + "/b.txt"; + ASSERT_TRUE(android::base::ReadFileToString(file_b, &data)); + ASSERT_EQ(kBTxtContents, data); + std::string file_b_c = temp_dir + "/b/c.txt"; + ASSERT_TRUE(android::base::ReadFileToString(file_b_c, &data)); + ASSERT_EQ(kCTxtContents, data); + std::string file_b_d = temp_dir + "/b/d.txt"; + ASSERT_TRUE(android::base::ReadFileToString(file_b_d, &data)); + ASSERT_EQ(kDTxtContents, data); + + ASSERT_EQ(0, unlink(file_a.c_str())); + ASSERT_EQ(0, unlink(file_b.c_str())); + ASSERT_EQ(0, unlink(file_b_c.c_str())); + ASSERT_EQ(0, unlink(file_b_d.c_str())); + ASSERT_EQ(0, rmdir((temp_dir + "/b").c_str())); + + // Extracting non-existent entry should still give "t". + script = "package_extract_dir(\"doesntexist\", \"" + temp_dir + "\")"; + expect("t", script.c_str(), kNoCause, &updater_info); + + // Only relative zip_path is allowed. + script = "package_extract_dir(\"/b\", \"" + temp_dir + "\")"; + expect("", script.c_str(), kNoCause, &updater_info); + + // Only absolute dest_path is allowed. + script = "package_extract_dir(\"b\", \"path\")"; + expect("", script.c_str(), kNoCause, &updater_info); + + CloseArchive(handle); +} + // TODO: Test extracting to block device. TEST_F(UpdaterTest, package_extract_file) { // package_extract_file expects 1 or 2 arguments. -- cgit v1.2.3 From bedf5fc11cea9cc6b92f37597fe8624d25b8d371 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 18 Nov 2016 12:01:26 -0800 Subject: updater: Refactor set_stage() and get_stage() functions. Add read_bootloader_message_from() and write_bootloader_message_to() to allow specifying the BCB device (/misc). Also add testcases for set_stage() and get_stage(). Test: recovery_component_test passes. Test: Build a recovery image and apply a two-step OTA package. Change-Id: If5ab06a1aaaea168d2a9e5dd63c07c0a3190e4ae --- tests/Android.mk | 2 ++ tests/component/updater_test.cpp | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index fdc947028..5f6a7ce0c 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -80,10 +80,12 @@ LOCAL_STATIC_LIBRARIES := \ libedify \ libotafault \ libupdater \ + libbootloader_message \ libverifier \ libminui \ libotautil \ libmounts \ + libfs_mgr \ liblog \ libselinux \ libext4_utils_static \ diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index cd285729d..f31f1f82a 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -451,3 +452,61 @@ TEST_F(UpdaterTest, write_value) { script = "write_value(\"value\", \"/proc/0/file1\")"; expect("", script.c_str(), kNoCause); } + +TEST_F(UpdaterTest, get_stage) { + // get_stage() expects one argument. + expect(nullptr, "get_stage()", kArgsParsingFailure); + expect(nullptr, "get_stage(\"arg1\", \"arg2\")", kArgsParsingFailure); + expect(nullptr, "get_stage(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + // Set up a local file as BCB. + TemporaryFile tf; + std::string temp_file(tf.path); + bootloader_message boot; + strlcpy(boot.stage, "2/3", sizeof(boot.stage)); + std::string err; + ASSERT_TRUE(write_bootloader_message_to(boot, temp_file, &err)); + + // Can read the stage value. + std::string script("get_stage(\"" + temp_file + "\")"); + expect("2/3", script.c_str(), kNoCause); + + // Bad BCB path. + script = "get_stage(\"doesntexist\")"; + expect("", script.c_str(), kNoCause); +} + +TEST_F(UpdaterTest, set_stage) { + // set_stage() expects two arguments. + expect(nullptr, "set_stage()", kArgsParsingFailure); + expect(nullptr, "set_stage(\"arg1\")", kArgsParsingFailure); + expect(nullptr, "set_stage(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + // Set up a local file as BCB. + TemporaryFile tf; + std::string temp_file(tf.path); + bootloader_message boot; + strlcpy(boot.command, "command", sizeof(boot.command)); + strlcpy(boot.stage, "2/3", sizeof(boot.stage)); + std::string err; + ASSERT_TRUE(write_bootloader_message_to(boot, temp_file, &err)); + + // Write with set_stage(). + std::string script("set_stage(\"" + temp_file + "\", \"1/3\")"); + expect(tf.path, script.c_str(), kNoCause); + + // Verify. + bootloader_message boot_verify; + ASSERT_TRUE(read_bootloader_message_from(&boot_verify, temp_file, &err)); + + // Stage should be updated, with command part untouched. + ASSERT_STREQ("1/3", boot_verify.stage); + ASSERT_STREQ(boot.command, boot_verify.command); + + // Bad BCB path. + script = "set_stage(\"doesntexist\", \"1/3\")"; + expect("", script.c_str(), kNoCause); + + script = "set_stage(\"/dev/full\", \"1/3\")"; + expect("", script.c_str(), kNoCause); +} -- cgit v1.2.3 From 8dd44e907ada675a5767bf2f4108e8c591e2781f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 21 Nov 2016 11:16:56 -0800 Subject: tests: Add testcases for EMMC targets. There're two types of targets in applypatch: regular files and EMMC targets. We have two sets of functions to handle them respectively. This CL adds testcases to use "EMMC:filename:size:sha1" as the target name, which triggers the code path for patching EMMC targets. Bug: 33034669 Test: recovery_component_test passes. Change-Id: I8f10c6c8d2c1fb083f06a83de91d9e23cb41fb6d --- tests/component/applypatch_test.cpp | 175 +++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 31 deletions(-) (limited to 'tests') diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index 1a0b19113..d178303aa 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -83,15 +83,11 @@ class ApplyPatchTest : public ::testing::Test { ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file)); // set up SHA constants - sha1sum(old_file, &old_sha1); - sha1sum(new_file, &new_sha1); + sha1sum(old_file, &old_sha1, &old_size); + sha1sum(new_file, &new_sha1, &new_size); srand(time(nullptr)); 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; @@ -105,6 +101,7 @@ class ApplyPatchTest : public ::testing::Test { static std::string bad_sha1_a; static std::string bad_sha1_b; + static size_t old_size; static size_t new_size; }; @@ -184,7 +181,7 @@ 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::old_size; size_t ApplyPatchTest::new_size; std::vector> ApplyPatchFullTest::patches; @@ -211,6 +208,42 @@ TEST_F(ApplyPatchTest, CheckModeFailure) { ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } +TEST_F(ApplyPatchTest, CheckModeEmmcTarget) { + // EMMC:old_file:size:sha1 should pass the check. + std::string src_file = + "EMMC:" + old_file + ":" + std::to_string(old_size) + ":" + old_sha1; + std::vector sha1s; + ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); + + // EMMC:old_file:(size-1):sha1:(size+1):sha1 should fail the check. + src_file = "EMMC:" + old_file + ":" + std::to_string(old_size - 1) + ":" + old_sha1 + ":" + + std::to_string(old_size + 1) + ":" + old_sha1; + ASSERT_EQ(1, applypatch_check(src_file.c_str(), sha1s)); + + // EMMC:old_file:(size-1):sha1:size:sha1:(size+1):sha1 should pass the check. + src_file = "EMMC:" + old_file + ":" + + std::to_string(old_size - 1) + ":" + old_sha1 + ":" + + std::to_string(old_size) + ":" + old_sha1 + ":" + + std::to_string(old_size + 1) + ":" + old_sha1; + ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); + + // EMMC:old_file:(size+1):sha1:(size-1):sha1:size:sha1 should pass the check. + src_file = "EMMC:" + old_file + ":" + + std::to_string(old_size + 1) + ":" + old_sha1 + ":" + + std::to_string(old_size - 1) + ":" + old_sha1 + ":" + + std::to_string(old_size) + ":" + old_sha1; + ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); + + // EMMC:new_file:(size+1):old_sha1:(size-1):old_sha1:size:old_sha1:size:new_sha1 + // should pass the check. + src_file = "EMMC:" + new_file + ":" + + std::to_string(old_size + 1) + ":" + old_sha1 + ":" + + std::to_string(old_size - 1) + ":" + old_sha1 + ":" + + std::to_string(old_size) + ":" + old_sha1 + ":" + + std::to_string(new_size) + ":" + new_sha1; + ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); +} + TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) { mangle_file(old_file); std::vector sha1s = { old_sha1 }; @@ -307,7 +340,7 @@ TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) { ASSERT_FALSE(file_cmp(output_loc, new_file)); } -TEST(ApplyPatchModes, InvalidArgs) { +TEST(ApplyPatchModesTest, InvalidArgs) { // At least two args (including the filename). ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" })); @@ -315,21 +348,22 @@ TEST(ApplyPatchModes, InvalidArgs) { ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" })); } -TEST(ApplyPatchModes, PatchMode) { +TEST(ApplyPatchModesTest, PatchMode) { std::string boot_img = from_testdata_base("boot.img"); size_t boot_img_size; std::string boot_img_sha1; sha1sum(boot_img, &boot_img_sha1, &boot_img_size); std::string recovery_img = from_testdata_base("recovery.img"); - size_t recovery_img_size; std::string recovery_img_sha1; - sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size); - + size_t size; + sha1sum(recovery_img, &recovery_img_sha1, &size); + std::string recovery_img_size = std::to_string(size); std::string bonus_file = from_testdata_base("bonus.file"); // applypatch -b : TemporaryFile tmp1; + std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); std::vector args = { "applypatch", "-b", @@ -337,28 +371,32 @@ TEST(ApplyPatchModes, PatchMode) { boot_img.c_str(), tmp1.path, recovery_img_sha1.c_str(), - std::to_string(recovery_img_size).c_str(), - (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str() + recovery_img_size.c_str(), + patch.c_str() }; ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); // applypatch : TemporaryFile tmp2; + patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); std::vector args2 = { "applypatch", boot_img.c_str(), tmp2.path, recovery_img_sha1.c_str(), - std::to_string(recovery_img_size).c_str(), - (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str() + recovery_img_size.c_str(), + patch.c_str() }; ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data())); // applypatch -b \ - // : : + // : : TemporaryFile tmp3; std::string bad_sha1_a = android::base::StringPrintf("%040x", rand()); std::string bad_sha1_b = android::base::StringPrintf("%040x", rand()); + std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p"); + std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); + std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p"); std::vector args3 = { "applypatch", "-b", @@ -366,15 +404,85 @@ TEST(ApplyPatchModes, PatchMode) { boot_img.c_str(), tmp3.path, recovery_img_sha1.c_str(), - std::to_string(recovery_img_size).c_str(), - (bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p")).c_str(), - (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str(), - (bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p")).c_str(), + recovery_img_size.c_str(), + patch1.c_str(), + patch2.c_str(), + patch3.c_str() + }; + ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data())); +} + +TEST(ApplyPatchModesTest, PatchModeEmmcTarget) { + std::string boot_img = from_testdata_base("boot.img"); + size_t boot_img_size; + std::string boot_img_sha1; + sha1sum(boot_img, &boot_img_sha1, &boot_img_size); + + std::string recovery_img = from_testdata_base("recovery.img"); + size_t size; + std::string recovery_img_sha1; + sha1sum(recovery_img, &recovery_img_sha1, &size); + std::string recovery_img_size = std::to_string(size); + + std::string bonus_file = from_testdata_base("bonus.file"); + + // applypatch -b : + TemporaryFile tmp1; + std::string src_file = + "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1; + std::string tgt_file = "EMMC:" + std::string(tmp1.path); + std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); + std::vector args = { + "applypatch", + "-b", + bonus_file.c_str(), + src_file.c_str(), + tgt_file.c_str(), + recovery_img_sha1.c_str(), + recovery_img_size.c_str(), + patch.c_str() + }; + ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); + + // applypatch : + TemporaryFile tmp2; + patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); + tgt_file = "EMMC:" + std::string(tmp2.path); + std::vector args2 = { + "applypatch", + src_file.c_str(), + tgt_file.c_str(), + recovery_img_sha1.c_str(), + recovery_img_size.c_str(), + patch.c_str() + }; + ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data())); + + // applypatch -b \ + // : : + TemporaryFile tmp3; + tgt_file = "EMMC:" + std::string(tmp3.path); + std::string bad_sha1_a = android::base::StringPrintf("%040x", rand()); + std::string bad_sha1_b = android::base::StringPrintf("%040x", rand()); + std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p"); + std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); + std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p"); + std::vector args3 = { + "applypatch", + "-b", + bonus_file.c_str(), + src_file.c_str(), + tgt_file.c_str(), + recovery_img_sha1.c_str(), + recovery_img_size.c_str(), + patch1.c_str(), + patch2.c_str(), + patch3.c_str() }; ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data())); } -TEST(ApplyPatchModes, PatchModeInvalidArgs) { +TEST(ApplyPatchModesTest, PatchModeInvalidArgs) { // Invalid bonus file. ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" })); @@ -388,9 +496,10 @@ TEST(ApplyPatchModes, PatchModeInvalidArgs) { sha1sum(boot_img, &boot_img_sha1, &boot_img_size); std::string recovery_img = from_testdata_base("recovery.img"); - size_t recovery_img_size; + size_t size; std::string recovery_img_sha1; - sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size); + sha1sum(recovery_img, &recovery_img_sha1, &size); + std::string recovery_img_size = std::to_string(size); // Bonus file is not supported in flash mode. // applypatch -b @@ -402,40 +511,44 @@ TEST(ApplyPatchModes, PatchModeInvalidArgs) { boot_img.c_str(), tmp4.path, recovery_img_sha1.c_str(), - std::to_string(recovery_img_size).c_str() }; + recovery_img_size.c_str() + }; ASSERT_NE(0, applypatch_modes(args4.size(), args4.data())); // Failed to parse patch args. TemporaryFile tmp5; + std::string bad_arg1 = + "invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p"); std::vector args5 = { "applypatch", boot_img.c_str(), tmp5.path, recovery_img_sha1.c_str(), - std::to_string(recovery_img_size).c_str(), - ("invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str(), + recovery_img_size.c_str(), + bad_arg1.c_str() }; ASSERT_NE(0, applypatch_modes(args5.size(), args5.data())); // Target size cannot be zero. TemporaryFile tmp6; + std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); std::vector args6 = { "applypatch", boot_img.c_str(), tmp6.path, recovery_img_sha1.c_str(), "0", // target size - (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str() + patch.c_str() }; ASSERT_NE(0, applypatch_modes(args6.size(), args6.data())); } -TEST(ApplyPatchModes, CheckModeInvalidArgs) { +TEST(ApplyPatchModesTest, CheckModeInvalidArgs) { // Insufficient args. ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" })); } -TEST(ApplyPatchModes, SpaceModeInvalidArgs) { +TEST(ApplyPatchModesTest, SpaceModeInvalidArgs) { // Insufficient args. ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-s" })); @@ -449,6 +562,6 @@ TEST(ApplyPatchModes, SpaceModeInvalidArgs) { ASSERT_EQ(0, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0x10" })); } -TEST(ApplyPatchModes, ShowLicenses) { +TEST(ApplyPatchModesTest, ShowLicenses) { ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" })); } -- cgit v1.2.3 From d530449e54bd327e9c26209ffa0490c6508afe6c Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Fri, 9 Dec 2016 16:20:49 -0800 Subject: Add a stub recovery UI. This allows recovery to work on devices without screen. The stub recovery UI does nothing except print to stdout. Test: write 'recovery\n--wipe_data\n--reason=wipe_data_from_ota\n' to misc and boot to recovery on a device without screen. Bug: 33175036 Change-Id: Icde698aa2e2e29f4b3d0532dfd3c6a939ac2bc63 --- tests/component/verifier_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 60a78f5c3..33aadb3fb 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -40,7 +40,7 @@ RecoveryUI* ui = NULL; class MockUI : public RecoveryUI { - void Init() { } + bool Init() { return true; } void SetStage(int, int) { } void SetLocale(const char*) { } void SetBackground(Icon /*icon*/) { } -- cgit v1.2.3 From 10334088017c9bfcf1b171567e7c4794876c33c9 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 12 Dec 2016 17:10:20 -0800 Subject: Add tests for setup-bcb and clear-bcb via uncrypt. Bug: http://b/33534933 Test: recovery_component_test passes (and fails on buggy build due to the CL in [1]). [1]: commit 7e31f421a514da09b90e46dbd642a5e9b16e0003 Change-Id: I120498048ec1db8f9fcbb3cf135c05d3a48cfcdf --- tests/Android.mk | 2 + tests/component/uncrypt_test.cpp | 174 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 tests/component/uncrypt_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 5f6a7ce0c..1621f37bf 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -62,8 +62,10 @@ LOCAL_C_INCLUDES := bootable/recovery LOCAL_SRC_FILES := \ component/applypatch_test.cpp \ component/edify_test.cpp \ + component/uncrypt_test.cpp \ component/updater_test.cpp \ component/verifier_test.cpp + LOCAL_FORCE_STATIC_EXECUTABLE := true tune2fs_static_libraries := \ diff --git a/tests/component/uncrypt_test.cpp b/tests/component/uncrypt_test.cpp new file mode 100644 index 000000000..a554c3e48 --- /dev/null +++ b/tests/component/uncrypt_test.cpp @@ -0,0 +1,174 @@ +/* + * 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 +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +static const std::string UNCRYPT_SOCKET = "/dev/socket/uncrypt"; +static const std::string INIT_SVC_SETUP_BCB = "init.svc.setup-bcb"; +static const std::string INIT_SVC_CLEAR_BCB = "init.svc.clear-bcb"; +static const std::string INIT_SVC_UNCRYPT = "init.svc.uncrypt"; +static constexpr int SOCKET_CONNECTION_MAX_RETRY = 30; + +class UncryptTest : public ::testing::Test { + protected: + virtual void SetUp() { + ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb")); + ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb")); + ASSERT_TRUE(android::base::SetProperty("ctl.stop", "uncrypt")); + + bool success = false; + for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { + std::string setup_bcb = android::base::GetProperty(INIT_SVC_SETUP_BCB, ""); + std::string clear_bcb = android::base::GetProperty(INIT_SVC_CLEAR_BCB, ""); + std::string uncrypt = android::base::GetProperty(INIT_SVC_UNCRYPT, ""); + LOG(INFO) << "setup-bcb: [" << setup_bcb << "] clear-bcb: [" << clear_bcb << "] uncrypt: [" + << uncrypt << "]"; + if (setup_bcb != "running" && clear_bcb != "running" && uncrypt != "running") { + success = true; + break; + } + sleep(1); + } + + ASSERT_TRUE(success) << "uncrypt service is not available."; + } +}; + +TEST_F(UncryptTest, setup_bcb) { + // Trigger the setup-bcb service. + ASSERT_TRUE(android::base::SetProperty("ctl.start", "setup-bcb")); + + // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected"). + sleep(1); + + struct sockaddr_un un = {}; + un.sun_family = AF_UNIX; + strlcpy(un.sun_path, UNCRYPT_SOCKET.c_str(), sizeof(un.sun_path)); + + int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + ASSERT_NE(-1, sockfd); + + // Connect to the uncrypt socket. + bool success = false; + for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { + if (connect(sockfd, reinterpret_cast(&un), sizeof(struct sockaddr_un)) != 0) { + success = true; + break; + } + sleep(1); + } + ASSERT_TRUE(success); + + // Send out the BCB message. + std::string message = "--update_message=abc value"; + std::string message_in_bcb = "recovery\n--update_message=abc value\n"; + int length = static_cast(message.size()); + int length_out = htonl(length); + ASSERT_TRUE(android::base::WriteFully(sockfd, &length_out, sizeof(int))) + << "Failed to write length: " << strerror(errno); + ASSERT_TRUE(android::base::WriteFully(sockfd, message.data(), length)) + << "Failed to write message: " << strerror(errno); + + // Check the status code from uncrypt. + int status; + ASSERT_TRUE(android::base::ReadFully(sockfd, &status, sizeof(int))); + ASSERT_EQ(100U, ntohl(status)); + + // Ack having received the status code. + int code = 0; + ASSERT_TRUE(android::base::WriteFully(sockfd, &code, sizeof(int))); + + ASSERT_EQ(0, close(sockfd)); + + ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb")); + + // Verify the message by reading from BCB directly. + bootloader_message boot; + std::string err; + ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err; + + ASSERT_EQ("boot-recovery", std::string(boot.command)); + ASSERT_EQ(message_in_bcb, std::string(boot.recovery)); + + // The rest of the boot.recovery message should be zero'd out. + ASSERT_LE(message_in_bcb.size(), sizeof(boot.recovery)); + size_t left = sizeof(boot.recovery) - message_in_bcb.size(); + ASSERT_EQ(std::string(left, '\0'), std::string(&boot.recovery[message_in_bcb.size()], left)); + + // Clear the BCB. + ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err; +} + +TEST_F(UncryptTest, clear_bcb) { + // Trigger the clear-bcb service. + ASSERT_TRUE(android::base::SetProperty("ctl.start", "clear-bcb")); + + // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected"). + sleep(1); + + struct sockaddr_un un = {}; + un.sun_family = AF_UNIX; + strlcpy(un.sun_path, UNCRYPT_SOCKET.c_str(), sizeof(un.sun_path)); + + int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + ASSERT_NE(-1, sockfd); + + // Connect to the uncrypt socket. + bool success = false; + for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { + if (connect(sockfd, reinterpret_cast(&un), sizeof(struct sockaddr_un)) != 0) { + success = true; + break; + } + sleep(1); + } + ASSERT_TRUE(success); + + // Check the status code from uncrypt. + int status; + ASSERT_TRUE(android::base::ReadFully(sockfd, &status, sizeof(int))); + ASSERT_EQ(100U, ntohl(status)); + + // Ack having received the status code. + int code = 0; + ASSERT_TRUE(android::base::WriteFully(sockfd, &code, sizeof(int))); + + ASSERT_EQ(0, close(sockfd)); + + ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb")); + + // Verify the content by reading from BCB directly. + bootloader_message boot; + std::string err; + ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err; + + // All the bytes should be cleared. + ASSERT_EQ(std::string(sizeof(boot), '\0'), + std::string(reinterpret_cast(&boot), sizeof(boot))); +} -- cgit v1.2.3 From 8b7301b7119e10f2f936c4c92f0a67a00cc2d203 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 14 Dec 2016 15:52:34 -0800 Subject: tests: Add tests for bootloader_message. Test: recovery_component_test passes. Change-Id: Ib9aa2ffd6b018546223c76b7424f4ba355f5b088 --- tests/Android.mk | 1 + tests/component/bootloader_message_test.cpp | 139 ++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 tests/component/bootloader_message_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 1621f37bf..8ae52d799 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -61,6 +61,7 @@ LOCAL_MODULE := recovery_component_test LOCAL_C_INCLUDES := bootable/recovery LOCAL_SRC_FILES := \ component/applypatch_test.cpp \ + component/bootloader_message_test.cpp \ component/edify_test.cpp \ component/uncrypt_test.cpp \ component/updater_test.cpp \ diff --git a/tests/component/bootloader_message_test.cpp b/tests/component/bootloader_message_test.cpp new file mode 100644 index 000000000..cff129cfc --- /dev/null +++ b/tests/component/bootloader_message_test.cpp @@ -0,0 +1,139 @@ +/* + * 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 +#include +#include + +#include +#include + +class BootloaderMessageTest : public ::testing::Test { + protected: + virtual void TearDown() override { + // Clear the BCB. + std::string err; + ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err; + } +}; + +TEST_F(BootloaderMessageTest, clear_bootloader_message) { + // Clear the BCB. + std::string err; + ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err; + + // Verify the content. + bootloader_message boot; + ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err; + + // All the bytes should be cleared. + ASSERT_EQ(std::string(sizeof(boot), '\0'), + std::string(reinterpret_cast(&boot), sizeof(boot))); +} + +TEST_F(BootloaderMessageTest, read_and_write_bootloader_message) { + // Write the BCB. + bootloader_message boot = {}; + strlcpy(boot.command, "command", sizeof(boot.command)); + strlcpy(boot.recovery, "message1\nmessage2\n", sizeof(boot.recovery)); + strlcpy(boot.status, "status1", sizeof(boot.status)); + + std::string err; + ASSERT_TRUE(write_bootloader_message(boot, &err)) << "Failed to write BCB: " << err; + + // Read and verify. + bootloader_message boot_verify; + ASSERT_TRUE(read_bootloader_message(&boot_verify, &err)) << "Failed to read BCB: " << err; + + ASSERT_EQ(std::string(reinterpret_cast(&boot), sizeof(boot)), + std::string(reinterpret_cast(&boot_verify), sizeof(boot_verify))); +} + +TEST_F(BootloaderMessageTest, write_bootloader_message_options) { + // Write the options to BCB. + std::vector options = { "option1", "option2" }; + std::string err; + ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err; + + // Inject some bytes into boot, which should be overwritten while reading. + bootloader_message boot; + strlcpy(boot.recovery, "random message", sizeof(boot.recovery)); + strlcpy(boot.reserved, "reserved bytes", sizeof(boot.reserved)); + + ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err; + + // Verify that command and recovery fields should be set. + ASSERT_EQ("boot-recovery", std::string(boot.command)); + std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n"; + ASSERT_EQ(expected, std::string(boot.recovery)); + + // The rest should be cleared. + ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status))); + ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage))); + ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'), + std::string(boot.reserved, sizeof(boot.reserved))); +} + +TEST_F(BootloaderMessageTest, write_bootloader_message_options_empty) { + // Write empty vector. + std::vector options; + std::string err; + ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err; + + // Read and verify. + bootloader_message boot; + ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err; + + // command and recovery fields should be set. + ASSERT_EQ("boot-recovery", std::string(boot.command)); + ASSERT_EQ("recovery\n", std::string(boot.recovery)); + + // The rest should be cleared. + ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status))); + ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage))); + ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'), + std::string(boot.reserved, sizeof(boot.reserved))); +} + +TEST_F(BootloaderMessageTest, write_bootloader_message_options_long) { + // Write super long message. + std::vector options; + for (int i = 0; i < 100; i++) { + options.push_back("option: " + std::to_string(i)); + } + + std::string err; + ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err; + + // Read and verify. + bootloader_message boot; + ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err; + + // Make sure it's long enough. + std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n"; + ASSERT_GE(expected.size(), sizeof(boot.recovery)); + + // command and recovery fields should be set. + ASSERT_EQ("boot-recovery", std::string(boot.command)); + ASSERT_EQ(expected.substr(0, sizeof(boot.recovery) - 1), std::string(boot.recovery)); + ASSERT_EQ('\0', boot.recovery[sizeof(boot.recovery) - 1]); + + // The rest should be cleared. + ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status))); + ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage))); + ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'), + std::string(boot.reserved, sizeof(boot.reserved))); +} -- cgit v1.2.3 From 2292db819bacc74a38334dc7da543856ac14de4e Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 13 Dec 2016 21:53:31 -0800 Subject: Add update_bootloader_message() to fix two-step OTAs. This is a retry of commit 7e31f421a514da09b90e46dbd642a5e9b16e0003. Commit bd56f1590c967205dc45eb2ec298aa8d2aacb740 switches to calling write_bootloader_message() in get_args(), which unintentionally resets the stage field thus breaks two-step OTAs. This CL adds update_bootloader_message(), which only sets the command field (to "boot-recovery") and the recovery field (with the specified options). Bug: 33534933 Test: Apply a two-step package. Test: recovery_component_test passes. Change-Id: Ie0b1ed4053d2d3c97d9cb84310d616b28fcfc72e --- tests/component/bootloader_message_test.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'tests') diff --git a/tests/component/bootloader_message_test.cpp b/tests/component/bootloader_message_test.cpp index cff129cfc..dbcaf619e 100644 --- a/tests/component/bootloader_message_test.cpp +++ b/tests/component/bootloader_message_test.cpp @@ -137,3 +137,29 @@ TEST_F(BootloaderMessageTest, write_bootloader_message_options_long) { ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'), std::string(boot.reserved, sizeof(boot.reserved))); } + +TEST_F(BootloaderMessageTest, update_bootloader_message) { + // Inject some bytes into boot, which should be not overwritten later. + bootloader_message boot; + strlcpy(boot.recovery, "random message", sizeof(boot.recovery)); + strlcpy(boot.reserved, "reserved bytes", sizeof(boot.reserved)); + std::string err; + ASSERT_TRUE(write_bootloader_message(boot, &err)) << "Failed to write BCB: " << err; + + // Update the BCB message. + std::vector options = { "option1", "option2" }; + ASSERT_TRUE(update_bootloader_message(options, &err)) << "Failed to update BCB: " << err; + + bootloader_message boot_verify; + ASSERT_TRUE(read_bootloader_message(&boot_verify, &err)) << "Failed to read BCB: " << err; + + // Verify that command and recovery fields should be set. + ASSERT_EQ("boot-recovery", std::string(boot_verify.command)); + std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n"; + ASSERT_EQ(expected, std::string(boot_verify.recovery)); + + // The rest should be intact. + ASSERT_EQ(std::string(boot.status), std::string(boot_verify.status)); + ASSERT_EQ(std::string(boot.stage), std::string(boot_verify.stage)); + ASSERT_EQ(std::string(boot.reserved), std::string(boot_verify.reserved)); +} -- cgit v1.2.3 From f69e6a9475983b2ad46729e44ab58d2b22cd74d0 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 16 Dec 2016 14:27:55 -0800 Subject: Add a checker for signature boundary in verifier The 'signature_start' variable marks the location of the signature from the end of a zip archive. And a boundary check is missing where 'signature_start' should be within the EOCD comment field. This causes problems when sideloading a malicious package. Also add a corresponding test. Bug: 31914369 Test: Verification fails correctly when sideloading recovery_test.zip on angler. Change-Id: I6ea96bf04dac5d8d4d6719e678d504f957b4d5c1 --- tests/component/verifier_test.cpp | 3 ++- tests/testdata/signature-boundary.zip | Bin 0 -> 22 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 tests/testdata/signature-boundary.zip (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 33aadb3fb..8d8b461cb 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -155,4 +155,5 @@ INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest, std::vector({"random.zip", "v1"}), std::vector({"fake-eocd.zip", "v1"}), std::vector({"alter-metadata.zip", "v1"}), - std::vector({"alter-footer.zip", "v1"}))); + std::vector({"alter-footer.zip", "v1"}), + std::vector({"signature-boundary.zip", "v1"}))); diff --git a/tests/testdata/signature-boundary.zip b/tests/testdata/signature-boundary.zip new file mode 100644 index 000000000..64a3cfa15 Binary files /dev/null and b/tests/testdata/signature-boundary.zip differ -- cgit v1.2.3 From 97555da4a67d45ada0020c0ee58d1b280cb4b57d Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 15 Dec 2016 10:15:06 -0800 Subject: Add tests for imgdiff. Factor out libimgdiff static library for testing purpose. This CL adds the imgdiff tests on host and on target both (similar to libimgpatch). In practice, we only need imgdiff binary on host, and libimgpatch on target. But they should build and pass tests on both platforms. Test: recovery_host_test passes; recovery_component_test passes. Change-Id: I0eafb7faf727cdf70066310e845af6ee245d4f60 --- tests/Android.mk | 29 +++ tests/component/imgdiff_test.cpp | 448 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 477 insertions(+) create mode 100644 tests/component/imgdiff_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 8ae52d799..ec725d865 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -63,6 +63,7 @@ LOCAL_SRC_FILES := \ component/applypatch_test.cpp \ component/bootloader_message_test.cpp \ component/edify_test.cpp \ + component/imgdiff_test.cpp \ component/uncrypt_test.cpp \ component/updater_test.cpp \ component/verifier_test.cpp @@ -81,6 +82,9 @@ LOCAL_STATIC_LIBRARIES := \ libapplypatch_modes \ libapplypatch \ libedify \ + libimgdiff \ + libimgpatch \ + libbsdiff \ libotafault \ libupdater \ libbootloader_message \ @@ -88,6 +92,8 @@ LOCAL_STATIC_LIBRARIES := \ libminui \ libotautil \ libmounts \ + libdivsufsort \ + libdivsufsort64 \ libfs_mgr \ liblog \ libselinux \ @@ -128,3 +134,26 @@ LOCAL_GENERATED_SOURCES += $(GEN) LOCAL_PICKUP_FILES := $(testdata_continuous_zip_prefix) include $(BUILD_NATIVE_TEST) + +# Host tests +include $(CLEAR_VARS) +LOCAL_CFLAGS := -Werror +LOCAL_MODULE := recovery_host_test +LOCAL_MODULE_HOST_OS := linux +LOCAL_C_INCLUDES := bootable/recovery +LOCAL_SRC_FILES := \ + component/imgdiff_test.cpp +LOCAL_STATIC_LIBRARIES := \ + libimgdiff \ + libimgpatch \ + libbsdiff \ + libziparchive \ + libbase \ + libcrypto \ + libbz \ + libdivsufsort64 \ + libdivsufsort \ + libz +LOCAL_SHARED_LIBRARIES := \ + liblog +include $(BUILD_HOST_NATIVE_TEST) diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp new file mode 100644 index 000000000..3711859de --- /dev/null +++ b/tests/component/imgdiff_test.cpp @@ -0,0 +1,448 @@ +/* + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#include "applypatch/utils.h" + +static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) { + std::string* s = static_cast(token); + s->append(reinterpret_cast(data), len); + return len; +} + +// Sanity check for the given imgdiff patch header. +static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw, + size_t* num_deflate) { + const size_t size = patch.size(); + const char* data = patch.data(); + + ASSERT_GE(size, 12U); + ASSERT_EQ("IMGDIFF2", std::string(data, 8)); + + const int num_chunks = Read4(data + 8); + ASSERT_GE(num_chunks, 0); + + size_t normal = 0; + size_t raw = 0; + size_t deflate = 0; + + size_t pos = 12; + for (int i = 0; i < num_chunks; ++i) { + ASSERT_LE(pos + 4, size); + int type = Read4(data + pos); + pos += 4; + if (type == CHUNK_NORMAL) { + pos += 24; + ASSERT_LE(pos, size); + normal++; + } else if (type == CHUNK_RAW) { + ASSERT_LE(pos + 4, size); + ssize_t data_len = Read4(data + pos); + ASSERT_GT(data_len, 0); + pos += 4 + data_len; + ASSERT_LE(pos, size); + raw++; + } else if (type == CHUNK_DEFLATE) { + pos += 60; + ASSERT_LE(pos, size); + deflate++; + } else { + FAIL() << "Invalid patch type: " << type; + } + } + + if (num_normal != nullptr) *num_normal = normal; + if (num_raw != nullptr) *num_raw = raw; + if (num_deflate != nullptr) *num_deflate = deflate; +} + +TEST(ImgdiffTest, invalid_args) { + // Insufficient inputs. + ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" })); + ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" })); + ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" })); + ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" })); + + // Failed to read bonus file. + ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" })); + + // Failed to read input files. + ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" })); + ASSERT_EQ( + 1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" })); +} + +TEST(ImgdiffTest, image_mode_smoke) { + // Random bytes. + const std::string src("abcdefg"); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + const std::string tgt("abcdefgxyz"); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect one CHUNK_RAW entry. + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(0U, num_deflate); + ASSERT_EQ(1U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + +TEST(ImgdiffTest, zip_mode_smoke_store) { + // Construct src and tgt zip files. + TemporaryFile src_file; + FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + ZipWriter src_writer(src_file_ptr); + ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode. + const std::string src_content("abcdefg"); + ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size())); + ASSERT_EQ(0, src_writer.FinishEntry()); + ASSERT_EQ(0, src_writer.Finish()); + ASSERT_EQ(0, fclose(src_file_ptr)); + + TemporaryFile tgt_file; + FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + ZipWriter tgt_writer(tgt_file_ptr); + ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode. + const std::string tgt_content("abcdefgxyz"); + ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size())); + ASSERT_EQ(0, tgt_writer.FinishEntry()); + ASSERT_EQ(0, tgt_writer.Finish()); + ASSERT_EQ(0, fclose(tgt_file_ptr)); + + // Compute patch. + TemporaryFile patch_file; + std::vector args = { + "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string tgt; + ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); + std::string src; + ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src)); + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect one CHUNK_RAW entry. + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(0U, num_deflate); + ASSERT_EQ(1U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + +TEST(ImgdiffTest, zip_mode_smoke_compressed) { + // Construct src and tgt zip files. + TemporaryFile src_file; + FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + ZipWriter src_writer(src_file_ptr); + ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress)); + const std::string src_content("abcdefg"); + ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size())); + ASSERT_EQ(0, src_writer.FinishEntry()); + ASSERT_EQ(0, src_writer.Finish()); + ASSERT_EQ(0, fclose(src_file_ptr)); + + TemporaryFile tgt_file; + FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + ZipWriter tgt_writer(tgt_file_ptr); + ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress)); + const std::string tgt_content("abcdefgxyz"); + ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size())); + ASSERT_EQ(0, tgt_writer.FinishEntry()); + ASSERT_EQ(0, tgt_writer.Finish()); + ASSERT_EQ(0, fclose(tgt_file_ptr)); + + // Compute patch. + TemporaryFile patch_file; + std::vector args = { + "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string tgt; + ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); + std::string src; + ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src)); + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(1U, num_deflate); + ASSERT_EQ(2U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + +TEST(ImgdiffTest, image_mode_simple) { + // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd). + const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', + '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', + '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', + '\x00', '\x00', '\x00' }; + const std::string src(src_data.cbegin(), src_data.cend()); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + // tgt: "abcdefgxyz" + gzipped "xxyyzz". + const std::vector tgt_data = { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b', + '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac', + '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00' + }; + const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(1U, num_deflate); + ASSERT_EQ(2U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + +TEST(ImgdiffTest, image_mode_different_num_chunks) { + // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test". + const std::vector src_data = { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08', + '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02', + '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b', + '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d', + '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00' + }; + const std::string src(src_data.cbegin(), src_data.cend()); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + // tgt: "abcdefgxyz" + gzipped "xxyyzz". + const std::vector tgt_data = { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b', + '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac', + '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00' + }; + const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(1, imgdiff(args.size(), args.data())); +} + +TEST(ImgdiffTest, image_mode_merge_chunks) { + // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd). + const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', + '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', + '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', + '\x00', '\x00', '\x00' }; + const std::string src(src_data.cbegin(), src_data.cend()); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + // tgt: gzipped "xyz" + "abcdefgh". + const std::vector tgt_data = { + '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', + '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', + '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' + }; + const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) + + // CHUNK_RAW (footer), they both should contain the same chunk types after merging. + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(1U, num_deflate); + ASSERT_EQ(2U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + +TEST(ImgdiffTest, image_mode_spurious_magic) { + // src: "abcdefgh" + '0x1f8b0b00' + some bytes. + const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', + '\x53', '\x58', 't', 'e', 's', 't' }; + const std::string src(src_data.cbegin(), src_data.cend()); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + // tgt: "abcdefgxyz". + const std::vector tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; + const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect one CHUNK_RAW (header) entry. + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(0U, num_deflate); + ASSERT_EQ(1U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + +TEST(ImgdiffTest, image_mode_single_entry_long) { + // src: "abcdefgh" + '0x1f8b0b00' + some bytes. + const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', + '\x53', '\x58', 't', 'e', 's', 't' }; + const std::string src(src_data.cbegin(), src_data.cend()); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + // tgt: "abcdefgxyz" + 200 bytes. + std::vector tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; + tgt_data.resize(tgt_data.size() + 200); + + const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW. + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(1U, num_normal); + ASSERT_EQ(0U, num_deflate); + ASSERT_EQ(0U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} -- cgit v1.2.3 From a3ece96f9f87e7219350498486975c5b8deccd83 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 21 Dec 2016 18:44:20 -0800 Subject: tests: Replace the O_RDONLY in access(2). Although O_RDONLY gives the same value as F_OK (0), it's not the right friend of access(2). Also clean up the temporary files from ZipTest (TemporaryDir doesn't like non-empty directory). Test: recovery_unit_test passes and has no leftover. Change-Id: I66b90e43c0954c89ce08b36b9e2b4e84183b28f5 --- tests/manual/recovery_test.cpp | 3 +-- tests/unit/zip_test.cpp | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/manual/recovery_test.cpp b/tests/manual/recovery_test.cpp index e83849546..e73cb1509 100644 --- a/tests/manual/recovery_test.cpp +++ b/tests/manual/recovery_test.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -79,7 +78,7 @@ TEST(recovery, persist) { std::string buf; EXPECT_TRUE(android::base::ReadFileToString(myFilename, &buf)); EXPECT_EQ(myContent, buf); - if (access(myFilename.c_str(), O_RDONLY) == 0) { + if (access(myFilename.c_str(), F_OK) == 0) { fprintf(stderr, "Removing persistent test data, " "check if reconstructed on reboot\n"); } diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp index ef0ee4c1d..4a1a49b97 100644 --- a/tests/unit/zip_test.cpp +++ b/tests/unit/zip_test.cpp @@ -15,7 +15,6 @@ */ #include -#include #include #include @@ -42,10 +41,10 @@ TEST(ZipTest, ExtractPackageRecursive) { // Make sure all the files are extracted correctly. std::string path(td.path); - ASSERT_EQ(0, access((path + "/a.txt").c_str(), O_RDONLY)); - ASSERT_EQ(0, access((path + "/b.txt").c_str(), O_RDONLY)); - ASSERT_EQ(0, access((path + "/b/c.txt").c_str(), O_RDONLY)); - ASSERT_EQ(0, access((path + "/b/d.txt").c_str(), O_RDONLY)); + ASSERT_EQ(0, access((path + "/a.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/b.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/b/c.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/b/d.txt").c_str(), F_OK)); // The content of the file is the same as expected. std::string content1; @@ -54,7 +53,16 @@ TEST(ZipTest, ExtractPackageRecursive) { std::string content2; ASSERT_TRUE(android::base::ReadFileToString(path + "/b/d.txt", &content2)); - ASSERT_EQ(kBTxtContents, content2); + ASSERT_EQ(kDTxtContents, content2); + + CloseArchive(handle); + + // Clean up. + ASSERT_EQ(0, unlink((path + "/a.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/b.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/b/c.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/b/d.txt").c_str())); + ASSERT_EQ(0, rmdir((path + "/b").c_str())); } TEST(ZipTest, OpenFromMemory) { @@ -76,6 +84,7 @@ TEST(ZipTest, OpenFromMemory) { ASSERT_NE(-1, tmp_binary.fd); ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd)); + CloseArchive(handle); sysReleaseMap(&map); } -- cgit v1.2.3 From e7e7b46666f27135783bcd45252655d9cf2edd33 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 21 Dec 2016 17:58:42 -0800 Subject: tests: Add testcase for ZipUtil. Test: recovery_unit_test passes. Change-Id: I8ad364e88aaee31579ed7206aad8e5620518d797 --- tests/Android.mk | 3 +- tests/unit/ziputil_test.cpp | 191 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 tests/unit/ziputil_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 8ae52d799..effed8313 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -35,7 +35,8 @@ LOCAL_SRC_FILES := \ unit/asn1_decoder_test.cpp \ unit/locale_test.cpp \ unit/sysutil_test.cpp \ - unit/zip_test.cpp + unit/zip_test.cpp \ + unit/ziputil_test.cpp LOCAL_C_INCLUDES := bootable/recovery LOCAL_SHARED_LIBRARIES := liblog diff --git a/tests/unit/ziputil_test.cpp b/tests/unit/ziputil_test.cpp new file mode 100644 index 000000000..14e541690 --- /dev/null +++ b/tests/unit/ziputil_test.cpp @@ -0,0 +1,191 @@ +/* + * Copyright 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 +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "common/test_constants.h" + +TEST(ZipUtilTest, invalid_args) { + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // zip_path must be a relative path. + ASSERT_FALSE(ExtractPackageRecursive(handle, "/a/b", "/tmp", nullptr, nullptr)); + + // dest_path must be an absolute path. + ASSERT_FALSE(ExtractPackageRecursive(handle, "a/b", "tmp", nullptr, nullptr)); + ASSERT_FALSE(ExtractPackageRecursive(handle, "a/b", "", nullptr, nullptr)); + + CloseArchive(handle); +} + +TEST(ZipUtilTest, extract_all) { + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // Extract the whole package into a temp directory. + TemporaryDir td; + ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr); + + // Make sure all the files are extracted correctly. + std::string path(td.path); + ASSERT_EQ(0, access((path + "/a.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/b.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/b/c.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/b/d.txt").c_str(), F_OK)); + + // The content of the file is the same as expected. + std::string content1; + ASSERT_TRUE(android::base::ReadFileToString(path + "/a.txt", &content1)); + ASSERT_EQ(kATxtContents, content1); + + std::string content2; + ASSERT_TRUE(android::base::ReadFileToString(path + "/b/d.txt", &content2)); + ASSERT_EQ(kDTxtContents, content2); + + // Clean up the temp files under td. + ASSERT_EQ(0, unlink((path + "/a.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/b.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/b/c.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/b/d.txt").c_str())); + ASSERT_EQ(0, rmdir((path + "/b").c_str())); + + CloseArchive(handle); +} + +TEST(ZipUtilTest, extract_prefix_with_slash) { + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // Extract all the entries starting with "b/". + TemporaryDir td; + ExtractPackageRecursive(handle, "b/", td.path, nullptr, nullptr); + + // Make sure all the files with "b/" prefix are extracted correctly. + std::string path(td.path); + ASSERT_EQ(0, access((path + "/c.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/d.txt").c_str(), F_OK)); + + // And the rest are not extracted. + ASSERT_EQ(-1, access((path + "/a.txt").c_str(), F_OK)); + ASSERT_EQ(ENOENT, errno); + ASSERT_EQ(-1, access((path + "/b.txt").c_str(), F_OK)); + ASSERT_EQ(ENOENT, errno); + + // The content of the file is the same as expected. + std::string content1; + ASSERT_TRUE(android::base::ReadFileToString(path + "/c.txt", &content1)); + ASSERT_EQ(kCTxtContents, content1); + + std::string content2; + ASSERT_TRUE(android::base::ReadFileToString(path + "/d.txt", &content2)); + ASSERT_EQ(kDTxtContents, content2); + + // Clean up the temp files under td. + ASSERT_EQ(0, unlink((path + "/c.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/d.txt").c_str())); + + CloseArchive(handle); +} + +TEST(ZipUtilTest, extract_prefix_without_slash) { + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // Extract all the file entries starting with "b/". + TemporaryDir td; + ExtractPackageRecursive(handle, "b", td.path, nullptr, nullptr); + + // Make sure all the files with "b/" prefix are extracted correctly. + std::string path(td.path); + ASSERT_EQ(0, access((path + "/c.txt").c_str(), F_OK)); + ASSERT_EQ(0, access((path + "/d.txt").c_str(), F_OK)); + + // And the rest are not extracted. + ASSERT_EQ(-1, access((path + "/a.txt").c_str(), F_OK)); + ASSERT_EQ(ENOENT, errno); + ASSERT_EQ(-1, access((path + "/b.txt").c_str(), F_OK)); + ASSERT_EQ(ENOENT, errno); + + // The content of the file is the same as expected. + std::string content1; + ASSERT_TRUE(android::base::ReadFileToString(path + "/c.txt", &content1)); + ASSERT_EQ(kCTxtContents, content1); + + std::string content2; + ASSERT_TRUE(android::base::ReadFileToString(path + "/d.txt", &content2)); + ASSERT_EQ(kDTxtContents, content2); + + // Clean up the temp files under td. + ASSERT_EQ(0, unlink((path + "/c.txt").c_str())); + ASSERT_EQ(0, unlink((path + "/d.txt").c_str())); + + CloseArchive(handle); +} + +TEST(ZipUtilTest, set_timestamp) { + std::string zip_path = from_testdata_base("ziptest_valid.zip"); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle)); + + // Set the timestamp to 8/1/2008. + constexpr struct utimbuf timestamp = { 1217592000, 1217592000 }; + + // Extract all the entries starting with "b/". + TemporaryDir td; + ExtractPackageRecursive(handle, "b", td.path, ×tamp, nullptr); + + // Make sure all the files with "b/" prefix are extracted correctly. + std::string path(td.path); + std::string file_c = path + "/c.txt"; + std::string file_d = path + "/d.txt"; + ASSERT_EQ(0, access(file_c.c_str(), F_OK)); + ASSERT_EQ(0, access(file_d.c_str(), F_OK)); + + // Verify the timestamp. + timespec time; + time.tv_sec = 1217592000; + time.tv_nsec = 0; + + struct stat sb; + ASSERT_EQ(0, stat(file_c.c_str(), &sb)) << strerror(errno); + ASSERT_EQ(time.tv_sec, static_cast(sb.st_atime)); + ASSERT_EQ(time.tv_sec, static_cast(sb.st_mtime)); + + ASSERT_EQ(0, stat(file_d.c_str(), &sb)) << strerror(errno); + ASSERT_EQ(time.tv_sec, static_cast(sb.st_atime)); + ASSERT_EQ(time.tv_sec, static_cast(sb.st_mtime)); + + // Clean up the temp files under td. + ASSERT_EQ(0, unlink(file_c.c_str())); + ASSERT_EQ(0, unlink(file_d.c_str())); + + CloseArchive(handle); +} -- cgit v1.2.3 From f19295c5dc7cefff2bb26b5bcbab5a76a16cffe3 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 22 Dec 2016 09:28:03 -0800 Subject: tests: Add test coverage for DirUtil. Test: recovery_unit_test passes. Change-Id: I764c56404c7ccdd57ae5486c946fbc9ac6ae7bc9 --- tests/Android.mk | 1 + tests/unit/dirutil_test.cpp | 150 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 tests/unit/dirutil_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index effed8313..17e2b7f5b 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -33,6 +33,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_SRC_FILES := \ unit/asn1_decoder_test.cpp \ + unit/dirutil_test.cpp \ unit/locale_test.cpp \ unit/sysutil_test.cpp \ unit/zip_test.cpp \ diff --git a/tests/unit/dirutil_test.cpp b/tests/unit/dirutil_test.cpp new file mode 100644 index 000000000..5e2ae4fb5 --- /dev/null +++ b/tests/unit/dirutil_test.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 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 +#include +#include + +#include + +#include +#include +#include + +TEST(DirUtilTest, create_invalid) { + // Requesting to create an empty dir is invalid. + ASSERT_EQ(-1, dirCreateHierarchy("", 0755, nullptr, false, nullptr)); + ASSERT_EQ(ENOENT, errno); + + // Requesting to strip the name with no slash present. + ASSERT_EQ(-1, dirCreateHierarchy("abc", 0755, nullptr, true, nullptr)); + ASSERT_EQ(ENOENT, errno); + + // Creating a dir that already exists. + TemporaryDir td; + ASSERT_EQ(0, dirCreateHierarchy(td.path, 0755, nullptr, false, nullptr)); + + // "///" is a valid dir. + ASSERT_EQ(0, dirCreateHierarchy("///", 0755, nullptr, false, nullptr)); + + // Request to create a dir, but a file with the same name already exists. + TemporaryFile tf; + ASSERT_EQ(-1, dirCreateHierarchy(tf.path, 0755, nullptr, false, nullptr)); + ASSERT_EQ(ENOTDIR, errno); +} + +TEST(DirUtilTest, create_smoke) { + TemporaryDir td; + std::string prefix(td.path); + std::string path = prefix + "/a/b"; + constexpr mode_t mode = 0755; + ASSERT_EQ(0, dirCreateHierarchy(path.c_str(), mode, nullptr, false, nullptr)); + + // Verify. + struct stat sb; + ASSERT_EQ(0, stat(path.c_str(), &sb)) << strerror(errno); + ASSERT_TRUE(S_ISDIR(sb.st_mode)); + constexpr mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO; + ASSERT_EQ(mode, sb.st_mode & mask); + + // Clean up. + ASSERT_EQ(0, rmdir((prefix + "/a/b").c_str())); + ASSERT_EQ(0, rmdir((prefix + "/a").c_str())); +} + +TEST(DirUtilTest, create_strip_filename) { + TemporaryDir td; + std::string prefix(td.path); + std::string path = prefix + "/a/b"; + ASSERT_EQ(0, dirCreateHierarchy(path.c_str(), 0755, nullptr, true, nullptr)); + + // Verify that "../a" exists but not "../a/b". + struct stat sb; + ASSERT_EQ(0, stat((prefix + "/a").c_str(), &sb)) << strerror(errno); + ASSERT_TRUE(S_ISDIR(sb.st_mode)); + + ASSERT_EQ(-1, stat(path.c_str(), &sb)); + ASSERT_EQ(ENOENT, errno); + + // Clean up. + ASSERT_EQ(0, rmdir((prefix + "/a").c_str())); +} + +TEST(DirUtilTest, create_mode_and_timestamp) { + TemporaryDir td; + std::string prefix(td.path); + std::string path = prefix + "/a/b"; + // Set the timestamp to 8/1/2008. + constexpr struct utimbuf timestamp = { 1217592000, 1217592000 }; + constexpr mode_t mode = 0751; + ASSERT_EQ(0, dirCreateHierarchy(path.c_str(), mode, ×tamp, false, nullptr)); + + // Verify the mode and timestamp for "../a/b". + struct stat sb; + ASSERT_EQ(0, stat(path.c_str(), &sb)) << strerror(errno); + ASSERT_TRUE(S_ISDIR(sb.st_mode)); + constexpr mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO; + ASSERT_EQ(mode, sb.st_mode & mask); + + timespec time; + time.tv_sec = 1217592000; + time.tv_nsec = 0; + + ASSERT_EQ(time.tv_sec, static_cast(sb.st_atime)); + ASSERT_EQ(time.tv_sec, static_cast(sb.st_mtime)); + + // Verify the mode for "../a". Note that the timestamp for intermediate directories (e.g. "../a") + // may not be 'timestamp' according to the current implementation. + ASSERT_EQ(0, stat((prefix + "/a").c_str(), &sb)) << strerror(errno); + ASSERT_TRUE(S_ISDIR(sb.st_mode)); + ASSERT_EQ(mode, sb.st_mode & mask); + + // Clean up. + ASSERT_EQ(0, rmdir((prefix + "/a/b").c_str())); + ASSERT_EQ(0, rmdir((prefix + "/a").c_str())); +} + +TEST(DirUtilTest, unlink_invalid) { + // File doesn't exist. + ASSERT_EQ(-1, dirUnlinkHierarchy("doesntexist")); + + // Nonexistent directory. + TemporaryDir td; + std::string path(td.path); + ASSERT_EQ(-1, dirUnlinkHierarchy((path + "/a").c_str())); + ASSERT_EQ(ENOENT, errno); +} + +TEST(DirUtilTest, unlink_smoke) { + // Unlink a file. + TemporaryFile tf; + ASSERT_EQ(0, dirUnlinkHierarchy(tf.path)); + ASSERT_EQ(-1, access(tf.path, F_OK)); + + TemporaryDir td; + std::string path(td.path); + constexpr mode_t mode = 0700; + ASSERT_EQ(0, mkdir((path + "/a").c_str(), mode)); + ASSERT_EQ(0, mkdir((path + "/a/b").c_str(), mode)); + ASSERT_EQ(0, mkdir((path + "/a/b/c").c_str(), mode)); + ASSERT_EQ(0, mkdir((path + "/a/d").c_str(), mode)); + + // Remove "../a" recursively. + ASSERT_EQ(0, dirUnlinkHierarchy((path + "/a").c_str())); + + // Verify it's gone. + ASSERT_EQ(-1, access((path + "/a").c_str(), F_OK)); +} -- cgit v1.2.3 From d37ce8f0821758edc33ad9c42b0bf78ff29b365f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sat, 17 Dec 2016 17:10:04 -0800 Subject: imgdiff: Fix an edge case that leads to infinite loop. When the input image ends with the magic value sequence of 0x1f, 0x8b, 0x0b (optionally with 0x00), the image parsing code will be stuck in an infinite loop. Test: recovery_component_test passes. Change-Id: Ie3629dfdc41360387b19cc3e0359c95ae4fb998e --- tests/component/imgdiff_test.cpp | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'tests') diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp index 3711859de..7ad330783 100644 --- a/tests/component/imgdiff_test.cpp +++ b/tests/component/imgdiff_test.cpp @@ -404,6 +404,86 @@ TEST(ImgdiffTest, image_mode_spurious_magic) { ASSERT_EQ(tgt, patched); } +TEST(ImgdiffTest, image_mode_short_input1) { + // src: "abcdefgh" + '0x1f8b0b'. + const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', '\x1f', '\x8b', '\x08' }; + const std::string src(src_data.cbegin(), src_data.cend()); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + // tgt: "abcdefgxyz". + const std::vector tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; + const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect one CHUNK_RAW (header) entry. + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(0U, num_deflate); + ASSERT_EQ(1U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + +TEST(ImgdiffTest, image_mode_short_input2) { + // src: "abcdefgh" + '0x1f8b0b00'. + const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' }; + const std::string src(src_data.cbegin(), src_data.cend()); + TemporaryFile src_file; + ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); + + // tgt: "abcdefgxyz". + const std::vector tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; + const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); + TemporaryFile tgt_file; + ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); + + TemporaryFile patch_file; + std::vector args = { + "imgdiff", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect one CHUNK_RAW (header) entry. + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(0U, num_deflate); + ASSERT_EQ(1U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + TEST(ImgdiffTest, image_mode_single_entry_long) { // src: "abcdefgh" + '0x1f8b0b00' + some bytes. const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', -- cgit v1.2.3 From 736d59c56754b86135d9156208645b8b1814fba1 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 3 Jan 2017 10:15:33 -0800 Subject: recovery: Fix the broken UI text. UI text is broken (doesn't show any text during FDR) due to commit d530449e54bd327e9c26209ffa0490c6508afe6c, which reordered the calls to RecoveryUI::SetLocale() and RecoveryUI::Init(). Because Init() uses the locale info to load the localized texts (from images), the locale must be set prior to that via SetLocale(). This CL refactors Init() to take the locale parameter, and removes the odd SetLocale() API. Bug: 34029338 Test: 'Run graphics test' under recovery. Change-Id: I620394a3d4e3705e9af5a1f6299285d143ae1b01 --- tests/component/verifier_test.cpp | 70 +++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 32 deletions(-) (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 33aadb3fb..b740af96b 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -40,38 +40,44 @@ RecoveryUI* ui = NULL; class MockUI : public RecoveryUI { - bool Init() { return true; } - 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() { } + bool Init(const std::string&) override { + return true; + } + void SetStage(int, int) override {} + void SetBackground(Icon /*icon*/) override {} + void SetSystemUpdateText(bool /*security_update*/) override {} + + void SetProgressType(ProgressType /*determinate*/) override {} + void ShowProgress(float /*portion*/, float /*seconds*/) override {} + void SetProgress(float /*fraction*/) override {} + + void ShowText(bool /*visible*/) override {} + bool IsTextVisible() override { + return false; + } + bool WasTextEverVisible() override { + return false; + } + void Print(const char* fmt, ...) override { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } + void PrintOnScreenOnly(const char* fmt, ...) override { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } + void ShowFile(const char*) override {} + + void StartMenu(const char* const* /*headers*/, const char* const* /*items*/, + int /*initial_selection*/) override {} + int SelectMenu(int /*sel*/) override { + return 0; + } + void EndMenu() override {} }; void -- cgit v1.2.3 From 9aa7ab5b1021c39337d67e39afb41b40848c2c72 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 5 Jan 2017 17:27:19 -0800 Subject: tests: Add testcase for show_progress() and set_progress(). Test: recovery_component_test passes. Change-Id: I4f00d0171cf86699e9ce747d07d7d44a01906e81 --- tests/component/updater_test.cpp | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index f31f1f82a..fa5f03134 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include @@ -22,6 +23,8 @@ #include #include +#include +#include #include #include #include @@ -510,3 +513,50 @@ TEST_F(UpdaterTest, set_stage) { script = "set_stage(\"/dev/full\", \"1/3\")"; expect("", script.c_str(), kNoCause); } + +TEST_F(UpdaterTest, set_progress) { + // set_progress() expects one argument. + expect(nullptr, "set_progress()", kArgsParsingFailure); + expect(nullptr, "set_progress(\"arg1\", \"arg2\")", kArgsParsingFailure); + + // Invalid progress argument. + expect(nullptr, "set_progress(\"arg1\")", kArgsParsingFailure); + expect(nullptr, "set_progress(\"3x+5\")", kArgsParsingFailure); + expect(nullptr, "set_progress(\".3.5\")", kArgsParsingFailure); + + TemporaryFile tf; + UpdaterInfo updater_info; + updater_info.cmd_pipe = fdopen(tf.fd, "w"); + expect(".52", "set_progress(\".52\")", kNoCause, &updater_info); + fflush(updater_info.cmd_pipe); + + std::string cmd; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &cmd)); + ASSERT_EQ(android::base::StringPrintf("set_progress %f\n", .52), cmd); + // recovery-updater protocol expects 2 tokens ("set_progress "). + ASSERT_EQ(2U, android::base::Split(cmd, " ").size()); +} + +TEST_F(UpdaterTest, show_progress) { + // show_progress() expects two arguments. + expect(nullptr, "show_progress()", kArgsParsingFailure); + expect(nullptr, "show_progress(\"arg1\")", kArgsParsingFailure); + expect(nullptr, "show_progress(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); + + // Invalid progress arguments. + expect(nullptr, "show_progress(\"arg1\", \"arg2\")", kArgsParsingFailure); + expect(nullptr, "show_progress(\"3x+5\", \"10\")", kArgsParsingFailure); + expect(nullptr, "show_progress(\".3\", \"5a\")", kArgsParsingFailure); + + TemporaryFile tf; + UpdaterInfo updater_info; + updater_info.cmd_pipe = fdopen(tf.fd, "w"); + expect(".52", "show_progress(\".52\", \"10\")", kNoCause, &updater_info); + fflush(updater_info.cmd_pipe); + + std::string cmd; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &cmd)); + ASSERT_EQ(android::base::StringPrintf("progress %f %d\n", .52, 10), cmd); + // recovery-updater protocol expects 3 tokens ("progress "). + ASSERT_EQ(3U, android::base::Split(cmd, " ").size()); +} -- cgit v1.2.3 From 31653660adad6aa220f1a975545042126ee83b84 Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Wed, 11 Jan 2017 14:02:13 -0800 Subject: Remove "_static" suffix from libext4_utils. Bug: 34220783 Change-Id: I34ccc3b11da0d1b48805967ad75b9ddade569930 --- tests/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 0aca8c6c7..09cedccb9 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -99,7 +99,7 @@ LOCAL_STATIC_LIBRARIES := \ libfs_mgr \ liblog \ libselinux \ - libext4_utils_static \ + libext4_utils \ libsparse_static \ libcrypto_utils \ libcrypto \ -- cgit v1.2.3 From 67f3aa880499c1143ed9aa1e5294a912a6962f28 Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Wed, 11 Jan 2017 14:38:20 -0800 Subject: Remove "_static" suffix from libsparse Bug: 34220783 Change-Id: I358f931f0b29f5bd526e1475180e477e2e90b936 --- tests/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 09cedccb9..1203817a2 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -100,7 +100,7 @@ LOCAL_STATIC_LIBRARIES := \ liblog \ libselinux \ libext4_utils \ - libsparse_static \ + libsparse \ libcrypto_utils \ libcrypto \ libcutils \ -- cgit v1.2.3 From d17a6885253da909e376ba5ca5084f5281f3557c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 9 Jan 2017 11:18:29 -0800 Subject: Add checkers and tests for empty locale in PNG file match_locale() will return false for empty locale string in the PNG file. Also add a manual test to validate if a PNG file is qualified to use under recovery. Bug: 34054052 Test: recovery_manual_test catches invalid PNG files successfully & Locale_test passed Change-Id: Id7e2136e1d8abf20da15825aa7901effbced8b03 --- tests/Android.mk | 28 ++++++++- tests/manual/recovery_test.cpp | 138 +++++++++++++++++++++++++++++++++++++++++ tests/unit/locale_test.cpp | 3 + 3 files changed, 167 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 1203817a2..1dbd2b614 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -49,10 +49,34 @@ LOCAL_CLANG := true LOCAL_CFLAGS := -Werror LOCAL_MODULE := recovery_manual_test LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_STATIC_LIBRARIES := libbase +LOCAL_STATIC_LIBRARIES := \ + libminui \ + libbase LOCAL_SRC_FILES := manual/recovery_test.cpp -LOCAL_SHARED_LIBRARIES := liblog +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libpng + +resource_files := $(call find-files-in-subdirs, bootable/recovery, \ + "*_text.png", \ + res-mdpi/images \ + res-hdpi/images \ + res-xhdpi/images \ + res-xxhdpi/images \ + res-xxxhdpi/images \ + ) + +# The resource image files that will go to $OUT/data/nativetest/recovery. +testimage_out_path := $(TARGET_OUT_DATA)/nativetest/recovery +GEN := $(addprefix $(testimage_out_path)/, $(resource_files)) + +$(GEN): PRIVATE_PATH := $(LOCAL_PATH) +$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@ +$(GEN): $(testimage_out_path)/% : bootable/recovery/% + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + include $(BUILD_NATIVE_TEST) # Component tests diff --git a/tests/manual/recovery_test.cpp b/tests/manual/recovery_test.cpp index e73cb1509..d36dd331e 100644 --- a/tests/manual/recovery_test.cpp +++ b/tests/manual/recovery_test.cpp @@ -14,19 +14,27 @@ * limitations under the License. */ +#include #include #include #include #include +#include #include +#include #include #include +#include #include +#include "minui/minui.h" + static const std::string myFilename = "/data/misc/recovery/inject.txt"; static const std::string myContent = "Hello World\nWelcome to my recovery\n"; +static const std::string kLocale = "zu"; +static const std::string kResourceTestDir = "/data/nativetest/recovery/"; // Failure is expected on systems that do not deliver either the // recovery-persist or recovery-refresh executables. Tests also require @@ -84,3 +92,133 @@ TEST(recovery, persist) { } EXPECT_EQ(0, unlink(myFilename.c_str())); } + +std::vector image_dir { + "res-mdpi/images/", + "res-hdpi/images/", + "res-xhdpi/images/", + "res-xxhdpi/images/", + "res-xxxhdpi/images/" +}; + +static int png_filter(const dirent* de) { + if (de->d_type != DT_REG || !android::base::EndsWith(de->d_name, "_text.png")) { + return 0; + } + return 1; +} + +// Find out all png files to test under /data/nativetest/recovery/. +static std::vector add_files() { + std::vector files; + for (const std::string& str : image_dir) { + std::string dir_path = kResourceTestDir + str; + dirent** namelist; + int n = scandir(dir_path.c_str(), &namelist, png_filter, alphasort); + if (n == -1) { + printf("Failed to scan dir %s: %s\n", kResourceTestDir.c_str(), strerror(errno)); + return files; + } + if (n == 0) { + printf("No file is added for test in %s\n", kResourceTestDir.c_str()); + } + + while (n--) { + std::string file_path = dir_path + namelist[n]->d_name; + files.push_back(file_path); + free(namelist[n]); + } + free(namelist); + } + return files; +} + +class ResourceTest : public testing::TestWithParam { + public: + static std::vector png_list; + + // Parse a png file and test if it's qualified for the background text image + // under recovery. + void SetUp() override { + std::string file_path = GetParam(); + fp = fopen(file_path.c_str(), "rb"); + ASSERT_NE(nullptr, fp); + + unsigned char header[8]; + size_t bytesRead = fread(header, 1, sizeof(header), fp); + ASSERT_EQ(sizeof(header), bytesRead); + ASSERT_EQ(0, png_sig_cmp(header, 0, sizeof(header))); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + ASSERT_NE(nullptr, png_ptr); + + info_ptr = png_create_info_struct(png_ptr); + ASSERT_NE(nullptr, info_ptr); + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, sizeof(header)); + png_read_info(png_ptr, info_ptr); + + int color_type, bit_depth; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, + nullptr); + ASSERT_EQ(PNG_COLOR_TYPE_GRAY, color_type) << "Recovery expects grayscale PNG file."; + ASSERT_LT(static_cast(5), width); + ASSERT_LT(static_cast(0), height); + if (bit_depth <= 8) { + // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. + png_set_expand_gray_1_2_4_to_8(png_ptr); + } + + png_byte channels = png_get_channels(png_ptr, info_ptr); + ASSERT_EQ(1, channels) << "Recovery background text images expects 1-channel PNG file."; + } + + void TearDown() override { + if (png_ptr != nullptr && info_ptr != nullptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + } + + if (fp != nullptr) { + fclose(fp); + } + } + + protected: + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + + FILE* fp; +}; + +std::vector ResourceTest::png_list = add_files(); + +TEST_P(ResourceTest, ValidateLocale) { + std::vector row(width); + for (png_uint_32 y = 0; y < height; ++y) { + png_read_row(png_ptr, row.data(), nullptr); + int w = (row[1] << 8) | row[0]; + int h = (row[3] << 8) | row[2]; + int len = row[4]; + EXPECT_LT(0, w); + EXPECT_LT(0, h); + EXPECT_LT(0, len) << "Locale string should be non-empty."; + EXPECT_NE(0, row[5]) << "Locale string is missing."; + + ASSERT_GT(height, y + 1 + h) << "Locale: " << kLocale << " is not found in the file."; + char* loc = reinterpret_cast(&row[5]); + if (matches_locale(loc, kLocale.c_str())) { + EXPECT_TRUE(android::base::StartsWith(loc, kLocale.c_str())); + break; + } else { + for (int i = 0; i < h; ++i, ++y) { + png_read_row(png_ptr, row.data(), nullptr); + } + } + } +} + +INSTANTIATE_TEST_CASE_P(BackgroundTextValidation, ResourceTest, + ::testing::ValuesIn(ResourceTest::png_list.cbegin(), + ResourceTest::png_list.cend())); diff --git a/tests/unit/locale_test.cpp b/tests/unit/locale_test.cpp index 0e515f8c1..f73235005 100644 --- a/tests/unit/locale_test.cpp +++ b/tests/unit/locale_test.cpp @@ -26,4 +26,7 @@ TEST(LocaleTest, Misc) { EXPECT_TRUE(matches_locale("en", "en_GB")); EXPECT_FALSE(matches_locale("en_GB", "en")); EXPECT_FALSE(matches_locale("en_GB", "en_US")); + EXPECT_FALSE(matches_locale("en_US", "")); + // Empty locale prefix in the PNG file will match the input locale. + EXPECT_TRUE(matches_locale("", "en_US")); } -- cgit v1.2.3 From 7c5dbd67517b4c96455617ed59628e1de0b3fcbb Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Fri, 13 Jan 2017 17:32:20 -0800 Subject: Remove '_static' suffix from libext2* references. Bug: 34220783 Test: make checkbuild Change-Id: Iceea20e440a4bb6a3b254486a65a86401a2241ef --- tests/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 1dbd2b614..a7e7b3c35 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -100,7 +100,7 @@ tune2fs_static_libraries := \ libext2_com_err \ libext2_blkid \ libext2_quota \ - libext2_uuid_static \ + libext2_uuid \ libext2_e2p \ libext2fs -- cgit v1.2.3 From 25c56979dd85a33a6467949ab76f99a987a0a006 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 10 May 2016 15:23:25 -0700 Subject: Use bspatch from external/bsdiff. Now ApplyBSDiffPatch() will stream the output to sink as we go instead of sinking everything at the end. Test: recovery_host_test Bug: 26982501 Change-Id: I05b6ed40d45e4b1b19ae72784cf705b731b976e3 --- tests/Android.mk | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index a7e7b3c35..3ab5ea6c2 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -111,6 +111,7 @@ LOCAL_STATIC_LIBRARIES := \ libimgdiff \ libimgpatch \ libbsdiff \ + libbspatch \ libotafault \ libupdater \ libbootloader_message \ @@ -173,6 +174,7 @@ LOCAL_STATIC_LIBRARIES := \ libimgdiff \ libimgpatch \ libbsdiff \ + libbspatch \ libziparchive \ libbase \ libcrypto \ -- cgit v1.2.3 From ca948564168a597c2d51a26555e327001f7eecc4 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 28 Feb 2017 12:26:29 -0800 Subject: Skip BootloaderMessageTest, UncryptTest for devices without /misc Skip these two tests if /misc partition is not found in fstab. Bug: 35712836 Test: Both test skip correctly if there's no /misc in fstab.${hardware}. Change-Id: I38417a8677030229a335e43eaef85ae70c4e0845 --- tests/common/component_test_util.h | 50 +++++++++++++++++++++++++++++ tests/component/bootloader_message_test.cpp | 44 +++++++++++++++++++++++-- tests/component/uncrypt_test.cpp | 20 +++++++++++- 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 tests/common/component_test_util.h (limited to 'tests') diff --git a/tests/common/component_test_util.h b/tests/common/component_test_util.h new file mode 100644 index 000000000..44322972b --- /dev/null +++ b/tests/common/component_test_util.h @@ -0,0 +1,50 @@ +/* + * 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 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 _COMPONENT_TEST_UTIL_H +#define _COMPONENT_TEST_UTIL_H + +#include + +#include +#include + +// Check if the /misc entry exists in the fstab. +static bool parse_misc() { + // The fstab path is "/fstab.${ro.hardware}". + std::string ro_hardware = android::base::GetProperty("ro.hardware", ""); + if (ro_hardware.empty()) { + GTEST_LOG_(INFO) << "Failed to get ro.hardware."; + return false; + } + + std::string fstab_path = "/fstab." + ro_hardware; + fstab* fstab = fs_mgr_read_fstab(fstab_path.c_str()); + if (fstab == nullptr) { + GTEST_LOG_(INFO) << "Failed to read " << fstab_path; + return false; + } + + fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc"); + if (record == nullptr) { + GTEST_LOG_(INFO) << "Failed to find /misc in fstab."; + return false; + } + return true; +} + +#endif //_COMPONENT_TEST_UTIL_H + diff --git a/tests/component/bootloader_message_test.cpp b/tests/component/bootloader_message_test.cpp index dbcaf619e..c32519d80 100644 --- a/tests/component/bootloader_message_test.cpp +++ b/tests/component/bootloader_message_test.cpp @@ -14,23 +14,38 @@ * limitations under the License. */ +#include +#include + #include #include #include -#include -#include +#include "common/component_test_util.h" class BootloaderMessageTest : public ::testing::Test { protected: + BootloaderMessageTest() : has_misc(true) {} + + virtual void SetUp() override { + has_misc = parse_misc(); + } + virtual void TearDown() override { // Clear the BCB. std::string err; ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err; } + + bool has_misc; }; TEST_F(BootloaderMessageTest, clear_bootloader_message) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Clear the BCB. std::string err; ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err; @@ -45,6 +60,11 @@ TEST_F(BootloaderMessageTest, clear_bootloader_message) { } TEST_F(BootloaderMessageTest, read_and_write_bootloader_message) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Write the BCB. bootloader_message boot = {}; strlcpy(boot.command, "command", sizeof(boot.command)); @@ -63,6 +83,11 @@ TEST_F(BootloaderMessageTest, read_and_write_bootloader_message) { } TEST_F(BootloaderMessageTest, write_bootloader_message_options) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Write the options to BCB. std::vector options = { "option1", "option2" }; std::string err; @@ -88,6 +113,11 @@ TEST_F(BootloaderMessageTest, write_bootloader_message_options) { } TEST_F(BootloaderMessageTest, write_bootloader_message_options_empty) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Write empty vector. std::vector options; std::string err; @@ -109,6 +139,11 @@ TEST_F(BootloaderMessageTest, write_bootloader_message_options_empty) { } TEST_F(BootloaderMessageTest, write_bootloader_message_options_long) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Write super long message. std::vector options; for (int i = 0; i < 100; i++) { @@ -139,6 +174,11 @@ TEST_F(BootloaderMessageTest, write_bootloader_message_options_long) { } TEST_F(BootloaderMessageTest, update_bootloader_message) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Inject some bytes into boot, which should be not overwritten later. bootloader_message boot; strlcpy(boot.recovery, "random message", sizeof(boot.recovery)); diff --git a/tests/component/uncrypt_test.cpp b/tests/component/uncrypt_test.cpp index a554c3e48..4f2b8164f 100644 --- a/tests/component/uncrypt_test.cpp +++ b/tests/component/uncrypt_test.cpp @@ -29,6 +29,8 @@ #include #include +#include "common/component_test_util.h" + static const std::string UNCRYPT_SOCKET = "/dev/socket/uncrypt"; static const std::string INIT_SVC_SETUP_BCB = "init.svc.setup-bcb"; static const std::string INIT_SVC_CLEAR_BCB = "init.svc.clear-bcb"; @@ -37,7 +39,9 @@ static constexpr int SOCKET_CONNECTION_MAX_RETRY = 30; class UncryptTest : public ::testing::Test { protected: - virtual void SetUp() { + UncryptTest() : has_misc(true) {} + + virtual void SetUp() override { ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb")); ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb")); ASSERT_TRUE(android::base::SetProperty("ctl.stop", "uncrypt")); @@ -57,10 +61,19 @@ class UncryptTest : public ::testing::Test { } ASSERT_TRUE(success) << "uncrypt service is not available."; + + has_misc = parse_misc(); } + + bool has_misc; }; TEST_F(UncryptTest, setup_bcb) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Trigger the setup-bcb service. ASSERT_TRUE(android::base::SetProperty("ctl.start", "setup-bcb")); @@ -126,6 +139,11 @@ TEST_F(UncryptTest, setup_bcb) { } TEST_F(UncryptTest, clear_bcb) { + if (!has_misc) { + GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device."; + return; + } + // Trigger the clear-bcb service. ASSERT_TRUE(android::base::SetProperty("ctl.start", "clear-bcb")); -- cgit v1.2.3 From b72a15a2ab48c3944237a15f899faa237ee43974 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 2 Mar 2017 13:46:37 -0800 Subject: Recovery Test: add SideloadTest to test FUSE support on target FUSE FS is required in recovery sideload functionalites. This CL is to add a native test to flag when FUSE is not supported in the device kernel. Bug: 35768196 Test: mma, run recovery_component_test on marlin and pass all Change-Id: I43b6dbee658010df56ba4d4b0e91baa7fd1c4480 --- tests/Android.mk | 1 + tests/component/sideload_test.cpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/component/sideload_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 3ab5ea6c2..c7d33256a 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -90,6 +90,7 @@ LOCAL_SRC_FILES := \ component/bootloader_message_test.cpp \ component/edify_test.cpp \ component/imgdiff_test.cpp \ + component/sideload_test.cpp \ component/uncrypt_test.cpp \ component/updater_test.cpp \ component/verifier_test.cpp diff --git a/tests/component/sideload_test.cpp b/tests/component/sideload_test.cpp new file mode 100644 index 000000000..ea93e9b84 --- /dev/null +++ b/tests/component/sideload_test.cpp @@ -0,0 +1,21 @@ +/* + * 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. + */ +#include +#include + +TEST(SideloadTest, fusedevice) { + ASSERT_NE(-1, access("/dev/fuse", R_OK | W_OK)); +} -- cgit v1.2.3 From cace743c4db6e73bc8ff3a0eee1f8f2044054ca7 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 3 Mar 2017 11:28:49 -0800 Subject: Fix an error on bootloadermessager test teardown The test should not clear bcb during teardown on devices without /misc. Bug: 35712836 Test: The test tears down without errors after /misc removed from the fstab. Change-Id: I42df89feb18fac5a435cd17eef97a6bad0f44545 --- tests/component/bootloader_message_test.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/component/bootloader_message_test.cpp b/tests/component/bootloader_message_test.cpp index c32519d80..0357accfe 100644 --- a/tests/component/bootloader_message_test.cpp +++ b/tests/component/bootloader_message_test.cpp @@ -33,8 +33,10 @@ class BootloaderMessageTest : public ::testing::Test { virtual void TearDown() override { // Clear the BCB. - std::string err; - ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err; + if (has_misc) { + std::string err; + ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err; + } } bool has_misc; -- cgit v1.2.3 From 1ea84d6da97f4c4269ac16c4d332bbff3466b1b8 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 22 Feb 2017 18:23:58 -0800 Subject: Refractor the code for imgdiff Put ImageChunk and some helper functions into a class. Also switch to using std::vector instead of malloc. Bug: 18606652 Test: imgdiff_test passed on host. Also generate a complete incremental OTA package. The file content is the same and time consumption is similar. Change-Id: Id603ada4e130ef521218400761a119001a86ca79 --- tests/Android.mk | 1 + tests/component/imgdiff_test.cpp | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 3ab5ea6c2..9ee27a06a 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -176,6 +176,7 @@ LOCAL_STATIC_LIBRARIES := \ libbsdiff \ libbspatch \ libziparchive \ + libutils \ libbase \ libcrypto \ libbz \ diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp index 7ad330783..be2dd385b 100644 --- a/tests/component/imgdiff_test.cpp +++ b/tests/component/imgdiff_test.cpp @@ -236,6 +236,62 @@ TEST(ImgdiffTest, zip_mode_smoke_compressed) { ASSERT_EQ(tgt, patched); } +TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) { + // Construct src and tgt zip files. + TemporaryFile src_file; + FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + ZipWriter src_writer(src_file_ptr); + ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress)); + const std::string src_content("abcdefg"); + ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size())); + ASSERT_EQ(0, src_writer.FinishEntry()); + ASSERT_EQ(0, src_writer.Finish()); + ASSERT_EQ(0, fclose(src_file_ptr)); + + TemporaryFile tgt_file; + FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + ZipWriter tgt_writer(tgt_file_ptr); + ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress)); + const std::string tgt_content("abcdefgxyz"); + ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size())); + ASSERT_EQ(0, tgt_writer.FinishEntry()); + ASSERT_EQ(0, tgt_writer.Finish()); + // Add trailing zeros to the target zip file. + std::vector zeros(10); + ASSERT_EQ(zeros.size(), fwrite(zeros.data(), sizeof(uint8_t), zeros.size(), tgt_file_ptr)); + ASSERT_EQ(0, fclose(tgt_file_ptr)); + + // Compute patch. + TemporaryFile patch_file; + std::vector args = { + "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path, + }; + ASSERT_EQ(0, imgdiff(args.size(), args.data())); + + // Verify. + std::string tgt; + ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); + std::string src; + ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src)); + std::string patch; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); + + // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). + size_t num_normal; + size_t num_raw; + size_t num_deflate; + verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); + ASSERT_EQ(0U, num_normal); + ASSERT_EQ(1U, num_deflate); + ASSERT_EQ(2U, num_raw); + + std::string patched; + ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast(src.data()), src.size(), + reinterpret_cast(patch.data()), patch.size(), + MemorySink, &patched)); + ASSERT_EQ(tgt, patched); +} + TEST(ImgdiffTest, image_mode_simple) { // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd). const std::vector src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', -- cgit v1.2.3 From d13b6cf29c71412adac3b0dca5eddcd6c75f5163 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Fri, 10 Mar 2017 16:00:40 +0800 Subject: recovery: replacing fs_mgr_read_fstab() with new fs_mgr APIs The fstab settings of early-mounted partitions (e.g., /vendor) will be in kernel device tree. Switch to the new API to get the whole settings with those in device tree: fs_mgr_read_fstab_with_dt("/etc/recovery.fstab") The original default /fstab.{ro.hardware} might be moved to /vendor/etc/. or /odm/etc/. Use another new API to get the default fstab instead of using the hard-coded /fstab.{ro.hardware}. This API also includes the settings from device tree: fs_mgr_read_fstab_default() Bug: 35811655 Test: boot sailfish recovery Change-Id: Iaa56ac7f7b4c4dfc7180c65f03e9a37b94f1de09 --- tests/common/component_test_util.h | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'tests') diff --git a/tests/common/component_test_util.h b/tests/common/component_test_util.h index 44322972b..3fee32d62 100644 --- a/tests/common/component_test_util.h +++ b/tests/common/component_test_util.h @@ -24,21 +24,14 @@ // Check if the /misc entry exists in the fstab. static bool parse_misc() { - // The fstab path is "/fstab.${ro.hardware}". - std::string ro_hardware = android::base::GetProperty("ro.hardware", ""); - if (ro_hardware.empty()) { - GTEST_LOG_(INFO) << "Failed to get ro.hardware."; + std::unique_ptr fstab(fs_mgr_read_fstab_default(), + fs_mgr_free_fstab); + if (!fstab) { + GTEST_LOG_(INFO) << "Failed to read default fstab"; return false; } - std::string fstab_path = "/fstab." + ro_hardware; - fstab* fstab = fs_mgr_read_fstab(fstab_path.c_str()); - if (fstab == nullptr) { - GTEST_LOG_(INFO) << "Failed to read " << fstab_path; - return false; - } - - fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc"); + fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab.get(), "/misc"); if (record == nullptr) { GTEST_LOG_(INFO) << "Failed to find /misc in fstab."; return false; -- cgit v1.2.3 From 63d786cf22cb44fe32e8b9c1f18b32da3c9d2e1b Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 8 Mar 2017 16:42:20 -0800 Subject: updater: Remove some obsoleted functions for file-based OTA. This CL removes the updater support for delete(), symlink(), rename(), set_metadata() and set_metadata_recursive(). Such functions have been removed from the generation script in commit f388104eaacd05cfa075d6478369e1d0df5ddbf3 (platform/build). Note: This CL also removes delete_recursive() which seems to have never been supported in generation script. Bug: 35853185 Test: recovery_component_test passes. Change-Id: I51e1ec946fa73761118fa1eaa082423df6d588e9 --- tests/component/updater_test.cpp | 113 --------------------------------------- 1 file changed, 113 deletions(-) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index fa5f03134..8c4bdbaa4 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -161,119 +161,6 @@ TEST_F(UpdaterTest, file_getprop) { expect("", script6.c_str(), kNoCause); } -TEST_F(UpdaterTest, delete) { - // Delete none. - expect("0", "delete()", kNoCause); - expect("0", "delete(\"/doesntexist\")", kNoCause); - expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\")", kNoCause); - expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\", \"/doesntexist3\")", kNoCause); - - // Delete one file. - TemporaryFile temp_file1; - ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); - std::string script1("delete(\"" + std::string(temp_file1.path) + "\")"); - expect("1", script1.c_str(), kNoCause); - - // Delete two files. - TemporaryFile temp_file2; - ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file2.path)); - TemporaryFile temp_file3; - ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file3.path)); - std::string script2("delete(\"" + std::string(temp_file2.path) + "\", \"" + - std::string(temp_file3.path) + "\")"); - expect("2", script2.c_str(), kNoCause); - - // Delete already deleted files. - expect("0", script2.c_str(), kNoCause); - - // Delete one out of three. - TemporaryFile temp_file4; - ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file4.path)); - std::string script3("delete(\"/doesntexist1\", \"" + std::string(temp_file4.path) + - "\", \"/doesntexist2\")"); - expect("1", script3.c_str(), kNoCause); -} - -TEST_F(UpdaterTest, rename) { - // rename() expects two arguments. - expect(nullptr, "rename()", kArgsParsingFailure); - expect(nullptr, "rename(\"arg1\")", kArgsParsingFailure); - expect(nullptr, "rename(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure); - - // src_name or dst_name cannot be empty. - expect(nullptr, "rename(\"\", \"arg2\")", kArgsParsingFailure); - expect(nullptr, "rename(\"arg1\", \"\")", kArgsParsingFailure); - - // File doesn't exist (both of src and dst). - expect(nullptr, "rename(\"/doesntexist\", \"/doesntexisteither\")" , kFileRenameFailure); - - // Can't create parent directory. - TemporaryFile temp_file1; - ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path)); - std::string script1("rename(\"" + std::string(temp_file1.path) + "\", \"/proc/0/file1\")"); - expect(nullptr, script1.c_str(), kFileRenameFailure); - - // Rename. - TemporaryFile temp_file2; - std::string script2("rename(\"" + std::string(temp_file1.path) + "\", \"" + - std::string(temp_file2.path) + "\")"); - expect(temp_file2.path, script2.c_str(), kNoCause); - - // Already renamed. - expect(temp_file2.path, script2.c_str(), kNoCause); - - // Parents create successfully. - TemporaryFile temp_file3; - TemporaryDir td; - std::string temp_dir(td.path); - std::string dst_file = temp_dir + "/aaa/bbb/a.txt"; - std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + dst_file + "\")"); - expect(dst_file.c_str(), script3.c_str(), kNoCause); - - // Clean up the temp files under td. - ASSERT_EQ(0, unlink(dst_file.c_str())); - ASSERT_EQ(0, rmdir((temp_dir + "/aaa/bbb").c_str())); - ASSERT_EQ(0, rmdir((temp_dir + "/aaa").c_str())); -} - -TEST_F(UpdaterTest, symlink) { - // symlink expects 1+ argument. - expect(nullptr, "symlink()", kArgsParsingFailure); - - // symlink should fail if src is an empty string. - TemporaryFile temp_file1; - std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")"); - expect(nullptr, script1.c_str(), kSymlinkFailure); - - std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"src1\", \"\")"); - expect(nullptr, script2.c_str(), kSymlinkFailure); - - // symlink failed to remove old src. - std::string script3("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")"); - expect(nullptr, script3.c_str(), kSymlinkFailure); - - // symlink can create symlinks. - TemporaryFile temp_file; - std::string content = "magicvalue"; - ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file.path)); - - TemporaryDir td; - std::string src1 = std::string(td.path) + "/symlink1"; - std::string src2 = std::string(td.path) + "/symlink2"; - std::string script4("symlink(\"" + std::string(temp_file.path) + "\", \"" + - src1 + "\", \"" + src2 + "\")"); - expect("t", script4.c_str(), kNoCause); - - // Verify the created symlinks. - struct stat sb; - ASSERT_TRUE(lstat(src1.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); - ASSERT_TRUE(lstat(src2.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)); - - // Clean up the leftovers. - ASSERT_EQ(0, unlink(src1.c_str())); - ASSERT_EQ(0, unlink(src2.c_str())); -} - TEST_F(UpdaterTest, package_extract_dir) { // package_extract_dir expects 2 arguments. expect(nullptr, "package_extract_dir()", kArgsParsingFailure); -- cgit v1.2.3 From 40e144dae877654f75e65242535036058ea48f58 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 15 Mar 2017 01:10:58 -0700 Subject: applypatch: Drop the support for patching non-EMMC targets. Patching regular files is used in file-based OTA only, which has become obsolete. Bug: 35853185 Test: Apply an incremental that patches the boot.img. Test: /system/bin/install-recovery.sh works. Test: recovery_component_test passes. Change-Id: Id44e42c4bc63f2162ecc8a6df1cb528b7ae6b0a9 --- tests/component/applypatch_test.cpp | 124 ------------------------------------ 1 file changed, 124 deletions(-) (limited to 'tests') diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index d178303aa..5cba68f8a 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -280,66 +280,6 @@ TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) { ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } -TEST_F(ApplyPatchFullTest, ApplyInPlace) { - std::vector sha1s = { bad_sha1_a, old_sha1 }; - ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_TRUE(file_cmp(old_file, new_file)); - - // reapply, applypatch is idempotent so it should succeed - ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_TRUE(file_cmp(old_file, new_file)); -} - -TEST_F(ApplyPatchFullTest, ApplyInNewLocation) { - std::vector sha1s = { bad_sha1_a, old_sha1 }; - // Apply bsdiff patch to new location. - ASSERT_EQ( - 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_TRUE(file_cmp(output_loc, new_file)); - - // Reapply to the same location. - ASSERT_EQ( - 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_TRUE(file_cmp(output_loc, new_file)); -} - -TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) { - std::vector sha1s = { bad_sha1_a, old_sha1 }; - // Apply bsdiff patch to new location with corrupted source. - mangle_file(old_file); - ASSERT_EQ( - 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_TRUE(file_cmp(output_loc, new_file)); - - // Reapply bsdiff patch to new location with corrupted source. - ASSERT_EQ( - 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_TRUE(file_cmp(output_loc, new_file)); -} - -TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) { - std::vector sha1s = { bad_sha1_a, old_sha1 }; - - // Apply bsdiff patch to new location with corrupted source and copy (no new file). - // Expected to fail. - mangle_file(old_file); - mangle_file(cache_file); - ASSERT_NE( - 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_FALSE(file_cmp(output_loc, new_file)); - - // Expected to fail again on retry. - ASSERT_NE( - 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_FALSE(file_cmp(output_loc, new_file)); - - // Expected to fail with incorrect new file. - mangle_file(output_loc); - ASSERT_NE( - 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr)); - ASSERT_FALSE(file_cmp(output_loc, new_file)); -} - TEST(ApplyPatchModesTest, InvalidArgs) { // At least two args (including the filename). ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" })); @@ -348,70 +288,6 @@ TEST(ApplyPatchModesTest, InvalidArgs) { ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" })); } -TEST(ApplyPatchModesTest, PatchMode) { - std::string boot_img = from_testdata_base("boot.img"); - size_t boot_img_size; - std::string boot_img_sha1; - sha1sum(boot_img, &boot_img_sha1, &boot_img_size); - - std::string recovery_img = from_testdata_base("recovery.img"); - std::string recovery_img_sha1; - size_t size; - sha1sum(recovery_img, &recovery_img_sha1, &size); - std::string recovery_img_size = std::to_string(size); - std::string bonus_file = from_testdata_base("bonus.file"); - - // applypatch -b : - TemporaryFile tmp1; - std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); - std::vector args = { - "applypatch", - "-b", - bonus_file.c_str(), - boot_img.c_str(), - tmp1.path, - recovery_img_sha1.c_str(), - recovery_img_size.c_str(), - patch.c_str() - }; - ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); - - // applypatch : - TemporaryFile tmp2; - patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); - std::vector args2 = { - "applypatch", - boot_img.c_str(), - tmp2.path, - recovery_img_sha1.c_str(), - recovery_img_size.c_str(), - patch.c_str() - }; - ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data())); - - // applypatch -b \ - // : : - TemporaryFile tmp3; - std::string bad_sha1_a = android::base::StringPrintf("%040x", rand()); - std::string bad_sha1_b = android::base::StringPrintf("%040x", rand()); - std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p"); - std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); - std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p"); - std::vector args3 = { - "applypatch", - "-b", - bonus_file.c_str(), - boot_img.c_str(), - tmp3.path, - recovery_img_sha1.c_str(), - recovery_img_size.c_str(), - patch1.c_str(), - patch2.c_str(), - patch3.c_str() - }; - ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data())); -} - TEST(ApplyPatchModesTest, PatchModeEmmcTarget) { std::string boot_img = from_testdata_base("boot.img"); size_t boot_img_size; -- cgit v1.2.3 From 12b90553d784b9d4ddd1b48300af6345bdf1085f Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 7 Mar 2017 14:44:14 -0800 Subject: More cleanup to imgdiff & imgpatch Also remove the utils in applypatch and replace them with the corresponding libbase functions. Test: recovery tests pass. Change-Id: I77254c141bd3e7d3d6894c23b60e866009516f81 --- tests/component/imgdiff_test.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp index be2dd385b..2f648501c 100644 --- a/tests/component/imgdiff_test.cpp +++ b/tests/component/imgdiff_test.cpp @@ -18,13 +18,14 @@ #include #include +#include #include #include #include #include #include -#include "applypatch/utils.h" +using android::base::get_unaligned; static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) { std::string* s = static_cast(token); @@ -41,7 +42,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si ASSERT_GE(size, 12U); ASSERT_EQ("IMGDIFF2", std::string(data, 8)); - const int num_chunks = Read4(data + 8); + const int num_chunks = get_unaligned(data + 8); ASSERT_GE(num_chunks, 0); size_t normal = 0; @@ -51,7 +52,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si size_t pos = 12; for (int i = 0; i < num_chunks; ++i) { ASSERT_LE(pos + 4, size); - int type = Read4(data + pos); + int type = get_unaligned(data + pos); pos += 4; if (type == CHUNK_NORMAL) { pos += 24; @@ -59,7 +60,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si normal++; } else if (type == CHUNK_RAW) { ASSERT_LE(pos + 4, size); - ssize_t data_len = Read4(data + pos); + ssize_t data_len = get_unaligned(data + pos); ASSERT_GT(data_len, 0); pos += 4 + data_len; ASSERT_LE(pos, size); -- cgit v1.2.3 From 56ebe620a241577ee2573649e57cc79c9931145b Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 16 Mar 2017 00:48:21 -0700 Subject: Add a test to perform block_image_update Add the following tests: stash src bspatch stashed_src tgt free stashed_src (expected a successful update) stash src free stashed_src fail_the_update (expected stashed_src freed) Bug: 36242722 Test: Test identified unfreed stashes correctly. Change-Id: I5a136e8dc31774367972fbfe8c63cbc1ddb3a113 --- tests/Android.mk | 9 ++- tests/component/updater_test.cpp | 120 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 123 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index ec971b38c..65f736d13 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -81,7 +81,10 @@ include $(BUILD_NATIVE_TEST) # Component tests include $(CLEAR_VARS) -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := \ + -Werror \ + -D_FILE_OFFSET_BITS=64 + LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := recovery_component_test LOCAL_C_INCLUDES := bootable/recovery @@ -136,6 +139,10 @@ LOCAL_STATIC_LIBRARIES := \ libz \ libbase \ libtune2fs \ + libfec \ + libfec_rs \ + libsquashfs_utils \ + libcutils \ $(tune2fs_static_libraries) testdata_files := $(call find-subdir-files, testdata/*) diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index 8c4bdbaa4..4f8349e2f 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -27,12 +28,17 @@ #include #include #include +#include #include #include +#include #include "common/test_constants.h" #include "edify/expr.h" #include "error_code.h" +#include "otautil/SysUtil.h" +#include "print_sha1.h" +#include "updater/blockimg.h" #include "updater/install.h" #include "updater/updater.h" @@ -64,12 +70,19 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c ASSERT_EQ(cause_code, state.cause_code); } +static std::string get_sha1(const std::string& content) { + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(content.c_str()), content.size(), digest); + return print_sha1(digest); +} + class UpdaterTest : public ::testing::Test { - protected: - virtual void SetUp() { - RegisterBuiltins(); - RegisterInstallFunctions(); - } + protected: + virtual void SetUp() override { + RegisterBuiltins(); + RegisterInstallFunctions(); + RegisterBlockImageFunctions(); + } }; TEST_F(UpdaterTest, getprop) { @@ -447,3 +460,100 @@ TEST_F(UpdaterTest, show_progress) { // recovery-updater protocol expects 3 tokens ("progress "). ASSERT_EQ(3U, android::base::Split(cmd, " ").size()); } + +TEST_F(UpdaterTest, block_image_update) { + // Create a zip file with new_data and patch_data. + TemporaryFile zip_file; + FILE* zip_file_ptr = fdopen(zip_file.fd, "wb"); + ZipWriter zip_writer(zip_file_ptr); + + // Add a dummy new data. + ASSERT_EQ(0, zip_writer.StartEntry("new_data", 0)); + ASSERT_EQ(0, zip_writer.FinishEntry()); + + // Generate and add the patch data. + std::string src_content = std::string(4096, 'a') + std::string(4096, 'c'); + std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd'); + TemporaryFile patch_file; + ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast(src_content.data()), + src_content.size(), reinterpret_cast(tgt_content.data()), + tgt_content.size(), patch_file.path, nullptr)); + std::string patch_content; + ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content)); + ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0)); + ASSERT_EQ(0, zip_writer.WriteBytes(patch_content.data(), patch_content.size())); + ASSERT_EQ(0, zip_writer.FinishEntry()); + + // Add two transfer lists. The first one contains a bsdiff; and we expect the update to succeed. + std::string src_hash = get_sha1(src_content); + std::string tgt_hash = get_sha1(tgt_content); + std::vector transfer_list = { + "4", + "2", + "0", + "2", + "stash " + src_hash + " 2,0,2", + android::base::StringPrintf("bsdiff 0 %zu %s %s 2,0,2 2 - %s:2,0,2", patch_content.size(), + src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()), + "free " + src_hash, + }; + ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); + std::string commands = android::base::Join(transfer_list, '\n'); + ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); + ASSERT_EQ(0, zip_writer.FinishEntry()); + + // Stash and free some blocks, then fail the 2nd update intentionally. + std::vector fail_transfer_list = { + "4", + "2", + "0", + "2", + "stash " + tgt_hash + " 2,0,2", + "free " + tgt_hash, + "fail", + }; + ASSERT_EQ(0, zip_writer.StartEntry("fail_transfer_list", 0)); + std::string fail_commands = android::base::Join(fail_transfer_list, '\n'); + ASSERT_EQ(0, zip_writer.WriteBytes(fail_commands.data(), fail_commands.size())); + ASSERT_EQ(0, zip_writer.FinishEntry()); + ASSERT_EQ(0, zip_writer.Finish()); + ASSERT_EQ(0, fclose(zip_file_ptr)); + + MemMapping map; + ASSERT_EQ(0, sysMapFile(zip_file.path, &map)); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle)); + + // Set up the handler, command_pipe, patch offset & length. + UpdaterInfo updater_info; + updater_info.package_zip = handle; + TemporaryFile temp_pipe; + updater_info.cmd_pipe = fopen(temp_pipe.path, "wb"); + updater_info.package_zip_addr = map.addr; + updater_info.package_zip_len = map.length; + + // Execute the commands in the 1st transfer list. + TemporaryFile update_file; + ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path)); + std::string script = "block_image_update(\"" + std::string(update_file.path) + + R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))"; + expect("t", script.c_str(), kNoCause, &updater_info); + // The update_file should be patched correctly. + std::string updated_content; + ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content)); + ASSERT_EQ(tgt_hash, get_sha1(updated_content)); + + // Expect the 2nd update to fail, but expect the stashed blocks to be freed. + script = "block_image_update(\"" + std::string(update_file.path) + + R"(", package_extract_file("fail_transfer_list"), "new_data", "patch_data"))"; + expect("", script.c_str(), kNoCause, &updater_info); + // Updater generates the stash name based on the input file name. + std::string name_digest = get_sha1(update_file.path); + std::string stash_base = "/cache/recovery/" + name_digest; + ASSERT_EQ(0, access(stash_base.c_str(), F_OK)); + ASSERT_EQ(-1, access((stash_base + tgt_hash).c_str(), F_OK)); + ASSERT_EQ(0, rmdir(stash_base.c_str())); + + ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); + CloseArchive(handle); +} -- cgit v1.2.3 From 5e535014dd7961fbf812abeaa27f3339775031f1 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 16 Mar 2017 17:37:38 -0700 Subject: Drop the dependency on 'ui' in verify_file(). verify_file() has a dependency on the global variable of 'ui' for posting the verification progress, which requires the users of libverifier to provide a UI instance. This CL adds an optional argument to verify_file() so that it can post the progress through the provided callback function. As a result, we can drop the MockUI class in verifier_test.cpp. Test: recovery_component_test passes. Test: verify_file() posts progress update when installing an OTA. Change-Id: I8b87d0f0d99777ea755d33d6dbbe2b6d44243bf1 --- tests/component/verifier_test.cpp | 149 ++++++++++++-------------------------- 1 file changed, 45 insertions(+), 104 deletions(-) (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index b740af96b..460585d22 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -22,93 +22,34 @@ #include #include -#include #include #include -#include - +#include #include -#include +#include -#include "common.h" #include "common/test_constants.h" #include "otautil/SysUtil.h" -#include "ui.h" #include "verifier.h" -RecoveryUI* ui = NULL; - -class MockUI : public RecoveryUI { - bool Init(const std::string&) override { - return true; - } - void SetStage(int, int) override {} - void SetBackground(Icon /*icon*/) override {} - void SetSystemUpdateText(bool /*security_update*/) override {} - - void SetProgressType(ProgressType /*determinate*/) override {} - void ShowProgress(float /*portion*/, float /*seconds*/) override {} - void SetProgress(float /*fraction*/) override {} - - void ShowText(bool /*visible*/) override {} - bool IsTextVisible() override { - return false; - } - bool WasTextEverVisible() override { - return false; - } - void Print(const char* fmt, ...) override { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - void PrintOnScreenOnly(const char* fmt, ...) override { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - void ShowFile(const char*) override {} - - void StartMenu(const char* const* /*headers*/, const char* const* /*items*/, - int /*initial_selection*/) override {} - int SelectMenu(int /*sel*/) override { - return 0; - } - void EndMenu() override {} -}; - -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> { - public: - MemMapping memmap; - std::vector certs; - - virtual void SetUp() { - std::vector args = GetParam(); - std::string package = from_testdata_base(args[0]); - if (sysMapFile(package.c_str(), &memmap) != 0) { - FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n"; - } - - for (auto it = ++(args.cbegin()); it != args.cend(); ++it) { - std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt"); - ASSERT_TRUE(load_keys(public_key_file.c_str(), certs)); - } + protected: + void SetUp() override { + std::vector args = GetParam(); + std::string package = from_testdata_base(args[0]); + if (sysMapFile(package.c_str(), &memmap) != 0) { + FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n"; } - static void SetUpTestCase() { - ui = new MockUI(); + for (auto it = ++args.cbegin(); it != args.cend(); ++it) { + std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt"); + ASSERT_TRUE(load_keys(public_key_file.c_str(), certs)); } + } + + MemMapping memmap; + std::vector certs; }; class VerifierSuccessTest : public VerifierTest { @@ -118,47 +59,47 @@ class VerifierFailureTest : public VerifierTest { }; TEST_P(VerifierSuccessTest, VerifySucceed) { - ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS); + ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_SUCCESS); } TEST_P(VerifierFailureTest, VerifyFailure) { - ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE); + ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_FAILURE); } INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v1"}), - std::vector({"otasigned_v2.zip", "v2"}), - std::vector({"otasigned_v3.zip", "v3"}), - std::vector({"otasigned_v4.zip", "v4"}), - std::vector({"otasigned_v5.zip", "v5"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v1"}), + std::vector({"otasigned_v2.zip", "v2"}), + std::vector({"otasigned_v3.zip", "v3"}), + std::vector({"otasigned_v4.zip", "v4"}), + std::vector({"otasigned_v5.zip", "v5"}))); INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v1", "v2"}), - std::vector({"otasigned_v2.zip", "v5", "v2"}), - std::vector({"otasigned_v3.zip", "v5", "v1", "v3"}), - std::vector({"otasigned_v4.zip", "v5", "v1", "v4"}), - std::vector({"otasigned_v5.zip", "v4", "v1", "v5"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v1", "v2"}), + std::vector({"otasigned_v2.zip", "v5", "v2"}), + std::vector({"otasigned_v3.zip", "v5", "v1", "v3"}), + std::vector({"otasigned_v4.zip", "v5", "v1", "v4"}), + std::vector({"otasigned_v5.zip", "v4", "v1", "v5"}))); INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v2"}), - std::vector({"otasigned_v2.zip", "v1"}), - std::vector({"otasigned_v3.zip", "v5"}), - std::vector({"otasigned_v4.zip", "v5"}), - std::vector({"otasigned_v5.zip", "v3"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v2"}), + std::vector({"otasigned_v2.zip", "v1"}), + std::vector({"otasigned_v3.zip", "v5"}), + std::vector({"otasigned_v4.zip", "v5"}), + std::vector({"otasigned_v5.zip", "v3"}))); INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v3"}), - std::vector({"otasigned_v2.zip", "v4"}), - std::vector({"otasigned_v3.zip", "v1"}), - std::vector({"otasigned_v4.zip", "v2"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v3"}), + std::vector({"otasigned_v2.zip", "v4"}), + std::vector({"otasigned_v3.zip", "v1"}), + std::vector({"otasigned_v4.zip", "v2"}))); INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest, - ::testing::Values( - std::vector({"random.zip", "v1"}), - std::vector({"fake-eocd.zip", "v1"}), - std::vector({"alter-metadata.zip", "v1"}), - std::vector({"alter-footer.zip", "v1"}))); + ::testing::Values( + std::vector({"random.zip", "v1"}), + std::vector({"fake-eocd.zip", "v1"}), + std::vector({"alter-metadata.zip", "v1"}), + std::vector({"alter-footer.zip", "v1"}))); -- cgit v1.2.3 From 7b22c92ac1265f439f8e2623c4a1d6b45bbb05f2 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 16 Mar 2017 17:37:38 -0700 Subject: Drop the dependency on 'ui' in verify_file(). verify_file() has a dependency on the global variable of 'ui' for posting the verification progress, which requires the users of libverifier to provide a UI instance. This CL adds an optional argument to verify_file() so that it can post the progress through the provided callback function. As a result, we can drop the MockUI class in verifier_test.cpp. Test: recovery_component_test passes. Test: verify_file() posts progress update when installing an OTA. Change-Id: I8b87d0f0d99777ea755d33d6dbbe2b6d44243bf1 (cherry picked from commit 5e535014dd7961fbf812abeaa27f3339775031f1) --- tests/component/verifier_test.cpp | 151 ++++++++++++-------------------------- 1 file changed, 46 insertions(+), 105 deletions(-) (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 4294d90eb..03829f393 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -22,93 +22,34 @@ #include #include -#include #include #include -#include - +#include #include -#include +#include -#include "common.h" #include "common/test_constants.h" #include "otautil/SysUtil.h" -#include "ui.h" #include "verifier.h" -RecoveryUI* ui = NULL; - -class MockUI : public RecoveryUI { - bool Init(const std::string&) override { - return true; - } - void SetStage(int, int) override {} - void SetBackground(Icon /*icon*/) override {} - void SetSystemUpdateText(bool /*security_update*/) override {} - - void SetProgressType(ProgressType /*determinate*/) override {} - void ShowProgress(float /*portion*/, float /*seconds*/) override {} - void SetProgress(float /*fraction*/) override {} - - void ShowText(bool /*visible*/) override {} - bool IsTextVisible() override { - return false; - } - bool WasTextEverVisible() override { - return false; - } - void Print(const char* fmt, ...) override { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - void PrintOnScreenOnly(const char* fmt, ...) override { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - void ShowFile(const char*) override {} - - void StartMenu(const char* const* /*headers*/, const char* const* /*items*/, - int /*initial_selection*/) override {} - int SelectMenu(int /*sel*/) override { - return 0; - } - void EndMenu() override {} -}; - -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> { - public: - MemMapping memmap; - std::vector certs; - - virtual void SetUp() { - std::vector args = GetParam(); - std::string package = from_testdata_base(args[0]); - if (sysMapFile(package.c_str(), &memmap) != 0) { - FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n"; - } - - for (auto it = ++(args.cbegin()); it != args.cend(); ++it) { - std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt"); - ASSERT_TRUE(load_keys(public_key_file.c_str(), certs)); - } + protected: + void SetUp() override { + std::vector args = GetParam(); + std::string package = from_testdata_base(args[0]); + if (sysMapFile(package.c_str(), &memmap) != 0) { + FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n"; } - static void SetUpTestCase() { - ui = new MockUI(); + for (auto it = ++args.cbegin(); it != args.cend(); ++it) { + std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt"); + ASSERT_TRUE(load_keys(public_key_file.c_str(), certs)); } + } + + MemMapping memmap; + std::vector certs; }; class VerifierSuccessTest : public VerifierTest { @@ -118,48 +59,48 @@ class VerifierFailureTest : public VerifierTest { }; TEST_P(VerifierSuccessTest, VerifySucceed) { - ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS); + ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_SUCCESS); } TEST_P(VerifierFailureTest, VerifyFailure) { - ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE); + ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_FAILURE); } INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v1"}), - std::vector({"otasigned_v2.zip", "v2"}), - std::vector({"otasigned_v3.zip", "v3"}), - std::vector({"otasigned_v4.zip", "v4"}), - std::vector({"otasigned_v5.zip", "v5"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v1"}), + std::vector({"otasigned_v2.zip", "v2"}), + std::vector({"otasigned_v3.zip", "v3"}), + std::vector({"otasigned_v4.zip", "v4"}), + std::vector({"otasigned_v5.zip", "v5"}))); INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v1", "v2"}), - std::vector({"otasigned_v2.zip", "v5", "v2"}), - std::vector({"otasigned_v3.zip", "v5", "v1", "v3"}), - std::vector({"otasigned_v4.zip", "v5", "v1", "v4"}), - std::vector({"otasigned_v5.zip", "v4", "v1", "v5"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v1", "v2"}), + std::vector({"otasigned_v2.zip", "v5", "v2"}), + std::vector({"otasigned_v3.zip", "v5", "v1", "v3"}), + std::vector({"otasigned_v4.zip", "v5", "v1", "v4"}), + std::vector({"otasigned_v5.zip", "v4", "v1", "v5"}))); INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v2"}), - std::vector({"otasigned_v2.zip", "v1"}), - std::vector({"otasigned_v3.zip", "v5"}), - std::vector({"otasigned_v4.zip", "v5"}), - std::vector({"otasigned_v5.zip", "v3"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v2"}), + std::vector({"otasigned_v2.zip", "v1"}), + std::vector({"otasigned_v3.zip", "v5"}), + std::vector({"otasigned_v4.zip", "v5"}), + std::vector({"otasigned_v5.zip", "v3"}))); INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest, - ::testing::Values( - std::vector({"otasigned_v1.zip", "v3"}), - std::vector({"otasigned_v2.zip", "v4"}), - std::vector({"otasigned_v3.zip", "v1"}), - std::vector({"otasigned_v4.zip", "v2"}))); + ::testing::Values( + std::vector({"otasigned_v1.zip", "v3"}), + std::vector({"otasigned_v2.zip", "v4"}), + std::vector({"otasigned_v3.zip", "v1"}), + std::vector({"otasigned_v4.zip", "v2"}))); INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest, - ::testing::Values( - std::vector({"random.zip", "v1"}), - std::vector({"fake-eocd.zip", "v1"}), - std::vector({"alter-metadata.zip", "v1"}), - std::vector({"alter-footer.zip", "v1"}), - std::vector({"signature-boundary.zip", "v1"}))); + ::testing::Values( + std::vector({"random.zip", "v1"}), + std::vector({"fake-eocd.zip", "v1"}), + std::vector({"alter-metadata.zip", "v1"}), + std::vector({"alter-footer.zip", "v1"}), + std::vector({"signature-boundary.zip", "v1"}))); -- cgit v1.2.3 From d7bf82eb5358df367daaac12562fe5aa4e87ba63 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sat, 18 Mar 2017 09:24:11 -0700 Subject: Remove the dead #include's in verifier.cpp. A follow-up to commit 5e535014dd7961fbf812abeaa27f3339775031f1. Also clean up Android.mk, since libverifier no longer needs anything from libminui. Test: mmma bootable/recovery Test: recovery_component_test passes. Change-Id: I1c11e4bbeef67ca34a2054debf1f5b280d509217 --- tests/Android.mk | 1 - 1 file changed, 1 deletion(-) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 65f736d13..ff6e14c9b 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -120,7 +120,6 @@ LOCAL_STATIC_LIBRARIES := \ libupdater \ libbootloader_message \ libverifier \ - libminui \ libotautil \ libmounts \ libdivsufsort \ -- cgit v1.2.3 From 3116ce46510e9b209e3b40dfeb577e18f51e8f95 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 16 Mar 2017 17:37:38 -0700 Subject: Add testcases for load_keys(). Test: recovery_component_test passes. Change-Id: I6276b59981c87c50736d69d4af7647c8ed892965 --- tests/component/verifier_test.cpp | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 460585d22..07a8c960f 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -58,6 +58,63 @@ class VerifierSuccessTest : public VerifierTest { class VerifierFailureTest : public VerifierTest { }; +TEST(VerifierTest, load_keys_multiple_keys) { + std::string testkey_v4; + ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4)); + + std::string testkey_v3; + ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3)); + + std::string keys = testkey_v4 + "," + testkey_v3 + "," + testkey_v4; + TemporaryFile key_file1; + ASSERT_TRUE(android::base::WriteStringToFile(keys, key_file1.path)); + std::vector certs; + ASSERT_TRUE(load_keys(key_file1.path, certs)); + ASSERT_EQ(3U, certs.size()); +} + +TEST(VerifierTest, load_keys_invalid_keys) { + std::vector certs; + ASSERT_FALSE(load_keys("/doesntexist", certs)); + + // Empty file. + TemporaryFile key_file1; + ASSERT_FALSE(load_keys(key_file1.path, certs)); + + // Invalid contents. + ASSERT_TRUE(android::base::WriteStringToFile("invalid", key_file1.path)); + ASSERT_FALSE(load_keys(key_file1.path, certs)); + + std::string testkey_v4; + ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4)); + + // Invalid key version: "v4 ..." => "v6 ...". + std::string invalid_key2(testkey_v4); + invalid_key2[1] = '6'; + TemporaryFile key_file2; + ASSERT_TRUE(android::base::WriteStringToFile(invalid_key2, key_file2.path)); + ASSERT_FALSE(load_keys(key_file2.path, certs)); + + // Invalid key content: inserted extra bytes ",2209831334". + std::string invalid_key3(testkey_v4); + invalid_key3.insert(invalid_key2.size() - 2, ",2209831334"); + TemporaryFile key_file3; + ASSERT_TRUE(android::base::WriteStringToFile(invalid_key3, key_file3.path)); + ASSERT_FALSE(load_keys(key_file3.path, certs)); + + // Invalid key: the last key must not end with an extra ','. + std::string invalid_key4 = testkey_v4 + ","; + TemporaryFile key_file4; + ASSERT_TRUE(android::base::WriteStringToFile(invalid_key4, key_file4.path)); + ASSERT_FALSE(load_keys(key_file4.path, certs)); + + // Invalid key separator. + std::string invalid_key5 = testkey_v4 + ";" + testkey_v4; + TemporaryFile key_file5; + ASSERT_TRUE(android::base::WriteStringToFile(invalid_key5, key_file5.path)); + ASSERT_FALSE(load_keys(key_file5.path, certs)); +} + TEST_P(VerifierSuccessTest, VerifySucceed) { ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_SUCCESS); } -- cgit v1.2.3 From 76fdb2419bfec0e747db2530379484a3dc571f34 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 20 Mar 2017 17:09:13 -0700 Subject: verify_file: Add constness to a few addresses. We should not touch any data while verifying packages (or parsing the in-memory ASN.1 structures). Test: mmma bootable/recovery Test: recovery_component_test passes. Test: recovery_unit_test passes. Change-Id: Ie990662c6451ec066a1807b3081c9296afbdb0bf --- tests/unit/asn1_decoder_test.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/unit/asn1_decoder_test.cpp b/tests/unit/asn1_decoder_test.cpp index af96d87d2..997639d8a 100644 --- a/tests/unit/asn1_decoder_test.cpp +++ b/tests/unit/asn1_decoder_test.cpp @@ -39,7 +39,7 @@ TEST_F(Asn1DecoderTest, Empty_Failure) { EXPECT_EQ(NULL, asn1_set_get(ctx)); EXPECT_FALSE(asn1_sequence_next(ctx)); - uint8_t* junk; + const uint8_t* junk; size_t length; EXPECT_FALSE(asn1_oid_get(ctx, &junk, &length)); EXPECT_FALSE(asn1_octet_string_get(ctx, &junk, &length)); @@ -68,7 +68,7 @@ TEST_F(Asn1DecoderTest, ConstructedGet_TooSmallForChild_Failure) { asn1_context_t* ptr = asn1_constructed_get(ctx); ASSERT_NE((asn1_context_t*)NULL, ptr); EXPECT_EQ(5, asn1_constructed_type(ptr)); - uint8_t* oid; + const uint8_t* oid; size_t length; EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length)); asn1_context_free(ptr); @@ -81,7 +81,7 @@ TEST_F(Asn1DecoderTest, ConstructedGet_Success) { asn1_context_t* ptr = asn1_constructed_get(ctx); ASSERT_NE((asn1_context_t*)NULL, ptr); EXPECT_EQ(5, asn1_constructed_type(ptr)); - uint8_t* oid; + const uint8_t* oid; size_t length; ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length)); EXPECT_EQ(1U, length); @@ -103,7 +103,7 @@ TEST_F(Asn1DecoderTest, ConstructedSkipAll_Success) { 0x06, 0x01, 0xA5, }; asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); ASSERT_TRUE(asn1_constructed_skip_all(ctx)); - uint8_t* oid; + const uint8_t* oid; size_t length; ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length)); EXPECT_EQ(1U, length); @@ -123,7 +123,7 @@ TEST_F(Asn1DecoderTest, SequenceGet_TooSmallForChild_Failure) { asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); asn1_context_t* ptr = asn1_sequence_get(ctx); ASSERT_NE((asn1_context_t*)NULL, ptr); - uint8_t* oid; + const uint8_t* oid; size_t length; EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length)); asn1_context_free(ptr); @@ -135,7 +135,7 @@ TEST_F(Asn1DecoderTest, SequenceGet_Success) { asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); asn1_context_t* ptr = asn1_sequence_get(ctx); ASSERT_NE((asn1_context_t*)NULL, ptr); - uint8_t* oid; + const uint8_t* oid; size_t length; ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length)); EXPECT_EQ(1U, length); @@ -156,7 +156,7 @@ TEST_F(Asn1DecoderTest, SetGet_TooSmallForChild_Failure) { asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); asn1_context_t* ptr = asn1_set_get(ctx); ASSERT_NE((asn1_context_t*)NULL, ptr); - uint8_t* oid; + const uint8_t* oid; size_t length; EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length)); asn1_context_free(ptr); @@ -168,7 +168,7 @@ TEST_F(Asn1DecoderTest, SetGet_Success) { asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); asn1_context_t* ptr = asn1_set_get(ctx); ASSERT_NE((asn1_context_t*)NULL, ptr); - uint8_t* oid; + const uint8_t* oid; size_t length; ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length)); EXPECT_EQ(1U, length); @@ -180,7 +180,7 @@ TEST_F(Asn1DecoderTest, SetGet_Success) { TEST_F(Asn1DecoderTest, OidGet_LengthZero_Failure) { uint8_t data[] = { 0x06, 0x00, 0x01, }; asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - uint8_t* oid; + const uint8_t* oid; size_t length; EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length)); asn1_context_free(ctx); @@ -189,7 +189,7 @@ TEST_F(Asn1DecoderTest, OidGet_LengthZero_Failure) { TEST_F(Asn1DecoderTest, OidGet_TooSmall_Failure) { uint8_t data[] = { 0x06, 0x01, }; asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - uint8_t* oid; + const uint8_t* oid; size_t length; EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length)); asn1_context_free(ctx); @@ -198,7 +198,7 @@ TEST_F(Asn1DecoderTest, OidGet_TooSmall_Failure) { TEST_F(Asn1DecoderTest, OidGet_Success) { uint8_t data[] = { 0x06, 0x01, 0x99, }; asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - uint8_t* oid; + const uint8_t* oid; size_t length; ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length)); EXPECT_EQ(1U, length); @@ -209,7 +209,7 @@ TEST_F(Asn1DecoderTest, OidGet_Success) { TEST_F(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) { uint8_t data[] = { 0x04, 0x00, 0x55, }; asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - uint8_t* string; + const uint8_t* string; size_t length; ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length)); asn1_context_free(ctx); @@ -218,7 +218,7 @@ TEST_F(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) { TEST_F(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) { uint8_t data[] = { 0x04, 0x01, }; asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - uint8_t* string; + const uint8_t* string; size_t length; ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length)); asn1_context_free(ctx); @@ -227,7 +227,7 @@ TEST_F(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) { TEST_F(Asn1DecoderTest, OctetStringGet_Success) { uint8_t data[] = { 0x04, 0x01, 0xAA, }; asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - uint8_t* string; + const uint8_t* string; size_t length; ASSERT_TRUE(asn1_octet_string_get(ctx, &string, &length)); EXPECT_EQ(1U, length); -- cgit v1.2.3 From 861c53c6c55db4cf6cb76d35f92804cabf1cd444 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 20 Mar 2017 17:09:13 -0700 Subject: Refactor asn1_decoder functions into a class. Test: mmma bootable/recovery Test: recovery_unit_test passes. Test: recovery_component_test passes. Change-Id: If0bf25993158eaebeedff55ba4f4dd0f6e5f937d --- tests/unit/asn1_decoder_test.cpp | 397 ++++++++++++++++++--------------------- 1 file changed, 180 insertions(+), 217 deletions(-) (limited to 'tests') diff --git a/tests/unit/asn1_decoder_test.cpp b/tests/unit/asn1_decoder_test.cpp index 997639d8a..b334a655b 100644 --- a/tests/unit/asn1_decoder_test.cpp +++ b/tests/unit/asn1_decoder_test.cpp @@ -14,225 +14,188 @@ * limitations under the License. */ -#define LOG_TAG "asn1_decoder_test" +#include + +#include -#include #include -#include -#include #include "asn1_decoder.h" -namespace android { - -class Asn1DecoderTest : public testing::Test { -}; - -TEST_F(Asn1DecoderTest, Empty_Failure) { - uint8_t empty[] = { }; - asn1_context_t* ctx = asn1_context_new(empty, sizeof(empty)); - - EXPECT_EQ(NULL, asn1_constructed_get(ctx)); - EXPECT_FALSE(asn1_constructed_skip_all(ctx)); - EXPECT_EQ(0, asn1_constructed_type(ctx)); - EXPECT_EQ(NULL, asn1_sequence_get(ctx)); - EXPECT_EQ(NULL, asn1_set_get(ctx)); - EXPECT_FALSE(asn1_sequence_next(ctx)); - - const uint8_t* junk; - size_t length; - EXPECT_FALSE(asn1_oid_get(ctx, &junk, &length)); - EXPECT_FALSE(asn1_octet_string_get(ctx, &junk, &length)); - - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, ConstructedGet_TruncatedLength_Failure) { - uint8_t truncated[] = { 0xA0, 0x82, }; - asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated)); - EXPECT_EQ(NULL, asn1_constructed_get(ctx)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, ConstructedGet_LengthTooBig_Failure) { - uint8_t truncated[] = { 0xA0, 0x8a, 0xA5, 0x5A, 0xA5, 0x5A, - 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A, }; - asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated)); - EXPECT_EQ(NULL, asn1_constructed_get(ctx)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, ConstructedGet_TooSmallForChild_Failure) { - uint8_t data[] = { 0xA5, 0x02, 0x06, 0x01, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - asn1_context_t* ptr = asn1_constructed_get(ctx); - ASSERT_NE((asn1_context_t*)NULL, ptr); - EXPECT_EQ(5, asn1_constructed_type(ptr)); - const uint8_t* oid; - size_t length; - EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length)); - asn1_context_free(ptr); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, ConstructedGet_Success) { - uint8_t data[] = { 0xA5, 0x03, 0x06, 0x01, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - asn1_context_t* ptr = asn1_constructed_get(ctx); - ASSERT_NE((asn1_context_t*)NULL, ptr); - EXPECT_EQ(5, asn1_constructed_type(ptr)); - const uint8_t* oid; - size_t length; - ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length)); - EXPECT_EQ(1U, length); - EXPECT_EQ(0x01U, *oid); - asn1_context_free(ptr); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, ConstructedSkipAll_TruncatedLength_Failure) { - uint8_t truncated[] = { 0xA2, 0x82, }; - asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated)); - EXPECT_FALSE(asn1_constructed_skip_all(ctx)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, ConstructedSkipAll_Success) { - uint8_t data[] = { 0xA0, 0x03, 0x02, 0x01, 0x01, - 0xA1, 0x03, 0x02, 0x01, 0x01, - 0x06, 0x01, 0xA5, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - ASSERT_TRUE(asn1_constructed_skip_all(ctx)); - const uint8_t* oid; - size_t length; - ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length)); - EXPECT_EQ(1U, length); - EXPECT_EQ(0xA5U, *oid); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, SequenceGet_TruncatedLength_Failure) { - uint8_t truncated[] = { 0x30, 0x82, }; - asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated)); - EXPECT_EQ(NULL, asn1_sequence_get(ctx)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, SequenceGet_TooSmallForChild_Failure) { - uint8_t data[] = { 0x30, 0x02, 0x06, 0x01, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - asn1_context_t* ptr = asn1_sequence_get(ctx); - ASSERT_NE((asn1_context_t*)NULL, ptr); - const uint8_t* oid; - size_t length; - EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length)); - asn1_context_free(ptr); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, SequenceGet_Success) { - uint8_t data[] = { 0x30, 0x03, 0x06, 0x01, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - asn1_context_t* ptr = asn1_sequence_get(ctx); - ASSERT_NE((asn1_context_t*)NULL, ptr); - const uint8_t* oid; - size_t length; - ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length)); - EXPECT_EQ(1U, length); - EXPECT_EQ(0x01U, *oid); - asn1_context_free(ptr); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, SetGet_TruncatedLength_Failure) { - uint8_t truncated[] = { 0x31, 0x82, }; - asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated)); - EXPECT_EQ(NULL, asn1_set_get(ctx)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, SetGet_TooSmallForChild_Failure) { - uint8_t data[] = { 0x31, 0x02, 0x06, 0x01, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - asn1_context_t* ptr = asn1_set_get(ctx); - ASSERT_NE((asn1_context_t*)NULL, ptr); - const uint8_t* oid; - size_t length; - EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length)); - asn1_context_free(ptr); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, SetGet_Success) { - uint8_t data[] = { 0x31, 0x03, 0x06, 0x01, 0xBA, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - asn1_context_t* ptr = asn1_set_get(ctx); - ASSERT_NE((asn1_context_t*)NULL, ptr); - const uint8_t* oid; - size_t length; - ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length)); - EXPECT_EQ(1U, length); - EXPECT_EQ(0xBAU, *oid); - asn1_context_free(ptr); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, OidGet_LengthZero_Failure) { - uint8_t data[] = { 0x06, 0x00, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - const uint8_t* oid; - size_t length; - EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, OidGet_TooSmall_Failure) { - uint8_t data[] = { 0x06, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - const uint8_t* oid; - size_t length; - EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, OidGet_Success) { - uint8_t data[] = { 0x06, 0x01, 0x99, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - const uint8_t* oid; - size_t length; - ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length)); - EXPECT_EQ(1U, length); - EXPECT_EQ(0x99U, *oid); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) { - uint8_t data[] = { 0x04, 0x00, 0x55, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - const uint8_t* string; - size_t length; - ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) { - uint8_t data[] = { 0x04, 0x01, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - const uint8_t* string; - size_t length; - ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length)); - asn1_context_free(ctx); -} - -TEST_F(Asn1DecoderTest, OctetStringGet_Success) { - uint8_t data[] = { 0x04, 0x01, 0xAA, }; - asn1_context_t* ctx = asn1_context_new(data, sizeof(data)); - const uint8_t* string; - size_t length; - ASSERT_TRUE(asn1_octet_string_get(ctx, &string, &length)); - EXPECT_EQ(1U, length); - EXPECT_EQ(0xAAU, *string); - asn1_context_free(ctx); -} - -} // namespace android +TEST(Asn1DecoderTest, Empty_Failure) { + uint8_t empty[] = {}; + asn1_context ctx(empty, sizeof(empty)); + + ASSERT_EQ(nullptr, ctx.asn1_constructed_get()); + ASSERT_FALSE(ctx.asn1_constructed_skip_all()); + ASSERT_EQ(0, ctx.asn1_constructed_type()); + ASSERT_EQ(nullptr, ctx.asn1_sequence_get()); + ASSERT_EQ(nullptr, ctx.asn1_set_get()); + ASSERT_FALSE(ctx.asn1_sequence_next()); + + const uint8_t* junk; + size_t length; + ASSERT_FALSE(ctx.asn1_oid_get(&junk, &length)); + ASSERT_FALSE(ctx.asn1_octet_string_get(&junk, &length)); +} + +TEST(Asn1DecoderTest, ConstructedGet_TruncatedLength_Failure) { + uint8_t truncated[] = { 0xA0, 0x82 }; + asn1_context ctx(truncated, sizeof(truncated)); + ASSERT_EQ(nullptr, ctx.asn1_constructed_get()); +} + +TEST(Asn1DecoderTest, ConstructedGet_LengthTooBig_Failure) { + uint8_t truncated[] = { 0xA0, 0x8a, 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A }; + asn1_context ctx(truncated, sizeof(truncated)); + ASSERT_EQ(nullptr, ctx.asn1_constructed_get()); +} + +TEST(Asn1DecoderTest, ConstructedGet_TooSmallForChild_Failure) { + uint8_t data[] = { 0xA5, 0x02, 0x06, 0x01, 0x01 }; + asn1_context ctx(data, sizeof(data)); + std::unique_ptr ptr(ctx.asn1_constructed_get()); + ASSERT_NE(nullptr, ptr); + ASSERT_EQ(5, ptr->asn1_constructed_type()); + const uint8_t* oid; + size_t length; + ASSERT_FALSE(ptr->asn1_oid_get(&oid, &length)); +} + +TEST(Asn1DecoderTest, ConstructedGet_Success) { + uint8_t data[] = { 0xA5, 0x03, 0x06, 0x01, 0x01 }; + asn1_context ctx(data, sizeof(data)); + std::unique_ptr ptr(ctx.asn1_constructed_get()); + ASSERT_NE(nullptr, ptr); + ASSERT_EQ(5, ptr->asn1_constructed_type()); + const uint8_t* oid; + size_t length; + ASSERT_TRUE(ptr->asn1_oid_get(&oid, &length)); + ASSERT_EQ(1U, length); + ASSERT_EQ(0x01U, *oid); +} + +TEST(Asn1DecoderTest, ConstructedSkipAll_TruncatedLength_Failure) { + uint8_t truncated[] = { 0xA2, 0x82 }; + asn1_context ctx(truncated, sizeof(truncated)); + ASSERT_FALSE(ctx.asn1_constructed_skip_all()); +} + +TEST(Asn1DecoderTest, ConstructedSkipAll_Success) { + uint8_t data[] = { 0xA0, 0x03, 0x02, 0x01, 0x01, 0xA1, 0x03, 0x02, 0x01, 0x01, 0x06, 0x01, 0xA5 }; + asn1_context ctx(data, sizeof(data)); + ASSERT_TRUE(ctx.asn1_constructed_skip_all()); + const uint8_t* oid; + size_t length; + ASSERT_TRUE(ctx.asn1_oid_get(&oid, &length)); + ASSERT_EQ(1U, length); + ASSERT_EQ(0xA5U, *oid); +} + +TEST(Asn1DecoderTest, SequenceGet_TruncatedLength_Failure) { + uint8_t truncated[] = { 0x30, 0x82 }; + asn1_context ctx(truncated, sizeof(truncated)); + ASSERT_EQ(nullptr, ctx.asn1_sequence_get()); +} + +TEST(Asn1DecoderTest, SequenceGet_TooSmallForChild_Failure) { + uint8_t data[] = { 0x30, 0x02, 0x06, 0x01, 0x01 }; + asn1_context ctx(data, sizeof(data)); + std::unique_ptr ptr(ctx.asn1_sequence_get()); + ASSERT_NE(nullptr, ptr); + const uint8_t* oid; + size_t length; + ASSERT_FALSE(ptr->asn1_oid_get(&oid, &length)); +} + +TEST(Asn1DecoderTest, SequenceGet_Success) { + uint8_t data[] = { 0x30, 0x03, 0x06, 0x01, 0x01 }; + asn1_context ctx(data, sizeof(data)); + std::unique_ptr ptr(ctx.asn1_sequence_get()); + ASSERT_NE(nullptr, ptr); + const uint8_t* oid; + size_t length; + ASSERT_TRUE(ptr->asn1_oid_get(&oid, &length)); + ASSERT_EQ(1U, length); + ASSERT_EQ(0x01U, *oid); +} + +TEST(Asn1DecoderTest, SetGet_TruncatedLength_Failure) { + uint8_t truncated[] = { 0x31, 0x82 }; + asn1_context ctx(truncated, sizeof(truncated)); + ASSERT_EQ(nullptr, ctx.asn1_set_get()); +} + +TEST(Asn1DecoderTest, SetGet_TooSmallForChild_Failure) { + uint8_t data[] = { 0x31, 0x02, 0x06, 0x01, 0x01 }; + asn1_context ctx(data, sizeof(data)); + std::unique_ptr ptr(ctx.asn1_set_get()); + ASSERT_NE(nullptr, ptr); + const uint8_t* oid; + size_t length; + ASSERT_FALSE(ptr->asn1_oid_get(&oid, &length)); +} + +TEST(Asn1DecoderTest, SetGet_Success) { + uint8_t data[] = { 0x31, 0x03, 0x06, 0x01, 0xBA }; + asn1_context ctx(data, sizeof(data)); + std::unique_ptr ptr(ctx.asn1_set_get()); + ASSERT_NE(nullptr, ptr); + const uint8_t* oid; + size_t length; + ASSERT_TRUE(ptr->asn1_oid_get(&oid, &length)); + ASSERT_EQ(1U, length); + ASSERT_EQ(0xBAU, *oid); +} + +TEST(Asn1DecoderTest, OidGet_LengthZero_Failure) { + uint8_t data[] = { 0x06, 0x00, 0x01 }; + asn1_context ctx(data, sizeof(data)); + const uint8_t* oid; + size_t length; + ASSERT_FALSE(ctx.asn1_oid_get(&oid, &length)); +} + +TEST(Asn1DecoderTest, OidGet_TooSmall_Failure) { + uint8_t data[] = { 0x06, 0x01 }; + asn1_context ctx(data, sizeof(data)); + const uint8_t* oid; + size_t length; + ASSERT_FALSE(ctx.asn1_oid_get(&oid, &length)); +} + +TEST(Asn1DecoderTest, OidGet_Success) { + uint8_t data[] = { 0x06, 0x01, 0x99 }; + asn1_context ctx(data, sizeof(data)); + const uint8_t* oid; + size_t length; + ASSERT_TRUE(ctx.asn1_oid_get(&oid, &length)); + ASSERT_EQ(1U, length); + ASSERT_EQ(0x99U, *oid); +} + +TEST(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) { + uint8_t data[] = { 0x04, 0x00, 0x55 }; + asn1_context ctx(data, sizeof(data)); + const uint8_t* string; + size_t length; + ASSERT_FALSE(ctx.asn1_octet_string_get(&string, &length)); +} + +TEST(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) { + uint8_t data[] = { 0x04, 0x01 }; + asn1_context ctx(data, sizeof(data)); + const uint8_t* string; + size_t length; + ASSERT_FALSE(ctx.asn1_octet_string_get(&string, &length)); +} + +TEST(Asn1DecoderTest, OctetStringGet_Success) { + uint8_t data[] = { 0x04, 0x01, 0xAA }; + asn1_context ctx(data, sizeof(data)); + const uint8_t* string; + size_t length; + ASSERT_TRUE(ctx.asn1_octet_string_get(&string, &length)); + ASSERT_EQ(1U, length); + ASSERT_EQ(0xAAU, *string); +} -- cgit v1.2.3 From c444732540d5245b6219293e96d29f325daa7839 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 6 Mar 2017 14:44:59 -0800 Subject: Remove malloc in edify functions And switch them to std::vector & std::unique_ptr Bug: 32117870 Test: recovery tests passed on sailfish Change-Id: I5a45951c4bdf895be311d6d760e52e7a1b0798c3 --- tests/component/edify_test.cpp | 5 +++-- tests/component/updater_test.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/component/edify_test.cpp b/tests/component/edify_test.cpp index 287e40cc6..61a1e6b64 100644 --- a/tests/component/edify_test.cpp +++ b/tests/component/edify_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include @@ -21,7 +22,7 @@ #include "edify/expr.h" static void expect(const char* expr_str, const char* expected) { - Expr* e; + std::unique_ptr e; int error_count = 0; EXPECT_EQ(0, parse_string(expr_str, &e, &error_count)); EXPECT_EQ(0, error_count); @@ -152,7 +153,7 @@ TEST_F(EdifyTest, big_string) { TEST_F(EdifyTest, unknown_function) { // unknown function const char* script1 = "unknown_function()"; - Expr* expr; + std::unique_ptr expr; int error_count = 0; EXPECT_EQ(1, parse_string(script1, &expr, &error_count)); EXPECT_EQ(1, error_count); diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index 4f8349e2f..ef121a973 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -46,7 +47,7 @@ struct selabel_handle *sehandle = nullptr; static void expect(const char* expected, const char* expr_str, CauseCode cause_code, UpdaterInfo* info = nullptr) { - Expr* e; + std::unique_ptr e; int error_count = 0; ASSERT_EQ(0, parse_string(expr_str, &e, &error_count)); ASSERT_EQ(0, error_count); -- cgit v1.2.3 From db56eb073e595a862f620e244e23471665f63527 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 23 Mar 2017 06:34:20 -0700 Subject: updater: Fix the broken case for apply_patch_check(). It's valid to provide only 1 argument to apply_patch_check(). We shouldn't fail the argument parsing. Bug: 36541737 Test: recovery_component_test passes. Test: recovery_component_test captures the failure without the fix. Test: The previously failed update applies successfully. Change-Id: Iee4c54ed33b877fc4885945b085341ec5c64f663 --- tests/component/updater_test.cpp | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'tests') diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index ef121a973..5652ddf46 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -127,6 +127,55 @@ TEST_F(UpdaterTest, sha1_check) { expect(nullptr, "sha1_check()", kArgsParsingFailure); } +TEST_F(UpdaterTest, apply_patch_check) { + // Zero-argument is not valid. + expect(nullptr, "apply_patch_check()", kArgsParsingFailure); + + // File not found. + expect("", "apply_patch_check(\"/doesntexist\")", kNoCause); + + std::string src_file = from_testdata_base("old.file"); + std::string src_content; + ASSERT_TRUE(android::base::ReadFileToString(src_file, &src_content)); + size_t src_size = src_content.size(); + std::string src_hash = get_sha1(src_content); + + // One-argument with EMMC:file:size:sha1 should pass the check. + std::string filename = android::base::Join( + std::vector{ "EMMC", src_file, std::to_string(src_size), src_hash }, ":"); + std::string cmd = "apply_patch_check(\"" + filename + "\")"; + expect("t", cmd.c_str(), kNoCause); + + // EMMC:file:(size-1):sha1:(size+1):sha1 should fail the check. + std::string filename_bad = android::base::Join( + std::vector{ "EMMC", src_file, std::to_string(src_size - 1), src_hash, + std::to_string(src_size + 1), src_hash }, + ":"); + cmd = "apply_patch_check(\"" + filename_bad + "\")"; + expect("", cmd.c_str(), kNoCause); + + // EMMC:file:(size-1):sha1:size:sha1:(size+1):sha1 should pass the check. + filename_bad = + android::base::Join(std::vector{ "EMMC", src_file, std::to_string(src_size - 1), + src_hash, std::to_string(src_size), src_hash, + std::to_string(src_size + 1), src_hash }, + ":"); + cmd = "apply_patch_check(\"" + filename_bad + "\")"; + expect("t", cmd.c_str(), kNoCause); + + // Multiple arguments. + cmd = "apply_patch_check(\"" + filename + "\", \"wrong_sha1\", \"wrong_sha2\")"; + expect("", cmd.c_str(), kNoCause); + + cmd = "apply_patch_check(\"" + filename + "\", \"wrong_sha1\", \"" + src_hash + + "\", \"wrong_sha2\")"; + expect("t", cmd.c_str(), kNoCause); + + cmd = "apply_patch_check(\"" + filename_bad + "\", \"wrong_sha1\", \"" + src_hash + + "\", \"wrong_sha2\")"; + expect("t", cmd.c_str(), kNoCause); +} + TEST_F(UpdaterTest, file_getprop) { // file_getprop() expects two arguments. expect(nullptr, "file_getprop()", kArgsParsingFailure); -- cgit v1.2.3 From 056e2da6790a5111039ef2e1310ad781107f80d4 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sun, 26 Mar 2017 23:25:11 -0700 Subject: tests: Construct signature-boundary.zip at runtime. Test: Observe the same failure with recovery_component_test ("signature start: 65535 is larger than comment size: 0"). Change-Id: I98c357b5df2fa4caa9d8eed63af2e945ed99f18a --- tests/component/verifier_test.cpp | 20 ++++++++++++++++++-- tests/testdata/signature-boundary.zip | Bin 22 -> 0 bytes 2 files changed, 18 insertions(+), 2 deletions(-) delete mode 100644 tests/testdata/signature-boundary.zip (limited to 'tests') diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 4993716f4..4c0648714 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -33,6 +33,8 @@ #include "otautil/SysUtil.h" #include "verifier.h" +using namespace std::string_literals; + class VerifierTest : public testing::TestWithParam> { protected: void SetUp() override { @@ -115,6 +117,21 @@ TEST(VerifierTest, load_keys_invalid_keys) { ASSERT_FALSE(load_keys(key_file5.path, certs)); } +TEST(VerifierTest, BadPackage_SignatureStartOutOfBounds) { + std::string testkey_v3; + ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3)); + + TemporaryFile key_file; + ASSERT_TRUE(android::base::WriteStringToFile(testkey_v3, key_file.path)); + std::vector certs; + ASSERT_TRUE(load_keys(key_file.path, certs)); + + // Signature start is 65535 (0xffff) while comment size is 0 (Bug: 31914369). + std::string package = "\x50\x4b\x05\x06"s + std::string(12, '\0') + "\xff\xff\xff\xff\x00\x00"s; + ASSERT_EQ(VERIFY_FAILURE, verify_file(reinterpret_cast(package.data()), + package.size(), certs)); +} + TEST_P(VerifierSuccessTest, VerifySucceed) { ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_SUCCESS); } @@ -159,5 +176,4 @@ INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest, std::vector({"random.zip", "v1"}), std::vector({"fake-eocd.zip", "v1"}), std::vector({"alter-metadata.zip", "v1"}), - std::vector({"alter-footer.zip", "v1"}), - std::vector({"signature-boundary.zip", "v1"}))); + std::vector({"alter-footer.zip", "v1"}))); diff --git a/tests/testdata/signature-boundary.zip b/tests/testdata/signature-boundary.zip deleted file mode 100644 index 64a3cfa15..000000000 Binary files a/tests/testdata/signature-boundary.zip and /dev/null differ -- cgit v1.2.3 From 0a599567ce79a80d8d511505d34fa810b11e034e Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 28 Mar 2017 20:11:15 +0000 Subject: Merge "Add the missing sr-Latn into png files and rename the png locale header" am: 713d915636 am: dc235b5ab9 am: 5ec12126f0 Change-Id: Ia6b861c91958d3be23a4a7456d6d5d8e4a1607c8 (cherry picked from commit 9166f66eee883d6d6cc280a6c355e5528bb4a3f0) --- tests/unit/locale_test.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'tests') diff --git a/tests/unit/locale_test.cpp b/tests/unit/locale_test.cpp index f73235005..cdaba0e8b 100644 --- a/tests/unit/locale_test.cpp +++ b/tests/unit/locale_test.cpp @@ -19,14 +19,15 @@ #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")); - EXPECT_FALSE(matches_locale("en_US", "")); - // Empty locale prefix in the PNG file will match the input locale. - EXPECT_TRUE(matches_locale("", "en_US")); + EXPECT_TRUE(matches_locale("zh-CN", "zh-Hans-CN")); + EXPECT_TRUE(matches_locale("zh", "zh-Hans-CN")); + EXPECT_FALSE(matches_locale("zh-HK", "zh-Hans-CN")); + 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")); + EXPECT_FALSE(matches_locale("en-US", "")); + // Empty locale prefix in the PNG file will match the input locale. + EXPECT_TRUE(matches_locale("", "en-US")); + EXPECT_TRUE(matches_locale("sr-Latn", "sr-Latn-BA")); } -- cgit v1.2.3 From 62e0bc7586077b3bde82759fb34b51b982cea20f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 10 Apr 2017 16:55:57 -0700 Subject: Verify the package compatibility with libvintf. verify_package_compatibility() is added to parse the compatibility entry (compatibility.zip) in a given OTA package. If entry is present, the information is sent to libvintf to check the compatibility. This CL doesn't actually call libvintf, since the API there is not available yet. Bug: 36597505 Test: Doesn't break the install with existing packages (i.e. w/o the compatibility entry). Test: recovery_component_test Change-Id: I3903ffa5f6ba33a5c0d761602ade6290c6752596 --- tests/Android.mk | 3 ++- tests/component/install_test.cpp | 57 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/component/install_test.cpp (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index ff6e14c9b..1e433a76e 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -93,6 +93,7 @@ LOCAL_SRC_FILES := \ component/bootloader_message_test.cpp \ component/edify_test.cpp \ component/imgdiff_test.cpp \ + component/install_test.cpp \ component/sideload_test.cpp \ component/uncrypt_test.cpp \ component/updater_test.cpp \ @@ -117,6 +118,7 @@ LOCAL_STATIC_LIBRARIES := \ libbsdiff \ libbspatch \ libotafault \ + librecovery \ libupdater \ libbootloader_message \ libverifier \ @@ -131,7 +133,6 @@ LOCAL_STATIC_LIBRARIES := \ libsparse \ libcrypto_utils \ libcrypto \ - libcutils \ libbz \ libziparchive \ libutils \ diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp new file mode 100644 index 000000000..3b6fbc301 --- /dev/null +++ b/tests/component/install_test.cpp @@ -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 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 + +#include +#include +#include +#include + +#include "install.h" + +TEST(InstallTest, verify_package_compatibility_no_entry) { + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "w"); + ZipWriter writer(zip_file); + // The archive must have something to be opened correctly. + ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0)); + ASSERT_EQ(0, writer.FinishEntry()); + ASSERT_EQ(0, writer.Finish()); + ASSERT_EQ(0, fclose(zip_file)); + + // Doesn't contain compatibility zip entry. + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + ASSERT_TRUE(verify_package_compatibility(zip)); + CloseArchive(zip); +} + +TEST(InstallTest, verify_package_compatibility_invalid_entry) { + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "w"); + ZipWriter writer(zip_file); + ASSERT_EQ(0, writer.StartEntry("compatibility.zip", 0)); + ASSERT_EQ(0, writer.FinishEntry()); + ASSERT_EQ(0, writer.Finish()); + ASSERT_EQ(0, fclose(zip_file)); + + // Empty compatibility zip entry. + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + ASSERT_FALSE(verify_package_compatibility(zip)); + CloseArchive(zip); +} -- cgit v1.2.3 From a233a89d99b673eccaf072f9d0f452afa1c725c7 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 17 Apr 2017 16:46:05 -0700 Subject: Add tests for update_binary_command(). Expose update_binary_command() through private/install.h for testing purpose. Also make minor clean-ups to install.cpp: a) adding more verbose logging on ExtractToMemory failures; b) update_binary_command() taking std::string instead of const char*; c) moving a few macro and global constants into update_binary_command(). Bug: 37300957 Test: recovery_component_test on marlin Test: Build new recovery and adb sideload on angler and sailfish. Change-Id: Ib2d9068af3fee038f01c90940ccaeb0a7da374fc Merged-In: Ib2d9068af3fee038f01c90940ccaeb0a7da374fc (cherry picked from commit bc4b1fe4c4305ebf0fbfc891b9b508c14b5c8ef8) --- tests/Android.mk | 5 +++ tests/component/install_test.cpp | 87 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 1e433a76e..22a8efcbb 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -86,6 +86,11 @@ LOCAL_CFLAGS := \ -D_FILE_OFFSET_BITS=64 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +ifeq ($(AB_OTA_UPDATER),true) +LOCAL_CFLAGS += -DAB_OTA_UPDATER=1 +endif + LOCAL_MODULE := recovery_component_test LOCAL_C_INCLUDES := bootable/recovery LOCAL_SRC_FILES := \ diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp index 3b6fbc301..fd3b28b07 100644 --- a/tests/component/install_test.cpp +++ b/tests/component/install_test.cpp @@ -16,12 +16,18 @@ #include +#include +#include + +#include +#include #include #include #include #include #include "install.h" +#include "private/install.h" TEST(InstallTest, verify_package_compatibility_no_entry) { TemporaryFile temp_file; @@ -55,3 +61,84 @@ TEST(InstallTest, verify_package_compatibility_invalid_entry) { ASSERT_FALSE(verify_package_compatibility(zip)); CloseArchive(zip); } + +TEST(InstallTest, update_binary_command_smoke) { +#ifdef AB_OTA_UPDATER + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "w"); + ZipWriter writer(zip_file); + ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored)); + ASSERT_EQ(0, writer.FinishEntry()); + ASSERT_EQ(0, writer.StartEntry("payload_properties.txt", kCompressStored)); + const std::string properties = "some_properties"; + ASSERT_EQ(0, writer.WriteBytes(properties.data(), properties.size())); + ASSERT_EQ(0, writer.FinishEntry()); + // A metadata entry is mandatory. + ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored)); + std::string device = android::base::GetProperty("ro.product.device", ""); + ASSERT_NE("", device); + std::string timestamp = android::base::GetProperty("ro.build.date.utc", ""); + ASSERT_NE("", timestamp); + std::string metadata = android::base::Join( + std::vector{ + "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp, + }, + "\n"); + ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size())); + ASSERT_EQ(0, writer.FinishEntry()); + ASSERT_EQ(0, writer.Finish()); + ASSERT_EQ(0, fclose(zip_file)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + int status_fd = 10; + std::string path = "/path/to/update.zip"; + std::vector cmd; + ASSERT_EQ(0, update_binary_command(path, zip, 0, status_fd, &cmd)); + ASSERT_EQ("/sbin/update_engine_sideload", cmd[0]); + ASSERT_EQ("--payload=file://" + path, cmd[1]); + ASSERT_EQ("--headers=" + properties, cmd[3]); + ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]); + CloseArchive(zip); +#else + // Cannot test update_binary_command() because it tries to extract update-binary to /tmp. + GTEST_LOG_(INFO) << "Test skipped on non-A/B device."; +#endif // AB_OTA_UPDATER +} + +TEST(InstallTest, update_binary_command_invalid) { +#ifdef AB_OTA_UPDATER + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "w"); + ZipWriter writer(zip_file); + // Missing payload_properties.txt. + ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored)); + ASSERT_EQ(0, writer.FinishEntry()); + // A metadata entry is mandatory. + ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored)); + std::string device = android::base::GetProperty("ro.product.device", ""); + ASSERT_NE("", device); + std::string timestamp = android::base::GetProperty("ro.build.date.utc", ""); + ASSERT_NE("", timestamp); + std::string metadata = android::base::Join( + std::vector{ + "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp, + }, + "\n"); + ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size())); + ASSERT_EQ(0, writer.FinishEntry()); + ASSERT_EQ(0, writer.Finish()); + ASSERT_EQ(0, fclose(zip_file)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + int status_fd = 10; + std::string path = "/path/to/update.zip"; + std::vector cmd; + ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(path, zip, 0, status_fd, &cmd)); + CloseArchive(zip); +#else + // Cannot test update_binary_command() because it tries to extract update-binary to /tmp. + GTEST_LOG_(INFO) << "Test skipped on non-A/B device."; +#endif // AB_OTA_UPDATER +} -- cgit v1.2.3 From da320ac6ab53395ddff3cc08b88a61f977ed939a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 10 Apr 2017 16:55:57 -0700 Subject: Call libvintf to verify package compatibility. The libvintf API has landed. Hook up to do the actual verification. Bug: 36597505 Test: recovery_component_test Test: m recoveryimage; adb sideload on angler and sailfish, with packages that contain dummy compatibility entries. Test: m recoveryimage; adb sideload on angler and sailfish, with packages that don't contain any compatibility entries. Change-Id: Idbd6f5aaef605ca51b20e667505d686de5ac781f --- tests/Android.mk | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 22a8efcbb..f59f486d7 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -133,6 +133,9 @@ LOCAL_STATIC_LIBRARIES := \ libdivsufsort64 \ libfs_mgr \ liblog \ + libvintf_recovery \ + libvintf \ + libtinyxml2 \ libselinux \ libext4_utils \ libsparse \ -- cgit v1.2.3 From b4c0de6c7bcd738e40dc4921d01b534d928e4f4f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 19 Apr 2017 12:37:12 -0700 Subject: Add more tests for verify_package_compatibility(). This now covers the actual calls to libvintf, and asserts we're getting identical results through verify_package_compatibility() and by calling libvintf directly. We were missing the coverage and introduced the double free bug (fixed by commit f978278995d02a58e311fe017bdbb2c3702dd3bc). Bug: 37413730 Test: recovery_component_test passes. Test: recovery_component_test fails w/o commit f978278995d02a58e311fe017bdbb2c3702dd3bc. Change-Id: If5195ea1c583fd7c440a1de289da82145e80e23c (cherry picked from commit f2784b6a43e54ed67bc30ac456f66f11bd16bc74) --- tests/component/install_test.cpp | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'tests') diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp index fd3b28b07..a5c0c1025 100644 --- a/tests/component/install_test.cpp +++ b/tests/component/install_test.cpp @@ -15,14 +15,17 @@ */ #include +#include #include #include +#include #include #include #include #include +#include #include #include @@ -62,6 +65,87 @@ TEST(InstallTest, verify_package_compatibility_invalid_entry) { CloseArchive(zip); } +TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) { + TemporaryFile compatibility_zip_file; + FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w"); + ZipWriter compatibility_zip_writer(compatibility_zip); + ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated)); + std::string malformed_xml = "malformed"; + ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(malformed_xml.data(), malformed_xml.size())); + ASSERT_EQ(0, compatibility_zip_writer.FinishEntry()); + ASSERT_EQ(0, compatibility_zip_writer.Finish()); + ASSERT_EQ(0, fclose(compatibility_zip)); + + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "w"); + ZipWriter writer(zip_file); + ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored)); + std::string compatibility_zip_content; + ASSERT_TRUE( + android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content)); + ASSERT_EQ(0, + writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size())); + ASSERT_EQ(0, writer.FinishEntry()); + ASSERT_EQ(0, writer.Finish()); + ASSERT_EQ(0, fclose(zip_file)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + std::vector compatibility_info; + compatibility_info.push_back(malformed_xml); + // Malformed compatibility zip is expected to be rejected by libvintf. But we defer that to + // libvintf. + std::string err; + bool result = + android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0; + ASSERT_EQ(result, verify_package_compatibility(zip)); + CloseArchive(zip); +} + +TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml) { + static constexpr const char* system_manifest_xml_path = "/system/manifest.xml"; + if (access(system_manifest_xml_path, R_OK) == -1) { + GTEST_LOG_(INFO) << "Test skipped on devices w/o /system/manifest.xml."; + return; + } + std::string system_manifest_xml_content; + ASSERT_TRUE( + android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content)); + TemporaryFile compatibility_zip_file; + FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w"); + ZipWriter compatibility_zip_writer(compatibility_zip); + ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated)); + ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(system_manifest_xml_content.data(), + system_manifest_xml_content.size())); + ASSERT_EQ(0, compatibility_zip_writer.FinishEntry()); + ASSERT_EQ(0, compatibility_zip_writer.Finish()); + ASSERT_EQ(0, fclose(compatibility_zip)); + + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "w"); + ZipWriter writer(zip_file); + ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored)); + std::string compatibility_zip_content; + ASSERT_TRUE( + android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content)); + ASSERT_EQ(0, + writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size())); + ASSERT_EQ(0, writer.FinishEntry()); + ASSERT_EQ(0, writer.Finish()); + ASSERT_EQ(0, fclose(zip_file)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + std::vector compatibility_info; + compatibility_info.push_back(system_manifest_xml_content); + std::string err; + bool result = + android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0; + // Make sure the result is consistent with libvintf library. + ASSERT_EQ(result, verify_package_compatibility(zip)); + CloseArchive(zip); +} + TEST(InstallTest, update_binary_command_smoke) { #ifdef AB_OTA_UPDATER TemporaryFile temp_file; -- cgit v1.2.3