diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Android.mk | 4 | ||||
-rw-r--r-- | tests/manual/recovery_test.cpp | 3 | ||||
-rw-r--r-- | tests/unit/dirutil_test.cpp | 150 | ||||
-rw-r--r-- | tests/unit/zip_test.cpp | 21 | ||||
-rw-r--r-- | tests/unit/ziputil_test.cpp | 191 |
5 files changed, 360 insertions, 9 deletions
diff --git a/tests/Android.mk b/tests/Android.mk index ec725d865..0aca8c6c7 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -33,9 +33,11 @@ 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 + unit/zip_test.cpp \ + unit/ziputil_test.cpp LOCAL_C_INCLUDES := bootable/recovery LOCAL_SHARED_LIBRARIES := liblog 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 <fcntl.h> #include <string.h> #include <sys/types.h> #include <unistd.h> @@ -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/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 <errno.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <string> + +#include <android-base/test_utils.h> +#include <gtest/gtest.h> +#include <otautil/DirUtil.h> + +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<long>(sb.st_atime)); + ASSERT_EQ(time.tv_sec, static_cast<long>(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)); +} 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 <errno.h> -#include <fcntl.h> #include <unistd.h> #include <memory> @@ -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); } 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); +} |