diff options
Diffstat (limited to 'test/utils/cpp')
-rw-r--r-- | test/utils/cpp/TARGETS | 17 | ||||
-rw-r--r-- | test/utils/cpp/archive_usage.test.cpp | 318 |
2 files changed, 334 insertions, 1 deletions
diff --git a/test/utils/cpp/TARGETS b/test/utils/cpp/TARGETS index 48676a54..e53e74d4 100644 --- a/test/utils/cpp/TARGETS +++ b/test/utils/cpp/TARGETS @@ -29,6 +29,21 @@ , "test": ["curl_usage_test.sh"] , "deps": [["test/utils", "test_utils_install"], "curl_usage_install"] } +, "archive_usage": + { "type": ["@", "rules", "CC/test", "test"] + , "tainted": ["test"] + , "name": ["archive_usage"] + , "srcs": ["archive_usage.test.cpp"] + , "private-deps": + [ ["@", "catch2", "", "catch2"] + , ["test", "catch-main"] + , ["src/buildtool/file_system", "file_system_manager"] + , ["", "libarchive"] + ] + } , "TESTS": - {"type": "install", "tainted": ["test"], "deps": ["path", "curl_usage_test"]} + { "type": "install" + , "tainted": ["test"] + , "deps": ["path", "curl_usage_test", "archive_usage"] + } } diff --git a/test/utils/cpp/archive_usage.test.cpp b/test/utils/cpp/archive_usage.test.cpp new file mode 100644 index 00000000..c3a4ec98 --- /dev/null +++ b/test/utils/cpp/archive_usage.test.cpp @@ -0,0 +1,318 @@ +// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd. +// +// 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 <string> +#include <unordered_map> + +#include "catch2/catch.hpp" +#include "src/buildtool/file_system/file_system_manager.hpp" + +extern "C" { +#include <archive.h> +#include <archive_entry.h> +} + +namespace { + +using file_t = std::pair</*content*/ std::string, mode_t>; +using filetree_t = std::unordered_map<std::string, file_t>; + +constexpr size_t kBlockSize = 10240; +constexpr int kFilePerm = 0644; +constexpr int kDirectoryPerm = 0755; + +auto const kExpected = filetree_t{{"foo", {"foo", AE_IFREG}}, + {"bar/", {"", AE_IFDIR}}, + {"bar/baz", {"baz", AE_IFREG}}}; + +[[nodiscard]] auto read_archive(archive* a, std::string const& path) + -> filetree_t { + filetree_t result{}; + + REQUIRE(archive_read_open_filename(a, path.c_str(), kBlockSize) == + ARCHIVE_OK); + + archive_entry* entry{}; + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + auto size = archive_entry_size(entry); + auto buf = std::string(static_cast<size_t>(size), '\0'); + REQUIRE(archive_read_data(a, buf.data(), buf.size()) == + static_cast<ssize_t>(buf.size())); + result.emplace(archive_entry_pathname(entry), + file_t{buf, archive_entry_filetype(entry)}); + } + REQUIRE(archive_read_close(a) == ARCHIVE_OK); + + return result; +} + +void write_archive(archive* a, + std::string const& path, + filetree_t const& files) { + REQUIRE(archive_write_open_filename(a, path.c_str()) == ARCHIVE_OK); + + archive_entry* entry = archive_entry_new(); + for (auto const& [path, file] : files) { + auto const& [content, type] = file; + archive_entry_set_pathname(entry, path.c_str()); + archive_entry_set_filetype(entry, type); + if (type == AE_IFREG) { + auto buf = std::filesystem::path{path}.filename().string(); + archive_entry_set_perm(entry, kFilePerm); + archive_entry_set_size(entry, static_cast<int64_t>(buf.size())); + REQUIRE(archive_write_header(a, entry) == ARCHIVE_OK); + REQUIRE(archive_write_data(a, buf.data(), buf.size()) == + static_cast<ssize_t>(buf.size())); + } + else { + archive_entry_set_perm(entry, kDirectoryPerm); + archive_entry_set_size(entry, 0); + REQUIRE(archive_write_header(a, entry) == ARCHIVE_OK); + } + entry = archive_entry_clear(entry); + } + archive_entry_free(entry); + REQUIRE(archive_write_close(a) == ARCHIVE_OK); +} + +void extract_archive(std::string const& path) { + auto* a = archive_read_new(); + REQUIRE(a != nullptr); + REQUIRE(archive_read_support_format_tar(a) == ARCHIVE_OK); + REQUIRE(archive_read_support_format_zip(a) == ARCHIVE_OK); + REQUIRE(archive_read_support_filter_gzip(a) == ARCHIVE_OK); + REQUIRE(archive_read_support_filter_bzip2(a) == ARCHIVE_OK); + REQUIRE(archive_read_open_filename(a, path.c_str(), kBlockSize) == + ARCHIVE_OK); + + auto* out = archive_write_disk_new(); + REQUIRE(out != nullptr); + archive_entry* entry{}; + int r{}; + while ((r = archive_read_next_header(a, &entry)) == ARCHIVE_OK) { + REQUIRE(archive_write_header(out, entry) == ARCHIVE_OK); + if (archive_entry_size(entry) > 0) { + void const* buf{}; + size_t size{}; + int64_t offset{}; + int r2{}; + while ((r2 = archive_read_data_block(a, &buf, &size, &offset)) == + ARCHIVE_OK) { + REQUIRE(archive_write_data_block(out, buf, size, offset) == + ARCHIVE_OK); + } + REQUIRE(r2 == ARCHIVE_EOF); + REQUIRE(archive_write_finish_entry(out) == ARCHIVE_OK); + } + } + REQUIRE(r == ARCHIVE_EOF); + REQUIRE(archive_read_close(a) == ARCHIVE_OK); + REQUIRE(archive_read_free(a) == ARCHIVE_OK); + REQUIRE(archive_write_close(out) == ARCHIVE_OK); + REQUIRE(archive_write_free(out) == ARCHIVE_OK); +} + +void compare_extracted( + std::filesystem::path const& extract_dir = ".") noexcept { + for (auto const& [path, file] : kExpected) { + auto const& [content, type] = file; + switch (type) { + case AE_IFREG: { + REQUIRE(FileSystemManager::IsFile(extract_dir / path)); + auto data = FileSystemManager::ReadFile(extract_dir / path); + REQUIRE(data); + CHECK(*data == content); + } break; + case AE_IFDIR: + CHECK(FileSystemManager::IsDirectory(extract_dir / path)); + break; + default: + CHECK(false); + } + } +} + +} // namespace + +TEST_CASE("Archive read context", "[archive_context]") { + auto* a = archive_read_new(); + REQUIRE(a != nullptr); + CHECK(archive_read_free(a) == ARCHIVE_OK); +} + +TEST_CASE("Archive write context", "[archive_context]") { + auto* a = archive_write_new(); + REQUIRE(a != nullptr); + CHECK(archive_write_free(a) == ARCHIVE_OK); +} + +TEST_CASE("Archive write disk context", "[archive_context]") { + auto* a = archive_write_disk_new(); + REQUIRE(a != nullptr); + CHECK(archive_read_free(a) == ARCHIVE_OK); +} + +TEST_CASE("Read-write tar", "[archive_read_write]") { + std::string test_dir{"test_tar"}; + std::string filename{"test.tar"}; + + REQUIRE(FileSystemManager::RemoveDirectory(test_dir, /*recursively=*/true)); + REQUIRE(FileSystemManager::CreateDirectory(test_dir)); + auto anchor = FileSystemManager::ChangeDirectory(test_dir); + + SECTION("Write tar") { + auto* out = archive_write_new(); + REQUIRE(out != nullptr); + REQUIRE(archive_write_set_format_pax_restricted(out) == ARCHIVE_OK); + write_archive(out, filename, kExpected); + REQUIRE(archive_write_free(out) == ARCHIVE_OK); + + SECTION("Read tar") { + auto* in = archive_read_new(); + REQUIRE(in != nullptr); + REQUIRE(archive_read_support_format_tar(in) == ARCHIVE_OK); + CHECK(read_archive(in, filename) == kExpected); + REQUIRE(archive_read_free(in) == ARCHIVE_OK); + } + + SECTION("Extract tar to disk") { + extract_archive(filename); + compare_extracted(); + } + + if (FileSystemManager::IsExecutable("/usr/bin/tar")) { + SECTION("Extract via system tar") { + REQUIRE(system(("/usr/bin/tar xf " + filename).c_str()) == 0); + compare_extracted(); + } + } + } +} + +TEST_CASE("Read-write tar.gz", "[archive_read_write]") { + std::string test_dir{"test_tar_gz"}; + std::string filename{"test.tar.gz"}; + + REQUIRE(FileSystemManager::RemoveDirectory(test_dir, /*recursively=*/true)); + REQUIRE(FileSystemManager::CreateDirectory(test_dir)); + auto anchor = FileSystemManager::ChangeDirectory(test_dir); + + SECTION("Write tar.gz") { + auto* out = archive_write_new(); + REQUIRE(out != nullptr); + REQUIRE(archive_write_set_format_pax_restricted(out) == ARCHIVE_OK); + REQUIRE(archive_write_add_filter_gzip(out) == ARCHIVE_OK); + write_archive(out, filename, kExpected); + REQUIRE(archive_write_free(out) == ARCHIVE_OK); + + SECTION("Read tar.gz") { + auto* in = archive_read_new(); + REQUIRE(in != nullptr); + REQUIRE(archive_read_support_format_tar(in) == ARCHIVE_OK); + REQUIRE(archive_read_support_filter_gzip(in) == ARCHIVE_OK); + CHECK(read_archive(in, filename) == kExpected); + REQUIRE(archive_read_free(in) == ARCHIVE_OK); + } + + SECTION("Extract tar.gz to disk") { + extract_archive(filename); + compare_extracted(); + } + + if (FileSystemManager::IsExecutable("/usr/bin/tar") and + FileSystemManager::IsExecutable("/usr/bin/gzip")) { + SECTION("Extract via system tar and gzip") { + REQUIRE(system(("/usr/bin/tar xzf " + filename).c_str()) == 0); + compare_extracted(); + } + } + } +} + +TEST_CASE("Read-write tar.bz2", "[archive_read_write]") { + std::string test_dir{"test_tar_bz2"}; + std::string filename{"test.tar.bz2"}; + + REQUIRE(FileSystemManager::RemoveDirectory(test_dir, /*recursively=*/true)); + REQUIRE(FileSystemManager::CreateDirectory(test_dir)); + auto anchor = FileSystemManager::ChangeDirectory(test_dir); + + SECTION("Write tar.bz2") { + auto* out = archive_write_new(); + REQUIRE(out != nullptr); + REQUIRE(archive_write_set_format_pax_restricted(out) == ARCHIVE_OK); + REQUIRE(archive_write_add_filter_bzip2(out) == ARCHIVE_OK); + write_archive(out, filename, kExpected); + REQUIRE(archive_write_free(out) == ARCHIVE_OK); + + SECTION("Read tar.bz2") { + auto* in = archive_read_new(); + REQUIRE(in != nullptr); + REQUIRE(archive_read_support_format_tar(in) == ARCHIVE_OK); + REQUIRE(archive_read_support_filter_bzip2(in) == ARCHIVE_OK); + CHECK(read_archive(in, filename) == kExpected); + REQUIRE(archive_read_free(in) == ARCHIVE_OK); + } + + SECTION("Extract tar.bz2 to disk") { + extract_archive(filename); + compare_extracted(); + } + + if (FileSystemManager::IsExecutable("/usr/bin/tar") and + FileSystemManager::IsExecutable("/usr/bin/bzip2")) { + SECTION("Extract via system tar and bzip2") { + REQUIRE(system(("/usr/bin/tar xjf " + filename).c_str()) == 0); + compare_extracted(); + } + } + } +} + +TEST_CASE("Read-write zip", "[archive_read_write]") { + std::string test_dir{"test_zip"}; + std::string filename{"test.zip"}; + + REQUIRE(FileSystemManager::RemoveDirectory(test_dir, /*recursively=*/true)); + REQUIRE(FileSystemManager::CreateDirectory(test_dir)); + auto anchor = FileSystemManager::ChangeDirectory(test_dir); + + SECTION("Write zip") { + auto* out = archive_write_new(); + REQUIRE(out != nullptr); + REQUIRE(archive_write_set_format_zip(out) == ARCHIVE_OK); + write_archive(out, filename, kExpected); + REQUIRE(archive_write_free(out) == ARCHIVE_OK); + + SECTION("Read zip") { + auto* in = archive_read_new(); + REQUIRE(in != nullptr); + REQUIRE(archive_read_support_format_zip(in) == ARCHIVE_OK); + CHECK(read_archive(in, filename) == kExpected); + REQUIRE(archive_read_free(in) == ARCHIVE_OK); + } + + SECTION("Extract zip to disk") { + extract_archive(filename); + compare_extracted(); + } + + if (FileSystemManager::IsExecutable("/usr/bin/unzip")) { + SECTION("Extract via system unzip") { + REQUIRE(system(("/usr/bin/unzip " + filename).c_str()) == 0); + compare_extracted(); + } + } + } +} |