blob: 4a11c52904dc55fe0b72babeb79cfd905ef6e172 [file] [log] [blame]
Darin Petkov68c10d12010-10-14 09:24:37 -07001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
adlr@google.com3defe6a2009-12-04 20:57:17 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <unistd.h>
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -08009#include <set>
Andrew de los Reyesef017552010-10-06 17:57:52 -070010#include <sstream>
adlr@google.com3defe6a2009-12-04 20:57:17 +000011#include <string>
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070012#include <utility>
adlr@google.com3defe6a2009-12-04 20:57:17 +000013#include <vector>
adlr@google.com3defe6a2009-12-04 20:57:17 +000014#include <gtest/gtest.h>
Chris Masone790e62e2010-08-12 10:41:18 -070015#include "base/logging.h"
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070016#include "update_engine/cycle_breaker.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000017#include "update_engine/delta_diff_generator.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070018#include "update_engine/delta_performer.h"
Andrew de los Reyesef017552010-10-06 17:57:52 -070019#include "update_engine/extent_ranges.h"
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070020#include "update_engine/graph_types.h"
21#include "update_engine/graph_utils.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000022#include "update_engine/subprocess.h"
23#include "update_engine/test_utils.h"
Andrew de los Reyesef017552010-10-06 17:57:52 -070024#include "update_engine/topological_sort.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000025#include "update_engine/utils.h"
26
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070027using std::make_pair;
28using std::set;
29using std::string;
Andrew de los Reyesef017552010-10-06 17:57:52 -070030using std::stringstream;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070031using std::vector;
32
adlr@google.com3defe6a2009-12-04 20:57:17 +000033namespace chromeos_update_engine {
34
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070035typedef DeltaDiffGenerator::Block Block;
36
37namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070038int64_t BlocksInExtents(
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070039 const google::protobuf::RepeatedPtrField<Extent>& extents) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070040 int64_t ret = 0;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070041 for (int i = 0; i < extents.size(); i++) {
42 ret += extents.Get(i).num_blocks();
43 }
44 return ret;
45}
46} // namespace {}
47
48class DeltaDiffGeneratorTest : public ::testing::Test {
49 protected:
50 const string old_path() { return "DeltaDiffGeneratorTest-old_path"; }
51 const string new_path() { return "DeltaDiffGeneratorTest-new_path"; }
52 virtual void TearDown() {
53 unlink(old_path().c_str());
54 unlink(new_path().c_str());
55 }
56};
57
58TEST_F(DeltaDiffGeneratorTest, RunAsRootMoveSmallTest) {
59 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
60 reinterpret_cast<const char*>(kRandomString),
61 sizeof(kRandomString)));
62 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
63 reinterpret_cast<const char*>(kRandomString),
64 sizeof(kRandomString)));
65 vector<char> data;
66 DeltaArchiveManifest_InstallOperation op;
67 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
68 new_path(),
69 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -070070 &op,
71 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070072 EXPECT_TRUE(data.empty());
73
74 EXPECT_TRUE(op.has_type());
75 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
76 EXPECT_FALSE(op.has_data_offset());
77 EXPECT_FALSE(op.has_data_length());
78 EXPECT_EQ(1, op.src_extents_size());
79 EXPECT_EQ(sizeof(kRandomString), op.src_length());
80 EXPECT_EQ(1, op.dst_extents_size());
81 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
82 EXPECT_EQ(BlocksInExtents(op.src_extents()),
83 BlocksInExtents(op.dst_extents()));
84 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
85}
86
87TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffSmallTest) {
88 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
89 reinterpret_cast<const char*>(kRandomString),
90 sizeof(kRandomString) - 1));
91 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
92 reinterpret_cast<const char*>(kRandomString),
93 sizeof(kRandomString)));
94 vector<char> data;
95 DeltaArchiveManifest_InstallOperation op;
96 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
97 new_path(),
98 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -070099 &op,
100 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700101 EXPECT_FALSE(data.empty());
102
103 EXPECT_TRUE(op.has_type());
104 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
105 EXPECT_FALSE(op.has_data_offset());
106 EXPECT_FALSE(op.has_data_length());
107 EXPECT_EQ(1, op.src_extents_size());
108 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
109 EXPECT_EQ(1, op.dst_extents_size());
110 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
111 EXPECT_EQ(BlocksInExtents(op.src_extents()),
112 BlocksInExtents(op.dst_extents()));
113 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
114}
115
116TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) {
117 vector<char> new_data;
118 for (int i = 0; i < 2; i++) {
119 new_data.insert(new_data.end(),
120 kRandomString,
121 kRandomString + sizeof(kRandomString));
122 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
123 &new_data[0],
124 new_data.size()));
125 vector<char> data;
126 DeltaArchiveManifest_InstallOperation op;
127 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
128 new_path(),
129 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700130 &op,
131 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700132 EXPECT_FALSE(data.empty());
133
134 EXPECT_TRUE(op.has_type());
135 const DeltaArchiveManifest_InstallOperation_Type expected_type =
136 (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE :
137 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
138 EXPECT_EQ(expected_type, op.type());
139 EXPECT_FALSE(op.has_data_offset());
140 EXPECT_FALSE(op.has_data_length());
141 EXPECT_EQ(0, op.src_extents_size());
142 EXPECT_FALSE(op.has_src_length());
143 EXPECT_EQ(1, op.dst_extents_size());
144 EXPECT_EQ(new_data.size(), op.dst_length());
145 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
146 }
147}
148
Darin Petkov68c10d12010-10-14 09:24:37 -0700149TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNoGatherExtentsSmallTest) {
150 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
151 reinterpret_cast<const char*>(kRandomString),
152 sizeof(kRandomString) - 1));
153 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
154 reinterpret_cast<const char*>(kRandomString),
155 sizeof(kRandomString)));
156 vector<char> data;
157 DeltaArchiveManifest_InstallOperation op;
158 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
159 new_path(),
160 &data,
161 &op,
162 false));
163 EXPECT_FALSE(data.empty());
164
165 EXPECT_TRUE(op.has_type());
166 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
167 EXPECT_FALSE(op.has_data_offset());
168 EXPECT_FALSE(op.has_data_length());
169 EXPECT_EQ(1, op.src_extents_size());
170 EXPECT_EQ(0, op.src_extents().Get(0).start_block());
171 EXPECT_EQ(1, op.src_extents().Get(0).num_blocks());
172 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
173 EXPECT_EQ(1, op.dst_extents_size());
174 EXPECT_EQ(0, op.dst_extents().Get(0).start_block());
175 EXPECT_EQ(1, op.dst_extents().Get(0).num_blocks());
176 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
177}
178
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700179namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700180void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700181 vect->resize(vect->size() + 1);
182 vect->back().set_start_block(start);
183 vect->back().set_num_blocks(length);
184}
185void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700186 uint64_t start,
187 uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700188 Extent* extent = op->add_src_extents();
189 extent->set_start_block(start);
190 extent->set_num_blocks(length);
191}
192}
193
194TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
195 vector<Extent> remove_blocks;
196 AppendExtent(&remove_blocks, 3, 3);
197 AppendExtent(&remove_blocks, 7, 1);
198 vector<Extent> replace_blocks;
199 AppendExtent(&replace_blocks, 10, 2);
200 AppendExtent(&replace_blocks, 13, 2);
Andrew de los Reyesef017552010-10-06 17:57:52 -0700201 Vertex vertex;
202 DeltaArchiveManifest_InstallOperation& op = vertex.op;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700203 OpAppendExtent(&op, 4, 3);
204 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
205 OpAppendExtent(&op, 3, 1);
206 OpAppendExtent(&op, 7, 3);
Darin Petkov68c10d12010-10-14 09:24:37 -0700207
Andrew de los Reyesef017552010-10-06 17:57:52 -0700208 DeltaDiffGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700209
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700210 EXPECT_EQ(7, op.src_extents_size());
211 EXPECT_EQ(11, op.src_extents(0).start_block());
212 EXPECT_EQ(1, op.src_extents(0).num_blocks());
213 EXPECT_EQ(13, op.src_extents(1).start_block());
214 EXPECT_EQ(1, op.src_extents(1).num_blocks());
215 EXPECT_EQ(6, op.src_extents(2).start_block());
216 EXPECT_EQ(1, op.src_extents(2).num_blocks());
217 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
218 EXPECT_EQ(4, op.src_extents(3).num_blocks());
219 EXPECT_EQ(10, op.src_extents(4).start_block());
220 EXPECT_EQ(1, op.src_extents(4).num_blocks());
221 EXPECT_EQ(14, op.src_extents(5).start_block());
222 EXPECT_EQ(1, op.src_extents(5).num_blocks());
223 EXPECT_EQ(8, op.src_extents(6).start_block());
224 EXPECT_EQ(2, op.src_extents(6).num_blocks());
225}
226
227TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) {
228 Graph graph;
229 vector<Block> blocks(9);
Darin Petkov68c10d12010-10-14 09:24:37 -0700230
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700231 // Create nodes in graph
232 {
233 graph.resize(graph.size() + 1);
234 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
235 // Reads from blocks 3, 5, 7
236 vector<Extent> extents;
237 graph_utils::AppendBlockToExtents(&extents, 3);
238 graph_utils::AppendBlockToExtents(&extents, 5);
239 graph_utils::AppendBlockToExtents(&extents, 7);
240 DeltaDiffGenerator::StoreExtents(extents,
241 graph.back().op.mutable_src_extents());
242 blocks[3].reader = graph.size() - 1;
243 blocks[5].reader = graph.size() - 1;
244 blocks[7].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700245
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700246 // Writes to blocks 1, 2, 4
247 extents.clear();
248 graph_utils::AppendBlockToExtents(&extents, 1);
249 graph_utils::AppendBlockToExtents(&extents, 2);
250 graph_utils::AppendBlockToExtents(&extents, 4);
251 DeltaDiffGenerator::StoreExtents(extents,
252 graph.back().op.mutable_dst_extents());
253 blocks[1].writer = graph.size() - 1;
254 blocks[2].writer = graph.size() - 1;
255 blocks[4].writer = graph.size() - 1;
256 }
257 {
258 graph.resize(graph.size() + 1);
259 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
260 // Reads from blocks 1, 2, 4
261 vector<Extent> extents;
262 graph_utils::AppendBlockToExtents(&extents, 1);
263 graph_utils::AppendBlockToExtents(&extents, 2);
264 graph_utils::AppendBlockToExtents(&extents, 4);
265 DeltaDiffGenerator::StoreExtents(extents,
266 graph.back().op.mutable_src_extents());
267 blocks[1].reader = graph.size() - 1;
268 blocks[2].reader = graph.size() - 1;
269 blocks[4].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700270
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700271 // Writes to blocks 3, 5, 6
272 extents.clear();
273 graph_utils::AppendBlockToExtents(&extents, 3);
274 graph_utils::AppendBlockToExtents(&extents, 5);
275 graph_utils::AppendBlockToExtents(&extents, 6);
276 DeltaDiffGenerator::StoreExtents(extents,
277 graph.back().op.mutable_dst_extents());
278 blocks[3].writer = graph.size() - 1;
279 blocks[5].writer = graph.size() - 1;
280 blocks[6].writer = graph.size() - 1;
281 }
Darin Petkov68c10d12010-10-14 09:24:37 -0700282
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700283 // Create edges
284 DeltaDiffGenerator::CreateEdges(&graph, blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700285
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700286 // Find cycles
287 CycleBreaker cycle_breaker;
288 set<Edge> cut_edges;
289 cycle_breaker.BreakCycles(graph, &cut_edges);
290
291 EXPECT_EQ(1, cut_edges.size());
292 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
293 0)));
294
Andrew de los Reyesef017552010-10-06 17:57:52 -0700295 vector<CutEdgeVertexes> cuts;
296 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts));
Darin Petkov68c10d12010-10-14 09:24:37 -0700297
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700298 EXPECT_EQ(3, graph.size());
Darin Petkov68c10d12010-10-14 09:24:37 -0700299
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700300 // Check new node in graph:
301 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
302 graph.back().op.type());
303 EXPECT_EQ(2, graph.back().op.src_extents_size());
Andrew de los Reyesef017552010-10-06 17:57:52 -0700304 EXPECT_EQ(1, graph.back().op.dst_extents_size());
305 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block());
306 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700307 EXPECT_TRUE(graph.back().out_edges.empty());
Darin Petkov68c10d12010-10-14 09:24:37 -0700308
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700309 // Check that old node reads from new blocks
Andrew de los Reyesef017552010-10-06 17:57:52 -0700310 EXPECT_EQ(2, graph[0].op.src_extents_size());
311 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block());
312 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks());
313 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700314 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700315
316 // And that the old dst extents haven't changed
317 EXPECT_EQ(2, graph[0].op.dst_extents_size());
318 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block());
319 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks());
320 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block());
321 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks());
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700322
323 // Ensure it only depends on the next node and the new temp node
324 EXPECT_EQ(2, graph[0].out_edges.size());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700325 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700326 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
327 1));
328
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700329 // Check second node has unchanged extents
330 EXPECT_EQ(2, graph[1].op.src_extents_size());
331 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block());
332 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks());
333 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block());
334 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks());
335
336 EXPECT_EQ(2, graph[1].op.dst_extents_size());
337 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block());
338 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks());
339 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block());
340 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks());
Darin Petkov68c10d12010-10-14 09:24:37 -0700341
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700342 // Ensure it only depends on the next node
343 EXPECT_EQ(1, graph[1].out_edges.size());
344 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
345}
346
347TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) {
348 string orig_blobs;
349 EXPECT_TRUE(
350 utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL));
351
352 string orig_data = "abcd";
353 EXPECT_TRUE(
354 utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
355
356 string new_blobs;
357 EXPECT_TRUE(
358 utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL));
Darin Petkov68c10d12010-10-14 09:24:37 -0700359
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700360 DeltaArchiveManifest manifest;
361 DeltaArchiveManifest_InstallOperation* op =
362 manifest.add_install_operations();
363 op->set_data_offset(1);
364 op->set_data_length(3);
365 op = manifest.add_install_operations();
366 op->set_data_offset(0);
367 op->set_data_length(1);
Darin Petkov68c10d12010-10-14 09:24:37 -0700368
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700369 EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest,
370 orig_blobs,
371 new_blobs));
Darin Petkov68c10d12010-10-14 09:24:37 -0700372
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700373 string new_data;
374 EXPECT_TRUE(utils::ReadFileToString(new_blobs, &new_data));
375 EXPECT_EQ("bcda", new_data);
376 EXPECT_EQ(2, manifest.install_operations_size());
377 EXPECT_EQ(0, manifest.install_operations(0).data_offset());
378 EXPECT_EQ(3, manifest.install_operations(0).data_length());
379 EXPECT_EQ(3, manifest.install_operations(1).data_offset());
380 EXPECT_EQ(1, manifest.install_operations(1).data_length());
Darin Petkov68c10d12010-10-14 09:24:37 -0700381
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700382 unlink(orig_blobs.c_str());
383 unlink(new_blobs.c_str());
384}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000385
Andrew de los Reyesef017552010-10-06 17:57:52 -0700386TEST_F(DeltaDiffGeneratorTest, MoveFullOpsToBackTest) {
387 Graph graph(4);
388 graph[0].file_name = "A";
389 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
390 graph[1].file_name = "B";
391 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
392 graph[2].file_name = "C";
393 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
394 graph[3].file_name = "D";
395 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
396
397 vector<Vertex::Index> vect(graph.size());
398
399 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) {
400 vect[i] = i;
401 }
402 DeltaDiffGenerator::MoveFullOpsToBack(&graph, &vect);
403 EXPECT_EQ(vect.size(), graph.size());
404 EXPECT_EQ(graph[vect[0]].file_name, "B");
405 EXPECT_EQ(graph[vect[1]].file_name, "D");
406 EXPECT_EQ(graph[vect[2]].file_name, "A");
407 EXPECT_EQ(graph[vect[3]].file_name, "C");
408}
409
410namespace {
411
412#define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF
413#define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE
414#define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE
415#define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ
416
417void GenVertex(Vertex* out,
418 const vector<Extent>& src_extents,
419 const vector<Extent>& dst_extents,
420 const string& path,
421 DeltaArchiveManifest_InstallOperation_Type type) {
422 out->op.set_type(type);
423 out->file_name = path;
424 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents());
425 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents());
426}
427
428vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) {
429 return vector<Extent>(1, ExtentForRange(start_block, num_blocks));
430}
431
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700432vector<Extent> VectOfExts(uint64_t start_block1, uint64_t num_blocks1,
433 uint64_t start_block2, uint64_t num_blocks2) {
434 vector<Extent> ret(1, ExtentForRange(start_block1, num_blocks1));
435 ret.push_back(ExtentForRange(start_block2, num_blocks2));
436 return ret;
437}
438
Andrew de los Reyesef017552010-10-06 17:57:52 -0700439EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) {
440 EdgeProperties ret;
441 ret.extents = extents;
442 return ret;
443}
444
445EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) {
446 EdgeProperties ret;
447 ret.write_extents = extents;
448 return ret;
449}
450
451template<typename T>
452void DumpVect(const vector<T>& vect) {
453 std::stringstream ss(stringstream::out);
454 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end();
455 it != e; ++it) {
456 ss << *it << ", ";
457 }
458 LOG(INFO) << "{" << ss.str() << "}";
459}
460
461} // namespace {}
462
463TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksTest) {
464 Graph graph(9);
465 const vector<Extent> empt; // empty
466 const string kFilename = "/foo";
Darin Petkov68c10d12010-10-14 09:24:37 -0700467
Andrew de los Reyesef017552010-10-06 17:57:52 -0700468 // Some scratch space:
469 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
470 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
471 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
472
473 // A cycle that requires 10 blocks to break:
474 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF);
475 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9));
476 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF);
477 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
478
479 // A cycle that requires 9 blocks to break:
480 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF);
481 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10));
482 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF);
483 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
484
485 // A cycle that requires 40 blocks to break (which is too many):
486 GenVertex(&graph[7],
487 VectOfExt(120, 50),
488 VectOfExt(60, 40),
489 "",
490 OP_BSDIFF);
491 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40));
492 GenVertex(&graph[8],
493 VectOfExt(60, 40),
494 VectOfExt(120, 50),
495 kFilename,
496 OP_BSDIFF);
497 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
Darin Petkov68c10d12010-10-14 09:24:37 -0700498
Andrew de los Reyesef017552010-10-06 17:57:52 -0700499 graph_utils::DumpGraph(graph);
Darin Petkov68c10d12010-10-14 09:24:37 -0700500
Andrew de los Reyesef017552010-10-06 17:57:52 -0700501 vector<Vertex::Index> final_order;
502
503
504 // Prepare the filesystem with the minimum required for this to work
505 string temp_dir;
506 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksTest.XXXXXX",
507 &temp_dir));
508 ScopedDirRemover temp_dir_remover(temp_dir);
Darin Petkov68c10d12010-10-14 09:24:37 -0700509
Andrew de los Reyesef017552010-10-06 17:57:52 -0700510 const size_t kBlockSize = 4096;
511 vector<char> temp_data(kBlockSize * 50);
512 FillWithData(&temp_data);
513 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
514 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
Darin Petkov68c10d12010-10-14 09:24:37 -0700515
Andrew de los Reyesef017552010-10-06 17:57:52 -0700516 int fd;
517 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksTestData.XXXXXX",
518 NULL,
519 &fd));
520 ScopedFdCloser fd_closer(&fd);
521 off_t data_file_size = 0;
522
523
524 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
525 temp_dir,
526 fd,
527 &data_file_size,
528 &final_order));
529
Darin Petkov68c10d12010-10-14 09:24:37 -0700530
Andrew de los Reyesef017552010-10-06 17:57:52 -0700531 Graph expected_graph(12);
532 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
533 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
534 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
535 GenVertex(&expected_graph[3],
536 VectOfExt(10, 11),
537 VectOfExt(0, 9),
538 "",
539 OP_BSDIFF);
540 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9));
541 GenVertex(&expected_graph[4],
542 VectOfExt(60, 9),
543 VectOfExt(10, 11),
544 "",
545 OP_BSDIFF);
546 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
547 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9));
548 GenVertex(&expected_graph[5],
549 VectOfExt(40, 11),
550 VectOfExt(30, 10),
551 "",
552 OP_BSDIFF);
553 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10));
554
555 GenVertex(&expected_graph[6],
556 VectOfExt(60, 10),
557 VectOfExt(40, 11),
558 "",
559 OP_BSDIFF);
560 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
561 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10));
Darin Petkov68c10d12010-10-14 09:24:37 -0700562
Andrew de los Reyesef017552010-10-06 17:57:52 -0700563 GenVertex(&expected_graph[7],
564 VectOfExt(120, 50),
565 VectOfExt(60, 40),
566 "",
567 OP_BSDIFF);
568 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10));
569
570 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ);
571 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
572
573 GenVertex(&expected_graph[9],
574 VectOfExt(0, 9),
575 VectOfExt(60, 9),
576 "",
577 OP_MOVE);
578
579 GenVertex(&expected_graph[10],
580 VectOfExt(30, 10),
581 VectOfExt(60, 10),
582 "",
583 OP_MOVE);
584 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
Darin Petkov68c10d12010-10-14 09:24:37 -0700585
Andrew de los Reyesef017552010-10-06 17:57:52 -0700586 EXPECT_EQ(12, graph.size());
587 EXPECT_FALSE(graph.back().valid);
588 for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
589 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
590 if (i == 8) {
591 // special case
592 } else {
593 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i;
594 }
595 }
596}
597
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700598TEST_F(DeltaDiffGeneratorTest, IsNoopOperationTest) {
599 DeltaArchiveManifest_InstallOperation op;
600 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
601 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
602 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
603 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
604 *(op.add_src_extents()) = ExtentForRange(3, 2);
605 *(op.add_dst_extents()) = ExtentForRange(3, 2);
606 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
607 *(op.add_src_extents()) = ExtentForRange(7, 5);
608 *(op.add_dst_extents()) = ExtentForRange(7, 5);
609 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
610 *(op.add_src_extents()) = ExtentForRange(20, 2);
611 *(op.add_dst_extents()) = ExtentForRange(20, 1);
612 *(op.add_dst_extents()) = ExtentForRange(21, 1);
613 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
614 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 2);
615 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 1);
616 *(op.add_dst_extents()) = ExtentForRange(kSparseHole, 3);
617 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
618 *(op.add_src_extents()) = ExtentForRange(24, 1);
619 *(op.add_dst_extents()) = ExtentForRange(25, 1);
620 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
621}
622
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700623TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksReuseTest) {
624 // AssignTempBlocks(Graph* graph,
625 // const string& new_root,
626 // int data_fd,
627 // off_t* data_file_size,
628 // vector<Vertex::Index>* op_indexes,
629 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
630 // const vector<CutEdgeVertexes>& cuts
631 Graph graph(9);
632
633 const vector<Extent> empt;
634 uint64_t tmp = kTempBlockStart;
635 const string kFilename = "/foo";
636
637 vector<CutEdgeVertexes> cuts;
638 cuts.resize(3);
639
640 // Simple broken loop:
641 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE);
642 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE);
643 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE);
644 // Corresponding edges:
645 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
646 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
647 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
648 // Store the cut:
649 cuts[0].old_dst = 1;
650 cuts[0].old_src = 0;
651 cuts[0].new_vertex = 2;
652 cuts[0].tmp_extents = VectOfExt(tmp, 1);
653 tmp++;
654
655 // Slightly more complex pair of loops:
656 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE);
657 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE);
658 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE);
659 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE);
660 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE);
661 // Corresponding edges:
662 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
663 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
664 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
665 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
666 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
667 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
668 // Store the cuts:
669 cuts[1].old_dst = 5;
670 cuts[1].old_src = 3;
671 cuts[1].new_vertex = 6;
672 cuts[1].tmp_extents = VectOfExt(tmp, 2);
673 cuts[2].old_dst = 5;
674 cuts[2].old_src = 4;
675 cuts[2].new_vertex = 7;
676 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
677
678 // Supplier of temp block:
679 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE);
680
681 // Specify the final order:
682 vector<Vertex::Index> op_indexes;
683 op_indexes.push_back(2);
684 op_indexes.push_back(0);
685 op_indexes.push_back(1);
686 op_indexes.push_back(6);
687 op_indexes.push_back(3);
688 op_indexes.push_back(7);
689 op_indexes.push_back(4);
690 op_indexes.push_back(5);
691 op_indexes.push_back(8);
692
693 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
694 DeltaDiffGenerator::GenerateReverseTopoOrderMap(op_indexes,
695 &reverse_op_indexes);
696
697 // Prepare the filesystem with the minimum required for this to work
698 string temp_dir;
699 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksReuseTest.XXXXXX",
700 &temp_dir));
701 ScopedDirRemover temp_dir_remover(temp_dir);
702
703 const size_t kBlockSize = 4096;
704 vector<char> temp_data(kBlockSize * 3);
705 FillWithData(&temp_data);
706 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
707 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
708
709 int fd;
710 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksReuseTest.XXXXXX",
711 NULL,
712 &fd));
713 ScopedFdCloser fd_closer(&fd);
714 off_t data_file_size = 0;
715
716 EXPECT_TRUE(DeltaDiffGenerator::AssignTempBlocks(&graph,
717 temp_dir,
718 fd,
719 &data_file_size,
720 &op_indexes,
721 &reverse_op_indexes,
722 cuts));
723 EXPECT_FALSE(graph[6].valid);
724 EXPECT_FALSE(graph[7].valid);
725 EXPECT_EQ(1, graph[1].op.src_extents_size());
726 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block());
727 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks());
728 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type());
729}
730
adlr@google.com3defe6a2009-12-04 20:57:17 +0000731} // namespace chromeos_update_engine