diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Android.mk | 5 | ||||
-rw-r--r-- | tests/component/updater_test.cpp | 209 | ||||
-rw-r--r-- | tests/unit/zip_test.cpp | 37 | ||||
-rw-r--r-- | tests/unit/ziputil_test.cpp | 191 |
4 files changed, 440 insertions, 2 deletions
diff --git a/tests/Android.mk b/tests/Android.mk index b3584fe87..f19ca36c0 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -40,8 +40,9 @@ LOCAL_SRC_FILES := \ unit/rangeset_test.cpp \ unit/sysutil_test.cpp \ unit/zip_test.cpp \ + unit/ziputil_test.cpp -LOCAL_C_INCLUDES := bootable/recovery +LOCAL_C_INCLUDES := $(commands_recovery_local_path) LOCAL_SHARED_LIBRARIES := liblog include $(BUILD_NATIVE_TEST) @@ -101,7 +102,7 @@ endif LOCAL_MODULE := recovery_component_test LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_C_INCLUDES := bootable/recovery +LOCAL_C_INCLUDES := $(commands_recovery_local_path) LOCAL_SRC_FILES := \ component/applypatch_test.cpp \ component/bootloader_message_test.cpp \ diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index 5bfd7cb40..50e0a6345 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -255,6 +255,215 @@ 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); + 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", "<dir>"). + 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. diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp index 827668521..df4e38cae 100644 --- a/tests/unit/zip_test.cpp +++ b/tests/unit/zip_test.cpp @@ -24,10 +24,47 @@ #include <android-base/test_utils.h> #include <gtest/gtest.h> #include <otautil/SysUtil.h> +#include <otautil/ZipUtil.h> #include <ziparchive/zip_archive.h> #include "common/test_constants.h" +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(), 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); + + 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) { std::string zip_path = from_testdata_base("ziptest_dummy-update.zip"); MemMapping map; 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 <errno.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <string> + +#include <android-base/file.h> +#include <android-base/test_utils.h> +#include <gtest/gtest.h> +#include <otautil/ZipUtil.h> +#include <ziparchive/zip_archive.h> + +#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<long>(sb.st_atime)); + ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_mtime)); + + ASSERT_EQ(0, stat(file_d.c_str(), &sb)) << strerror(errno); + ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_atime)); + ASSERT_EQ(time.tv_sec, static_cast<long>(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); +} |