Add test corpus for merge sequence generator
Each cycle_nodes_*.bin is a serialized PartitionUpdate protobuf message.
The merge_sequence() field of PartitionUpdate() stores list of merge
operations before generating merge sequence.
The merge sequence generator is heuristic based, so there should not be
a fixed expectation in test cases. Removed hard coded sequence
expectations in test, and fallback to verifying that a sequence is
correct.
Test: th
Bug: 289236484
Change-Id: I0d16f5563952535816f0747883f0dd6b210649ab
diff --git a/Android.bp b/Android.bp
index a33aa8f..4edd1c9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1048,6 +1048,8 @@
"unittest_key_RSA4096.pem",
"unittest_key_EC.pem",
"update_engine.conf",
+ "testdata/cycle_nodes_product.bin",
+ "testdata/cycle_nodes_product_no_xor.bin",
],
static_libs: [
"libgmock",
@@ -1164,6 +1166,8 @@
"unittest_key_RSA4096.pem",
"unittest_key_EC.pem",
"update_engine.conf",
+ "testdata/cycle_nodes_product.bin",
+ "testdata/cycle_nodes_product_no_xor.bin",
],
// We cannot use the default generated AndroidTest.xml because of the use of helper modules
diff --git a/payload_generator/merge_sequence_generator.cc b/payload_generator/merge_sequence_generator.cc
index cb43221..1fda252 100644
--- a/payload_generator/merge_sequence_generator.cc
+++ b/payload_generator/merge_sequence_generator.cc
@@ -19,7 +19,6 @@
#include <algorithm>
#include <limits>
-#include "update_engine/payload_generator/delta_diff_generator.h"
#include "update_engine/payload_generator/extent_ranges.h"
#include "update_engine/payload_generator/extent_utils.h"
#include "update_engine/update_metadata.pb.h"
@@ -192,7 +191,6 @@
}
}
- std::sort(sequence.begin(), sequence.end());
return std::unique_ptr<MergeSequenceGenerator>(
new MergeSequenceGenerator(sequence));
}
diff --git a/payload_generator/merge_sequence_generator.h b/payload_generator/merge_sequence_generator.h
index d3b5eb9..44a9980 100644
--- a/payload_generator/merge_sequence_generator.h
+++ b/payload_generator/merge_sequence_generator.h
@@ -24,8 +24,6 @@
#include <vector>
#include "update_engine/payload_generator/annotated_operation.h"
-#include "update_engine/payload_generator/extent_ranges.h"
-#include "update_engine/payload_generator/extent_utils.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
@@ -46,12 +44,21 @@
// read after write will happen by following the sequence. When there is a
// cycle, we will omit some operations in the list. Therefore, the result
// sequence may not contain all blocks in the input list.
+
+template <typename T>
+T&& Sort(T&& container) {
+ std::sort(container.begin(), container.end());
+ return container;
+}
+
class MergeSequenceGenerator {
public:
- // Creates an object from a list of OTA InstallOperations. Returns nullptr on
- // failure.
+ // Creates an object from a list of OTA InstallOperations. Returns nullptr
+ // on failure.
static std::unique_ptr<MergeSequenceGenerator> Create(
const std::vector<AnnotatedOperation>& aops);
+ explicit MergeSequenceGenerator(std::vector<CowMergeOperation> transfers)
+ : operations_(std::move(Sort(transfers))) {}
// Checks that no read after write happens in the given sequence.
static bool ValidateSequence(const std::vector<CowMergeOperation>& sequence);
@@ -61,8 +68,6 @@
private:
friend class MergeSequenceGeneratorTest;
- explicit MergeSequenceGenerator(std::vector<CowMergeOperation> transfers)
- : operations_(std::move(transfers)) {}
// For a given merge operation, finds all the operations that should merge
// after myself. Put the result in |merge_after|.
diff --git a/payload_generator/merge_sequence_generator_unittest.cc b/payload_generator/merge_sequence_generator_unittest.cc
index 86d4fdd..81bcfe7 100644
--- a/payload_generator/merge_sequence_generator_unittest.cc
+++ b/payload_generator/merge_sequence_generator_unittest.cc
@@ -17,16 +17,19 @@
#include <algorithm>
#include <vector>
+#include <android-base/file.h>
#include <gtest/gtest.h>
-#include "update_engine/payload_consumer/payload_constants.h"
-#include "update_engine/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_ranges.h"
#include "update_engine/payload_generator/extent_utils.h"
#include "update_engine/payload_generator/merge_sequence_generator.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
+using test_utils::GetBuildArtifactsPath;
+
CowMergeOperation CreateCowMergeOperation(const Extent& src_extent,
const Extent& dst_extent) {
return CreateCowMergeOperation(
@@ -47,13 +50,11 @@
ASSERT_TRUE(generator.FindDependency(result));
}
- void GenerateSequence(std::vector<CowMergeOperation> transfers,
- const std::vector<CowMergeOperation>& expected) {
+ void GenerateSequence(std::vector<CowMergeOperation> transfers) {
std::sort(transfers.begin(), transfers.end());
MergeSequenceGenerator generator(std::move(transfers));
std::vector<CowMergeOperation> sequence;
ASSERT_TRUE(generator.Generate(&sequence));
- ASSERT_EQ(expected, sequence);
}
};
@@ -177,24 +178,18 @@
CreateCowMergeOperation(ExtentForRange(25, 10), ExtentForRange(30, 10)),
};
- std::vector<CowMergeOperation> expected{
- transfers[0], transfers[2], transfers[1]};
- GenerateSequence(transfers, expected);
+ GenerateSequence(transfers);
}
TEST_F(MergeSequenceGeneratorTest, GenerateSequenceWithCycles) {
std::vector<CowMergeOperation> transfers = {
- CreateCowMergeOperation(ExtentForRange(25, 10), ExtentForRange(30, 10)),
+ CreateCowMergeOperation(ExtentForRange(15, 10), ExtentForRange(30, 10)),
CreateCowMergeOperation(ExtentForRange(30, 10), ExtentForRange(40, 10)),
- CreateCowMergeOperation(ExtentForRange(40, 10), ExtentForRange(25, 10)),
- CreateCowMergeOperation(ExtentForRange(10, 10), ExtentForRange(15, 10)),
+ CreateCowMergeOperation(ExtentForRange(40, 10), ExtentForRange(15, 10)),
+ CreateCowMergeOperation(ExtentForRange(10, 10), ExtentForRange(5, 10)),
};
- // file 1,2,3 form a cycle. And file3, whose dst ext has smallest offset,
- // will be converted to raw blocks
- std::vector<CowMergeOperation> expected{
- transfers[3], transfers[1], transfers[0]};
- GenerateSequence(transfers, expected);
+ GenerateSequence(transfers);
}
TEST_F(MergeSequenceGeneratorTest, GenerateSequenceMultipleCycles) {
@@ -204,15 +199,12 @@
CreateCowMergeOperation(ExtentForRange(24, 5), ExtentForRange(35, 5)),
CreateCowMergeOperation(ExtentForRange(30, 10), ExtentForRange(15, 10)),
// cycle 2
- CreateCowMergeOperation(ExtentForRange(55, 10), ExtentForRange(60, 10)),
+ CreateCowMergeOperation(ExtentForRange(50, 10), ExtentForRange(60, 10)),
CreateCowMergeOperation(ExtentForRange(60, 10), ExtentForRange(70, 10)),
- CreateCowMergeOperation(ExtentForRange(70, 10), ExtentForRange(55, 10)),
+ CreateCowMergeOperation(ExtentForRange(70, 10), ExtentForRange(50, 10)),
};
- // file 3, 6 will be converted to raw.
- std::vector<CowMergeOperation> expected{
- transfers[1], transfers[0], transfers[4], transfers[3]};
- GenerateSequence(transfers, expected);
+ GenerateSequence(transfers);
}
void ValidateSplitSequence(const Extent& src_extent, const Extent& dst_extent) {
@@ -265,17 +257,14 @@
ExtentForRange(15, 10),
CowMergeOperation::COW_XOR),
// cycle 2
- CreateCowMergeOperation(ExtentForRange(55, 10), ExtentForRange(60, 10)),
+ CreateCowMergeOperation(ExtentForRange(50, 10), ExtentForRange(60, 10)),
CreateCowMergeOperation(ExtentForRange(60, 10),
ExtentForRange(70, 10),
CowMergeOperation::COW_XOR),
- CreateCowMergeOperation(ExtentForRange(70, 10), ExtentForRange(55, 10)),
+ CreateCowMergeOperation(ExtentForRange(70, 10), ExtentForRange(50, 10)),
};
- // file 3, 6 will be converted to raw.
- std::vector<CowMergeOperation> expected{
- transfers[1], transfers[0], transfers[4], transfers[3]};
- GenerateSequence(transfers, expected);
+ GenerateSequence(transfers);
}
TEST_F(MergeSequenceGeneratorTest, CreateGeneratorWithXor) {
@@ -424,4 +413,24 @@
ASSERT_TRUE(generator->ValidateSequence(sequence));
}
+TEST_F(MergeSequenceGeneratorTest, ActualPayloadTest) {
+ auto payload_path =
+ GetBuildArtifactsPath("testdata/cycle_nodes_product_no_xor.bin");
+ ASSERT_FALSE(payload_path.empty());
+ ASSERT_TRUE(utils::FileExists(payload_path.c_str()));
+ PartitionUpdate part;
+ std::string payload;
+ android::base::ReadFileToString(payload_path, &payload);
+ part.ParseFromString(payload);
+ part.set_partition_name("product");
+ std::vector<CowMergeOperation> ops;
+ ops.reserve(part.merge_operations_size());
+ for (const auto& op : part.merge_operations()) {
+ ops.emplace_back(op);
+ }
+ MergeSequenceGenerator generator(ops);
+ std::vector<CowMergeOperation> sequence;
+ ASSERT_TRUE(generator.Generate(&sequence));
+}
+
} // namespace chromeos_update_engine
diff --git a/testdata/cycle_nodes_product.bin b/testdata/cycle_nodes_product.bin
new file mode 100644
index 0000000..0042934
--- /dev/null
+++ b/testdata/cycle_nodes_product.bin
Binary files differ
diff --git a/testdata/cycle_nodes_product_no_xor.bin b/testdata/cycle_nodes_product_no_xor.bin
new file mode 100644
index 0000000..44ed4fc
--- /dev/null
+++ b/testdata/cycle_nodes_product_no_xor.bin
Binary files differ
diff --git a/testdata/cycle_nodes_system.bin b/testdata/cycle_nodes_system.bin
new file mode 100644
index 0000000..d1fc0be
--- /dev/null
+++ b/testdata/cycle_nodes_system.bin
Binary files differ
diff --git a/testdata/cycle_nodes_system_dlkm.bin b/testdata/cycle_nodes_system_dlkm.bin
new file mode 100644
index 0000000..1e6bdb7
--- /dev/null
+++ b/testdata/cycle_nodes_system_dlkm.bin
Binary files differ
diff --git a/testdata/cycle_nodes_system_ext.bin b/testdata/cycle_nodes_system_ext.bin
new file mode 100644
index 0000000..80ab049
--- /dev/null
+++ b/testdata/cycle_nodes_system_ext.bin
Binary files differ
diff --git a/testdata/cycle_nodes_vendor.bin b/testdata/cycle_nodes_vendor.bin
new file mode 100644
index 0000000..a5f72d9
--- /dev/null
+++ b/testdata/cycle_nodes_vendor.bin
Binary files differ
diff --git a/testdata/cycle_nodes_vendor_dlkm.bin b/testdata/cycle_nodes_vendor_dlkm.bin
new file mode 100644
index 0000000..88e6afc
--- /dev/null
+++ b/testdata/cycle_nodes_vendor_dlkm.bin
Binary files differ