| Index: src/platform/update_engine/delta_diff_generator_unittest.cc | 
| diff --git a/src/platform/update_engine/delta_diff_generator_unittest.cc b/src/platform/update_engine/delta_diff_generator_unittest.cc | 
| index a5def92a83b81982315308613f64c959d4c0ff68..644d9d8c9623ae6217bad13fa56f984f052a4b8e 100644 | 
| --- a/src/platform/update_engine/delta_diff_generator_unittest.cc | 
| +++ b/src/platform/update_engine/delta_diff_generator_unittest.cc | 
| @@ -8,21 +8,341 @@ | 
| #include <unistd.h> | 
| #include <set> | 
| #include <string> | 
| +#include <utility> | 
| #include <vector> | 
| -#include "base/string_util.h" | 
| #include <gtest/gtest.h> | 
| #include "chromeos/obsolete_logging.h" | 
| -#include "update_engine/decompressing_file_writer.h" | 
| +#include "update_engine/cycle_breaker.h" | 
| #include "update_engine/delta_diff_generator.h" | 
| -#include "update_engine/delta_diff_parser.h" | 
| -#include "update_engine/gzip.h" | 
| -#include "update_engine/mock_file_writer.h" | 
| +#include "update_engine/graph_types.h" | 
| +#include "update_engine/graph_utils.h" | 
| #include "update_engine/subprocess.h" | 
| #include "update_engine/test_utils.h" | 
| #include "update_engine/utils.h" | 
|  | 
| +using std::make_pair; | 
| +using std::set; | 
| +using std::string; | 
| +using std::vector; | 
| + | 
| namespace chromeos_update_engine { | 
|  | 
| -class DeltaDiffGeneratorTest : public ::testing::Test {}; | 
| +typedef DeltaDiffGenerator::Block Block; | 
| + | 
| +namespace { | 
| +int64 BlocksInExtents( | 
| +    const google::protobuf::RepeatedPtrField<Extent>& extents) { | 
| +  int64 ret = 0; | 
| +  for (int i = 0; i < extents.size(); i++) { | 
| +    ret += extents.Get(i).num_blocks(); | 
| +  } | 
| +  return ret; | 
| +} | 
| +}  // namespace {} | 
| + | 
| +class DeltaDiffGeneratorTest : public ::testing::Test { | 
| + protected: | 
| +  const string old_path() { return "DeltaDiffGeneratorTest-old_path"; } | 
| +  const string new_path() { return "DeltaDiffGeneratorTest-new_path"; } | 
| +  virtual void TearDown() { | 
| +    unlink(old_path().c_str()); | 
| +    unlink(new_path().c_str()); | 
| +  } | 
| +}; | 
| + | 
| +TEST_F(DeltaDiffGeneratorTest, RunAsRootMoveSmallTest) { | 
| +  EXPECT_TRUE(utils::WriteFile(old_path().c_str(), | 
| +                               reinterpret_cast<const char*>(kRandomString), | 
| +                               sizeof(kRandomString))); | 
| +  EXPECT_TRUE(utils::WriteFile(new_path().c_str(), | 
| +                               reinterpret_cast<const char*>(kRandomString), | 
| +                               sizeof(kRandomString))); | 
| +  vector<char> data; | 
| +  DeltaArchiveManifest_InstallOperation op; | 
| +  EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(), | 
| +                                                 new_path(), | 
| +                                                 &data, | 
| +                                                 &op)); | 
| +  EXPECT_TRUE(data.empty()); | 
| + | 
| +  EXPECT_TRUE(op.has_type()); | 
| +  EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type()); | 
| +  EXPECT_FALSE(op.has_data_offset()); | 
| +  EXPECT_FALSE(op.has_data_length()); | 
| +  EXPECT_EQ(1, op.src_extents_size()); | 
| +  EXPECT_EQ(sizeof(kRandomString), op.src_length()); | 
| +  EXPECT_EQ(1, op.dst_extents_size()); | 
| +  EXPECT_EQ(sizeof(kRandomString), op.dst_length()); | 
| +  EXPECT_EQ(BlocksInExtents(op.src_extents()), | 
| +            BlocksInExtents(op.dst_extents())); | 
| +  EXPECT_EQ(1, BlocksInExtents(op.dst_extents())); | 
| +} | 
| + | 
| +TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffSmallTest) { | 
| +  EXPECT_TRUE(utils::WriteFile(old_path().c_str(), | 
| +                               reinterpret_cast<const char*>(kRandomString), | 
| +                               sizeof(kRandomString) - 1)); | 
| +  EXPECT_TRUE(utils::WriteFile(new_path().c_str(), | 
| +                               reinterpret_cast<const char*>(kRandomString), | 
| +                               sizeof(kRandomString))); | 
| +  vector<char> data; | 
| +  DeltaArchiveManifest_InstallOperation op; | 
| +  EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(), | 
| +                                                 new_path(), | 
| +                                                 &data, | 
| +                                                 &op)); | 
| +  EXPECT_FALSE(data.empty()); | 
| + | 
| +  EXPECT_TRUE(op.has_type()); | 
| +  EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type()); | 
| +  EXPECT_FALSE(op.has_data_offset()); | 
| +  EXPECT_FALSE(op.has_data_length()); | 
| +  EXPECT_EQ(1, op.src_extents_size()); | 
| +  EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length()); | 
| +  EXPECT_EQ(1, op.dst_extents_size()); | 
| +  EXPECT_EQ(sizeof(kRandomString), op.dst_length()); | 
| +  EXPECT_EQ(BlocksInExtents(op.src_extents()), | 
| +            BlocksInExtents(op.dst_extents())); | 
| +  EXPECT_EQ(1, BlocksInExtents(op.dst_extents())); | 
| +} | 
| + | 
| +TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) { | 
| +  vector<char> new_data; | 
| +  for (int i = 0; i < 2; i++) { | 
| +    new_data.insert(new_data.end(), | 
| +                    kRandomString, | 
| +                    kRandomString + sizeof(kRandomString)); | 
| +    EXPECT_TRUE(utils::WriteFile(new_path().c_str(), | 
| +                                 &new_data[0], | 
| +                                 new_data.size())); | 
| +    vector<char> data; | 
| +    DeltaArchiveManifest_InstallOperation op; | 
| +    EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(), | 
| +                                                   new_path(), | 
| +                                                   &data, | 
| +                                                   &op)); | 
| +    EXPECT_FALSE(data.empty()); | 
| + | 
| +    EXPECT_TRUE(op.has_type()); | 
| +    const DeltaArchiveManifest_InstallOperation_Type expected_type = | 
| +        (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE : | 
| +         DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); | 
| +    EXPECT_EQ(expected_type, op.type()); | 
| +    EXPECT_FALSE(op.has_data_offset()); | 
| +    EXPECT_FALSE(op.has_data_length()); | 
| +    EXPECT_EQ(0, op.src_extents_size()); | 
| +    EXPECT_FALSE(op.has_src_length()); | 
| +    EXPECT_EQ(1, op.dst_extents_size()); | 
| +    EXPECT_EQ(new_data.size(), op.dst_length()); | 
| +    EXPECT_EQ(1, BlocksInExtents(op.dst_extents())); | 
| +  } | 
| +} | 
| + | 
| +namespace { | 
| +void AppendExtent(vector<Extent>* vect, uint64 start, uint64 length) { | 
| +  vect->resize(vect->size() + 1); | 
| +  vect->back().set_start_block(start); | 
| +  vect->back().set_num_blocks(length); | 
| +} | 
| +void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op, | 
| +                    uint64 start, | 
| +                    uint64 length) { | 
| +  Extent* extent = op->add_src_extents(); | 
| +  extent->set_start_block(start); | 
| +  extent->set_num_blocks(length); | 
| +} | 
| +} | 
| + | 
| +TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) { | 
| +  vector<Extent> remove_blocks; | 
| +  AppendExtent(&remove_blocks, 3, 3); | 
| +  AppendExtent(&remove_blocks, 7, 1); | 
| +  vector<Extent> replace_blocks; | 
| +  AppendExtent(&replace_blocks, 10, 2); | 
| +  AppendExtent(&replace_blocks, 13, 2); | 
| +  DeltaArchiveManifest_InstallOperation op; | 
| +  OpAppendExtent(&op, 4, 3); | 
| +  OpAppendExtent(&op, kSparseHole, 4);  // Sparse hole in file | 
| +  OpAppendExtent(&op, 3, 1); | 
| +  OpAppendExtent(&op, 7, 3); | 
| + | 
| +  DeltaDiffGenerator::SubstituteBlocks(&op, remove_blocks, replace_blocks); | 
| + | 
| +  EXPECT_EQ(7, op.src_extents_size()); | 
| +  EXPECT_EQ(11, op.src_extents(0).start_block()); | 
| +  EXPECT_EQ(1, op.src_extents(0).num_blocks()); | 
| +  EXPECT_EQ(13, op.src_extents(1).start_block()); | 
| +  EXPECT_EQ(1, op.src_extents(1).num_blocks()); | 
| +  EXPECT_EQ(6, op.src_extents(2).start_block()); | 
| +  EXPECT_EQ(1, op.src_extents(2).num_blocks()); | 
| +  EXPECT_EQ(kSparseHole, op.src_extents(3).start_block()); | 
| +  EXPECT_EQ(4, op.src_extents(3).num_blocks()); | 
| +  EXPECT_EQ(10, op.src_extents(4).start_block()); | 
| +  EXPECT_EQ(1, op.src_extents(4).num_blocks()); | 
| +  EXPECT_EQ(14, op.src_extents(5).start_block()); | 
| +  EXPECT_EQ(1, op.src_extents(5).num_blocks()); | 
| +  EXPECT_EQ(8, op.src_extents(6).start_block()); | 
| +  EXPECT_EQ(2, op.src_extents(6).num_blocks()); | 
| +} | 
| + | 
| +TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) { | 
| +  Graph graph; | 
| +  vector<Block> blocks(9); | 
| + | 
| +  // Create nodes in graph | 
| +  { | 
| +    graph.resize(graph.size() + 1); | 
| +    graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); | 
| +    // Reads from blocks 3, 5, 7 | 
| +    vector<Extent> extents; | 
| +    graph_utils::AppendBlockToExtents(&extents, 3); | 
| +    graph_utils::AppendBlockToExtents(&extents, 5); | 
| +    graph_utils::AppendBlockToExtents(&extents, 7); | 
| +    DeltaDiffGenerator::StoreExtents(extents, | 
| +                                     graph.back().op.mutable_src_extents()); | 
| +    blocks[3].reader = graph.size() - 1; | 
| +    blocks[5].reader = graph.size() - 1; | 
| +    blocks[7].reader = graph.size() - 1; | 
| + | 
| +    // Writes to blocks 1, 2, 4 | 
| +    extents.clear(); | 
| +    graph_utils::AppendBlockToExtents(&extents, 1); | 
| +    graph_utils::AppendBlockToExtents(&extents, 2); | 
| +    graph_utils::AppendBlockToExtents(&extents, 4); | 
| +    DeltaDiffGenerator::StoreExtents(extents, | 
| +                                     graph.back().op.mutable_dst_extents()); | 
| +    blocks[1].writer = graph.size() - 1; | 
| +    blocks[2].writer = graph.size() - 1; | 
| +    blocks[4].writer = graph.size() - 1; | 
| +  } | 
| +  { | 
| +    graph.resize(graph.size() + 1); | 
| +    graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); | 
| +    // Reads from blocks 1, 2, 4 | 
| +    vector<Extent> extents; | 
| +    graph_utils::AppendBlockToExtents(&extents, 1); | 
| +    graph_utils::AppendBlockToExtents(&extents, 2); | 
| +    graph_utils::AppendBlockToExtents(&extents, 4); | 
| +    DeltaDiffGenerator::StoreExtents(extents, | 
| +                                     graph.back().op.mutable_src_extents()); | 
| +    blocks[1].reader = graph.size() - 1; | 
| +    blocks[2].reader = graph.size() - 1; | 
| +    blocks[4].reader = graph.size() - 1; | 
| + | 
| +    // Writes to blocks 3, 5, 6 | 
| +    extents.clear(); | 
| +    graph_utils::AppendBlockToExtents(&extents, 3); | 
| +    graph_utils::AppendBlockToExtents(&extents, 5); | 
| +    graph_utils::AppendBlockToExtents(&extents, 6); | 
| +    DeltaDiffGenerator::StoreExtents(extents, | 
| +                                     graph.back().op.mutable_dst_extents()); | 
| +    blocks[3].writer = graph.size() - 1; | 
| +    blocks[5].writer = graph.size() - 1; | 
| +    blocks[6].writer = graph.size() - 1; | 
| +  } | 
| + | 
| +  // Create edges | 
| +  DeltaDiffGenerator::CreateEdges(&graph, blocks); | 
| + | 
| +  // Find cycles | 
| +  CycleBreaker cycle_breaker; | 
| +  set<Edge> cut_edges; | 
| +  cycle_breaker.BreakCycles(graph, &cut_edges); | 
| + | 
| +  EXPECT_EQ(1, cut_edges.size()); | 
| +  EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1, | 
| +                                                                         0))); | 
| + | 
| +  EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, blocks, cut_edges)); | 
| + | 
| +  EXPECT_EQ(3, graph.size()); | 
| + | 
| +  // Check new node in graph: | 
| +  EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, | 
| +            graph.back().op.type()); | 
| +  EXPECT_EQ(2, graph.back().op.src_extents_size()); | 
| +  EXPECT_EQ(2, graph.back().op.dst_extents_size()); | 
| +  EXPECT_EQ(0, graph.back().op.dst_extents(0).start_block()); | 
| +  EXPECT_EQ(1, graph.back().op.dst_extents(0).num_blocks()); | 
| +  EXPECT_EQ(8, graph.back().op.dst_extents(1).start_block()); | 
| +  EXPECT_EQ(1, graph.back().op.dst_extents(1).num_blocks()); | 
| +  EXPECT_TRUE(graph.back().out_edges.empty()); | 
| + | 
| +  // Check that old node reads from new blocks | 
| +  EXPECT_EQ(3, graph[0].op.src_extents_size()); | 
| +  EXPECT_EQ(0, graph[0].op.src_extents(0).start_block()); | 
| +  EXPECT_EQ(1, graph[0].op.src_extents(0).num_blocks()); | 
| +  EXPECT_EQ(8, graph[0].op.src_extents(1).start_block()); | 
| +  EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks()); | 
| +  EXPECT_EQ(7, graph[0].op.src_extents(2).start_block()); | 
| +  EXPECT_EQ(1, graph[0].op.src_extents(2).num_blocks()); | 
| + | 
| +  // And that the old dst extents haven't changed | 
| +  EXPECT_EQ(2, graph[0].op.dst_extents_size()); | 
| +  EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block()); | 
| +  EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks()); | 
| +  EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block()); | 
| +  EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks()); | 
| + | 
| +  // Ensure it only depends on the next node | 
| +  EXPECT_EQ(1, graph[0].out_edges.size()); | 
| +  EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1)); | 
| + | 
| +  // Check second node has unchanged extents | 
| +  EXPECT_EQ(2, graph[1].op.src_extents_size()); | 
| +  EXPECT_EQ(1, graph[1].op.src_extents(0).start_block()); | 
| +  EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks()); | 
| +  EXPECT_EQ(4, graph[1].op.src_extents(1).start_block()); | 
| +  EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks()); | 
| + | 
| +  EXPECT_EQ(2, graph[1].op.dst_extents_size()); | 
| +  EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block()); | 
| +  EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks()); | 
| +  EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block()); | 
| +  EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks()); | 
| + | 
| +  // Ensure it only depends on the next node | 
| +  EXPECT_EQ(1, graph[1].out_edges.size()); | 
| +  EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2)); | 
| +} | 
| + | 
| +TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) { | 
| +  string orig_blobs; | 
| +  EXPECT_TRUE( | 
| +      utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL)); | 
| + | 
| +  string orig_data = "abcd"; | 
| +  EXPECT_TRUE( | 
| +      utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size())); | 
| + | 
| +  string new_blobs; | 
| +  EXPECT_TRUE( | 
| +      utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL)); | 
| + | 
| +  DeltaArchiveManifest manifest; | 
| +  DeltaArchiveManifest_InstallOperation* op = | 
| +      manifest.add_install_operations(); | 
| +  op->set_data_offset(1); | 
| +  op->set_data_length(3); | 
| +  op = manifest.add_install_operations(); | 
| +  op->set_data_offset(0); | 
| +  op->set_data_length(1); | 
| + | 
| +  EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest, | 
| +                                                   orig_blobs, | 
| +                                                   new_blobs)); | 
| + | 
| +  string new_data; | 
| +  EXPECT_TRUE(utils::ReadFileToString(new_blobs, &new_data)); | 
| +  EXPECT_EQ("bcda", new_data); | 
| +  EXPECT_EQ(2, manifest.install_operations_size()); | 
| +  EXPECT_EQ(0, manifest.install_operations(0).data_offset()); | 
| +  EXPECT_EQ(3, manifest.install_operations(0).data_length()); | 
| +  EXPECT_EQ(3, manifest.install_operations(1).data_offset()); | 
| +  EXPECT_EQ(1, manifest.install_operations(1).data_length()); | 
| + | 
| +  unlink(orig_blobs.c_str()); | 
| +  unlink(new_blobs.c_str()); | 
| +} | 
|  | 
| }  // namespace chromeos_update_engine | 
|  |