Add erofs filesystem unittest
Test: th
Bug: 206729162
Change-Id: I228cba4f1b5d40f164ee2e9df3575a836950bb38
diff --git a/Android.bp b/Android.bp
index 2a6b2a4..618b5fb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -737,6 +737,21 @@
],
}
+genrule {
+ name: "ue_unittest_erofs_imgs",
+ cmd: "$(in) $(location mkfs.erofs) $(location gen/erofs_empty.img) &&" +
+ "$(in) $(location mkfs.erofs) $(location gen/erofs.img) $(location delta_generator)",
+ srcs: ["sample_images/generate_test_erofs_images.sh"],
+ out: [
+ "gen/erofs.img",
+ "gen/erofs_empty.img",
+ ],
+ tools: [
+ "mkfs.erofs",
+ "delta_generator",
+ ],
+}
+
filegroup {
name: "update_engine_host_unittest_srcs",
srcs: [
@@ -760,6 +775,7 @@
"payload_generator/boot_img_filesystem_unittest.cc",
"payload_generator/deflate_utils_unittest.cc",
"payload_generator/delta_diff_utils_unittest.cc",
+ "payload_generator/erofs_filesystem_unittest.cc",
"payload_generator/ext2_filesystem_unittest.cc",
"payload_generator/extent_ranges_unittest.cc",
"payload_generator/extent_utils_unittest.cc",
@@ -794,6 +810,7 @@
data: [
":ue_unittest_delta_generator",
":ue_unittest_disk_imgs",
+ ":ue_unittest_erofs_imgs",
":ue_unittest_keys",
"otacerts.zip",
"unittest_key.pem",
@@ -838,6 +855,7 @@
":test_subprocess",
":ue_unittest_delta_generator",
":ue_unittest_disk_imgs",
+ ":ue_unittest_erofs_imgs",
":ue_unittest_keys",
"otacerts.zip",
"unittest_key.pem",
diff --git a/payload_generator/erofs_filesystem_unittest.cc b/payload_generator/erofs_filesystem_unittest.cc
new file mode 100644
index 0000000..e6a8929
--- /dev/null
+++ b/payload_generator/erofs_filesystem_unittest.cc
@@ -0,0 +1,127 @@
+//
+// Copyright (C) 2021 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 "update_engine/payload_generator/erofs_filesystem.h"
+
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <base/format_macros.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "payload_generator/delta_diff_generator.h"
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace {
+
+class ErofsFilesystemTest : public ::testing::Test {};
+
+} // namespace
+
+namespace chromeos_update_engine {
+
+using test_utils::GetBuildArtifactsPath;
+
+TEST_F(ErofsFilesystemTest, InvalidFilesystem) {
+ ScopedTempFile fs_filename_{"ErofsFilesystemTest-XXXXXX"};
+ ASSERT_EQ(0, truncate(fs_filename_.path().c_str(), kBlockSize));
+ unique_ptr<ErofsFilesystem> fs =
+ ErofsFilesystem::CreateFromFile(fs_filename_.path());
+ ASSERT_EQ(nullptr, fs.get());
+
+ fs = ErofsFilesystem::CreateFromFile("/path/to/invalid/file");
+ ASSERT_EQ(nullptr, fs.get());
+}
+
+TEST_F(ErofsFilesystemTest, EmptyFilesystem) {
+ unique_ptr<ErofsFilesystem> fs = ErofsFilesystem::CreateFromFile(
+ GetBuildArtifactsPath("gen/erofs_empty.img"));
+
+ ASSERT_NE(nullptr, fs);
+ ASSERT_EQ(kBlockSize, fs->GetBlockSize());
+
+ vector<FilesystemInterface::File> files;
+ ASSERT_TRUE(fs->GetFiles(&files));
+ ASSERT_EQ(files.size(), 0UL);
+}
+
+// This test parses the sample images generated during build time with the
+// "generate_image.sh" script. The expected conditions of each file in these
+// images is encoded in the file name, as defined in the mentioned script.
+TEST_F(ErofsFilesystemTest, ParseGeneratedImages) {
+ const auto build_path = GetBuildArtifactsPath("gen/erofs.img");
+ auto fs = ErofsFilesystem::CreateFromFile(build_path);
+ ASSERT_NE(fs, nullptr);
+ ASSERT_EQ(kBlockSize, fs->GetBlockSize());
+
+ vector<ErofsFilesystem::File> files;
+ ASSERT_TRUE(fs->GetFiles(&files));
+
+ std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) {
+ return a.name < b.name;
+ });
+ vector<string> filenames;
+ filenames.resize(files.size());
+ std::transform(
+ files.begin(), files.end(), filenames.begin(), [](const auto& file) {
+ return file.name;
+ });
+ const std::vector<std::string> expected_filenames = {
+ "/delta_generator",
+ "/dir1/dir2/dir123/chunks_of_zero",
+ // Empty files are ignored
+ // "/dir1/dir2/dir123/empty",
+ "/dir1/dir2/file0",
+ "/dir1/dir2/file1",
+ "/dir1/dir2/file2",
+ "/dir1/dir2/file4",
+ "/dir1/file0",
+ "/dir1/file2",
+ "/file1",
+ // Files < 4K are stored inline, and therefore ignored, as they are often
+ // stored not on block boundary.
+ // "/generate_test_erofs_images.sh"
+ };
+ ASSERT_EQ(filenames, expected_filenames);
+ const auto delta_generator = files[0];
+ ASSERT_GT(delta_generator.compressed_file_info.blocks.size(), 0UL);
+ size_t compressed_size = 0;
+ size_t uncompressed_size = 0;
+ for (const auto& block : delta_generator.compressed_file_info.blocks) {
+ compressed_size += block.compressed_length;
+ uncompressed_size += block.uncompressed_length;
+ }
+ ASSERT_GE(uncompressed_size,
+ static_cast<size_t>(delta_generator.file_stat.st_size))
+ << "Uncompressed data should be at least as big as original file, plus "
+ "possible trailing data.";
+ const auto total_blocks = utils::BlocksInExtents(delta_generator.extents);
+ ASSERT_EQ(compressed_size, total_blocks * kBlockSize);
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_generator/ext2_filesystem_unittest.cc b/payload_generator/ext2_filesystem_unittest.cc
index 88e1538..8fa5080 100644
--- a/payload_generator/ext2_filesystem_unittest.cc
+++ b/payload_generator/ext2_filesystem_unittest.cc
@@ -57,10 +57,10 @@
}
}
-} // namespace
-
class Ext2FilesystemTest : public ::testing::Test {};
+} // namespace
+
TEST_F(Ext2FilesystemTest, InvalidFilesystem) {
ScopedTempFile fs_filename_{"Ext2FilesystemTest-XXXXXX"};
ASSERT_EQ(0, truncate(fs_filename_.path().c_str(), kDefaultFilesystemSize));
diff --git a/sample_images/generate_test_erofs_images.sh b/sample_images/generate_test_erofs_images.sh
new file mode 100755
index 0000000..c058f3c
--- /dev/null
+++ b/sample_images/generate_test_erofs_images.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+set -e
+
+sh_path=$0
+mkfs=$1
+output_image=$2
+delta_generator=$3
+
+fs_root=$(mktemp -d -t erofs-XXXXXXXXXX)
+
+clean_up () {
+ ARG=$?
+ rm -rf $fs_root
+ echo "> clean_up"
+ exit $ARG
+}
+trap clean_up EXIT
+
+if [ ! -z "${delta_generator}" ]; then
+ mkdir -p ${fs_root}/dir1/dir2/dir123/nested_dir
+ mkdir -p ${fs_root}/etc/
+ cp ${sh_path} ${fs_root}/
+ truncate -s 1M ${fs_root}/file1
+ truncate -s 1M ${fs_root}/dir1/file2
+ truncate -s 1M ${fs_root}/dir1/file0
+ truncate -s 1M ${fs_root}/dir1/dir2/file0
+ truncate -s 1M ${fs_root}/dir1/dir2/file1
+ truncate -s 1M ${fs_root}/dir1/dir2/file2
+ truncate -s 1M ${fs_root}/dir1/dir2/file4
+ touch ${fs_root}/dir1/dir2/dir123/empty
+ cp ${delta_generator} ${fs_root}/delta_generator
+ echo "PAYLOAD_MINOR_VERSION=1234" > ${fs_root}/etc/update_engine.conf
+ truncate -s 16M ${fs_root}/dir1/dir2/dir123/chunks_of_zero
+fi
+
+${mkfs} -z lz4hc,9 ${output_image} ${fs_root}