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