diff options
Diffstat (limited to 'tests/component')
-rw-r--r-- | tests/component/applypatch_test.cpp | 595 | ||||
-rw-r--r-- | tests/component/updater_test.cpp | 134 | ||||
-rw-r--r-- | tests/component/verifier_test.cpp | 11 |
3 files changed, 469 insertions, 271 deletions
diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index 908a9f5f5..1a0b19113 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -23,167 +23,158 @@ #include <sys/types.h> #include <time.h> +#include <memory> #include <string> +#include <vector> #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/test_utils.h> +#include <openssl/sha.h> #include "applypatch/applypatch.h" +#include "applypatch/applypatch_modes.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 void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) { + ASSERT_NE(nullptr, sha1); -static std::string sha1sum(const std::string& fname) { - uint8_t digest[SHA_DIGEST_LENGTH]; - std::string data; - android::base::ReadFileToString(fname, &data); + std::string data; + ASSERT_TRUE(android::base::ReadFileToString(fname, &data)); - SHA1((const uint8_t*)data.c_str(), data.size(), digest); - return print_sha1(digest); -} + if (fsize != nullptr) { + *fsize = data.size(); + } -static void mangle_file(const std::string& fname) { - FILE* fh = fopen(&fname[0], "w"); - int r; - for (int i=0; i < 1024; i++) { - r = rand(); - fwrite(&r, sizeof(short), 1, fh); - } - fclose(fh); + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest); + *sha1 = print_sha1(digest); } -static bool file_cmp(std::string& f1, std::string& f2) { - std::string c1; - std::string c2; - android::base::ReadFileToString(f1, &c1); - android::base::ReadFileToString(f2, &c2); - return c1 == c2; +static 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)); } -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]); +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; } 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(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(std::string src, std::string tgt) { - std::string cmd = android::base::StringPrintf("cp %s %s", - &src[0], - &tgt[0]); - system(&cmd[0]); +static void cp(const std::string& src, const std::string& tgt) { + 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(); - 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<Value*> 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<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); + + ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc)); + patches.push_back( + std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); + } + + static void TearDownTestCase() { + delete output_f; + patches.clear(); + } + + static std::vector<std::unique_ptr<Value>> patches; + static TemporaryFile* output_f; + static std::string output_loc; }; class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest { - public: - virtual void SetUp() { - ApplyPatchCacheTest::SetUp(); - cp(cache_file, "/cache/reallysaved.file"); - } - - virtual void TearDown() { - cp("/cache/reallysaved.file", cache_file); - ApplyPatchCacheTest::TearDown(); - } + 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,188 +187,268 @@ std::string ApplyPatchTest::bad_sha1_b; size_t ApplyPatchTest::new_size; -std::vector<Value*> ApplyPatchFullTest::patches; +std::vector<std::unique_ptr<Value>> ApplyPatchFullTest::patches; TemporaryFile* ApplyPatchFullTest::output_f; std::string ApplyPatchFullTest::output_loc; TEST_F(ApplyPatchTest, CheckModeSkip) { - std::vector<std::string> sha1s; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + std::vector<std::string> sha1s; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeSingle) { - std::vector<std::string> sha1s = { old_sha1 }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + std::vector<std::string> sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeMultiple) { - std::vector<std::string> sha1s = { - bad_sha1_a, - old_sha1, - bad_sha1_b - }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchTest, CheckModeFailure) { - std::vector<std::string> sha1s = { - bad_sha1_a, - bad_sha1_b - }; - ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); + std::vector<std::string> 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<std::string> sha1s = { old_sha1 }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + mangle_file(old_file); + std::vector<std::string> sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) { - mangle_file(old_file); - std::vector<std::string> sha1s = { - bad_sha1_a, - old_sha1, - bad_sha1_b - }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + mangle_file(old_file); + std::vector<std::string> 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<std::string> sha1s = { - bad_sha1_a, - bad_sha1_b - }; - ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); + mangle_file(old_file); + std::vector<std::string> 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<std::string> sha1s = { old_sha1 }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + unlink(&old_file[0]); + std::vector<std::string> sha1s = { old_sha1 }; + ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) { - unlink(&old_file[0]); - std::vector<std::string> sha1s = { - bad_sha1_a, - old_sha1, - bad_sha1_b - }; - ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); + unlink(&old_file[0]); + std::vector<std::string> 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<std::string> sha1s = { - bad_sha1_a, - bad_sha1_b - }; - ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); + unlink(&old_file[0]); + std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b }; + ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); } TEST_F(ApplyPatchFullTest, ApplyInPlace) { - std::vector<std::string> sha1s = { - bad_sha1_a, - old_sha1 - }; - int ap_result = applypatch(&old_file[0], - "-", - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(old_file, new_file)); - // reapply, applypatch is idempotent so it should succeed - ap_result = applypatch(&old_file[0], - "-", - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(old_file, new_file)); + std::vector<std::string> 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<std::string> sha1s = { - bad_sha1_a, - old_sha1 - }; - int ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(output_loc, new_file)); - ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(output_loc, new_file)); + std::vector<std::string> 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) { - mangle_file(old_file); - std::vector<std::string> sha1s = { - bad_sha1_a, - old_sha1 - }; - int ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(output_loc, new_file)); - ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_EQ(0, ap_result); - ASSERT_TRUE(file_cmp(output_loc, new_file)); + std::vector<std::string> 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) { - mangle_file(old_file); - mangle_file(cache_file); - - std::vector<std::string> sha1s = { - bad_sha1_a, - old_sha1 - }; - int ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_NE(0, ap_result); - ASSERT_FALSE(file_cmp(output_loc, new_file)); - ap_result = applypatch(&old_file[0], - &output_loc[0], - &new_sha1[0], - new_size, - sha1s, - patches.data(), - nullptr); - ASSERT_NE(0, ap_result); - ASSERT_FALSE(file_cmp(output_loc, new_file)); + std::vector<std::string> 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 <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch> + TemporaryFile tmp1; + std::vector<const char*> 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 <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch> + TemporaryFile tmp2; + std::vector<const char*> 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 <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> \ + // <src-sha1-fake>:<patch1> <src-sha1>:<patch2> + TemporaryFile tmp3; + std::string bad_sha1_a = android::base::StringPrintf("%040x", rand()); + std::string bad_sha1_b = android::base::StringPrintf("%040x", rand()); + std::vector<const char*> 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 <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> + TemporaryFile tmp4; + std::vector<const char*> 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<const char*> 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<const char*> 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/component/updater_test.cpp b/tests/component/updater_test.cpp index a859f11c1..acc2b4040 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -16,7 +16,9 @@ #include <string> +#include <android-base/file.h> #include <android-base/properties.h> +#include <android-base/test_utils.h> #include <gtest/gtest.h> #include "edify/expr.h" @@ -97,3 +99,135 @@ 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); +} + +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 = 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); +} 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<std::vector<std::string>> { virtual void SetUp() { std::vector<std::string> args = GetParam(); - std::string package = - android::base::StringPrintf("%s%s%s%s", DATA_PATH, NATIVE_TEST_PATH, - TESTDATA_PATH, args[0].c_str()); + 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)); } } |