blob: bd0b48e6da2c2e92574ecfe00d5ad72fda0506a4 [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>
Thieu Le5c7d9752010-12-15 16:09:28 -08009
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -080010#include <set>
Andrew de los Reyesef017552010-10-06 17:57:52 -070011#include <sstream>
adlr@google.com3defe6a2009-12-04 20:57:17 +000012#include <string>
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070013#include <utility>
adlr@google.com3defe6a2009-12-04 20:57:17 +000014#include <vector>
Thieu Le5c7d9752010-12-15 16:09:28 -080015
16#include <base/logging.h>
17#include <base/string_util.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000018#include <gtest/gtest.h>
Thieu Le5c7d9752010-12-15 16:09:28 -080019
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070020#include "update_engine/cycle_breaker.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000021#include "update_engine/delta_diff_generator.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070022#include "update_engine/delta_performer.h"
Andrew de los Reyesef017552010-10-06 17:57:52 -070023#include "update_engine/extent_ranges.h"
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070024#include "update_engine/graph_types.h"
25#include "update_engine/graph_utils.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000026#include "update_engine/subprocess.h"
27#include "update_engine/test_utils.h"
Andrew de los Reyesef017552010-10-06 17:57:52 -070028#include "update_engine/topological_sort.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000029#include "update_engine/utils.h"
30
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070031using std::make_pair;
32using std::set;
33using std::string;
Andrew de los Reyesef017552010-10-06 17:57:52 -070034using std::stringstream;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070035using std::vector;
36
adlr@google.com3defe6a2009-12-04 20:57:17 +000037namespace chromeos_update_engine {
38
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070039typedef DeltaDiffGenerator::Block Block;
40
41namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070042int64_t BlocksInExtents(
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070043 const google::protobuf::RepeatedPtrField<Extent>& extents) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070044 int64_t ret = 0;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070045 for (int i = 0; i < extents.size(); i++) {
46 ret += extents.Get(i).num_blocks();
47 }
48 return ret;
49}
50} // namespace {}
51
52class DeltaDiffGeneratorTest : public ::testing::Test {
53 protected:
54 const string old_path() { return "DeltaDiffGeneratorTest-old_path"; }
55 const string new_path() { return "DeltaDiffGeneratorTest-new_path"; }
56 virtual void TearDown() {
57 unlink(old_path().c_str());
58 unlink(new_path().c_str());
59 }
60};
61
62TEST_F(DeltaDiffGeneratorTest, RunAsRootMoveSmallTest) {
63 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
64 reinterpret_cast<const char*>(kRandomString),
65 sizeof(kRandomString)));
66 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
67 reinterpret_cast<const char*>(kRandomString),
68 sizeof(kRandomString)));
69 vector<char> data;
70 DeltaArchiveManifest_InstallOperation op;
71 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
72 new_path(),
73 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -070074 &op,
75 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070076 EXPECT_TRUE(data.empty());
77
78 EXPECT_TRUE(op.has_type());
79 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
80 EXPECT_FALSE(op.has_data_offset());
81 EXPECT_FALSE(op.has_data_length());
82 EXPECT_EQ(1, op.src_extents_size());
83 EXPECT_EQ(sizeof(kRandomString), op.src_length());
84 EXPECT_EQ(1, op.dst_extents_size());
85 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
86 EXPECT_EQ(BlocksInExtents(op.src_extents()),
87 BlocksInExtents(op.dst_extents()));
88 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
89}
90
91TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffSmallTest) {
92 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
93 reinterpret_cast<const char*>(kRandomString),
94 sizeof(kRandomString) - 1));
95 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
96 reinterpret_cast<const char*>(kRandomString),
97 sizeof(kRandomString)));
98 vector<char> data;
99 DeltaArchiveManifest_InstallOperation op;
100 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
101 new_path(),
102 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700103 &op,
104 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700105 EXPECT_FALSE(data.empty());
106
107 EXPECT_TRUE(op.has_type());
108 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
109 EXPECT_FALSE(op.has_data_offset());
110 EXPECT_FALSE(op.has_data_length());
111 EXPECT_EQ(1, op.src_extents_size());
112 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
113 EXPECT_EQ(1, op.dst_extents_size());
114 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
115 EXPECT_EQ(BlocksInExtents(op.src_extents()),
116 BlocksInExtents(op.dst_extents()));
117 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
118}
119
120TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) {
121 vector<char> new_data;
122 for (int i = 0; i < 2; i++) {
123 new_data.insert(new_data.end(),
124 kRandomString,
125 kRandomString + sizeof(kRandomString));
126 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
127 &new_data[0],
128 new_data.size()));
129 vector<char> data;
130 DeltaArchiveManifest_InstallOperation op;
131 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
132 new_path(),
133 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700134 &op,
135 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700136 EXPECT_FALSE(data.empty());
137
138 EXPECT_TRUE(op.has_type());
139 const DeltaArchiveManifest_InstallOperation_Type expected_type =
140 (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE :
141 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
142 EXPECT_EQ(expected_type, op.type());
143 EXPECT_FALSE(op.has_data_offset());
144 EXPECT_FALSE(op.has_data_length());
145 EXPECT_EQ(0, op.src_extents_size());
146 EXPECT_FALSE(op.has_src_length());
147 EXPECT_EQ(1, op.dst_extents_size());
148 EXPECT_EQ(new_data.size(), op.dst_length());
149 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
150 }
151}
152
Darin Petkov68c10d12010-10-14 09:24:37 -0700153TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNoGatherExtentsSmallTest) {
154 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
155 reinterpret_cast<const char*>(kRandomString),
156 sizeof(kRandomString) - 1));
157 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
158 reinterpret_cast<const char*>(kRandomString),
159 sizeof(kRandomString)));
160 vector<char> data;
161 DeltaArchiveManifest_InstallOperation op;
162 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
163 new_path(),
164 &data,
165 &op,
166 false));
167 EXPECT_FALSE(data.empty());
168
169 EXPECT_TRUE(op.has_type());
170 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
171 EXPECT_FALSE(op.has_data_offset());
172 EXPECT_FALSE(op.has_data_length());
173 EXPECT_EQ(1, op.src_extents_size());
174 EXPECT_EQ(0, op.src_extents().Get(0).start_block());
175 EXPECT_EQ(1, op.src_extents().Get(0).num_blocks());
176 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
177 EXPECT_EQ(1, op.dst_extents_size());
178 EXPECT_EQ(0, op.dst_extents().Get(0).start_block());
179 EXPECT_EQ(1, op.dst_extents().Get(0).num_blocks());
180 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
181}
182
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700183namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700184void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700185 vect->resize(vect->size() + 1);
186 vect->back().set_start_block(start);
187 vect->back().set_num_blocks(length);
188}
189void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700190 uint64_t start,
191 uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700192 Extent* extent = op->add_src_extents();
193 extent->set_start_block(start);
194 extent->set_num_blocks(length);
195}
196}
197
198TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
199 vector<Extent> remove_blocks;
200 AppendExtent(&remove_blocks, 3, 3);
201 AppendExtent(&remove_blocks, 7, 1);
202 vector<Extent> replace_blocks;
203 AppendExtent(&replace_blocks, 10, 2);
204 AppendExtent(&replace_blocks, 13, 2);
Andrew de los Reyesef017552010-10-06 17:57:52 -0700205 Vertex vertex;
206 DeltaArchiveManifest_InstallOperation& op = vertex.op;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700207 OpAppendExtent(&op, 4, 3);
208 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
209 OpAppendExtent(&op, 3, 1);
210 OpAppendExtent(&op, 7, 3);
Darin Petkov68c10d12010-10-14 09:24:37 -0700211
Andrew de los Reyesef017552010-10-06 17:57:52 -0700212 DeltaDiffGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700213
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700214 EXPECT_EQ(7, op.src_extents_size());
215 EXPECT_EQ(11, op.src_extents(0).start_block());
216 EXPECT_EQ(1, op.src_extents(0).num_blocks());
217 EXPECT_EQ(13, op.src_extents(1).start_block());
218 EXPECT_EQ(1, op.src_extents(1).num_blocks());
219 EXPECT_EQ(6, op.src_extents(2).start_block());
220 EXPECT_EQ(1, op.src_extents(2).num_blocks());
221 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
222 EXPECT_EQ(4, op.src_extents(3).num_blocks());
223 EXPECT_EQ(10, op.src_extents(4).start_block());
224 EXPECT_EQ(1, op.src_extents(4).num_blocks());
225 EXPECT_EQ(14, op.src_extents(5).start_block());
226 EXPECT_EQ(1, op.src_extents(5).num_blocks());
227 EXPECT_EQ(8, op.src_extents(6).start_block());
228 EXPECT_EQ(2, op.src_extents(6).num_blocks());
229}
230
231TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) {
232 Graph graph;
233 vector<Block> blocks(9);
Darin Petkov68c10d12010-10-14 09:24:37 -0700234
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700235 // Create nodes in graph
236 {
237 graph.resize(graph.size() + 1);
238 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
239 // Reads from blocks 3, 5, 7
240 vector<Extent> extents;
241 graph_utils::AppendBlockToExtents(&extents, 3);
242 graph_utils::AppendBlockToExtents(&extents, 5);
243 graph_utils::AppendBlockToExtents(&extents, 7);
244 DeltaDiffGenerator::StoreExtents(extents,
245 graph.back().op.mutable_src_extents());
246 blocks[3].reader = graph.size() - 1;
247 blocks[5].reader = graph.size() - 1;
248 blocks[7].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700249
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700250 // Writes to blocks 1, 2, 4
251 extents.clear();
252 graph_utils::AppendBlockToExtents(&extents, 1);
253 graph_utils::AppendBlockToExtents(&extents, 2);
254 graph_utils::AppendBlockToExtents(&extents, 4);
255 DeltaDiffGenerator::StoreExtents(extents,
256 graph.back().op.mutable_dst_extents());
257 blocks[1].writer = graph.size() - 1;
258 blocks[2].writer = graph.size() - 1;
259 blocks[4].writer = graph.size() - 1;
260 }
261 {
262 graph.resize(graph.size() + 1);
263 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
264 // Reads from blocks 1, 2, 4
265 vector<Extent> extents;
266 graph_utils::AppendBlockToExtents(&extents, 1);
267 graph_utils::AppendBlockToExtents(&extents, 2);
268 graph_utils::AppendBlockToExtents(&extents, 4);
269 DeltaDiffGenerator::StoreExtents(extents,
270 graph.back().op.mutable_src_extents());
271 blocks[1].reader = graph.size() - 1;
272 blocks[2].reader = graph.size() - 1;
273 blocks[4].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700274
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700275 // Writes to blocks 3, 5, 6
276 extents.clear();
277 graph_utils::AppendBlockToExtents(&extents, 3);
278 graph_utils::AppendBlockToExtents(&extents, 5);
279 graph_utils::AppendBlockToExtents(&extents, 6);
280 DeltaDiffGenerator::StoreExtents(extents,
281 graph.back().op.mutable_dst_extents());
282 blocks[3].writer = graph.size() - 1;
283 blocks[5].writer = graph.size() - 1;
284 blocks[6].writer = graph.size() - 1;
285 }
Darin Petkov68c10d12010-10-14 09:24:37 -0700286
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700287 // Create edges
288 DeltaDiffGenerator::CreateEdges(&graph, blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700289
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700290 // Find cycles
291 CycleBreaker cycle_breaker;
292 set<Edge> cut_edges;
293 cycle_breaker.BreakCycles(graph, &cut_edges);
294
295 EXPECT_EQ(1, cut_edges.size());
296 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
297 0)));
298
Andrew de los Reyesef017552010-10-06 17:57:52 -0700299 vector<CutEdgeVertexes> cuts;
300 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts));
Darin Petkov68c10d12010-10-14 09:24:37 -0700301
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700302 EXPECT_EQ(3, graph.size());
Darin Petkov68c10d12010-10-14 09:24:37 -0700303
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700304 // Check new node in graph:
305 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
306 graph.back().op.type());
307 EXPECT_EQ(2, graph.back().op.src_extents_size());
Andrew de los Reyesef017552010-10-06 17:57:52 -0700308 EXPECT_EQ(1, graph.back().op.dst_extents_size());
309 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block());
310 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700311 EXPECT_TRUE(graph.back().out_edges.empty());
Darin Petkov68c10d12010-10-14 09:24:37 -0700312
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700313 // Check that old node reads from new blocks
Andrew de los Reyesef017552010-10-06 17:57:52 -0700314 EXPECT_EQ(2, graph[0].op.src_extents_size());
315 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block());
316 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks());
317 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700318 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700319
320 // And that the old dst extents haven't changed
321 EXPECT_EQ(2, graph[0].op.dst_extents_size());
322 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block());
323 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks());
324 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block());
325 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks());
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700326
327 // Ensure it only depends on the next node and the new temp node
328 EXPECT_EQ(2, graph[0].out_edges.size());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700329 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700330 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
331 1));
332
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700333 // Check second node has unchanged extents
334 EXPECT_EQ(2, graph[1].op.src_extents_size());
335 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block());
336 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks());
337 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block());
338 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks());
339
340 EXPECT_EQ(2, graph[1].op.dst_extents_size());
341 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block());
342 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks());
343 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block());
344 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks());
Darin Petkov68c10d12010-10-14 09:24:37 -0700345
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700346 // Ensure it only depends on the next node
347 EXPECT_EQ(1, graph[1].out_edges.size());
348 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
349}
350
351TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) {
352 string orig_blobs;
353 EXPECT_TRUE(
354 utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL));
355
356 string orig_data = "abcd";
357 EXPECT_TRUE(
358 utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
359
360 string new_blobs;
361 EXPECT_TRUE(
362 utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL));
Darin Petkov68c10d12010-10-14 09:24:37 -0700363
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700364 DeltaArchiveManifest manifest;
365 DeltaArchiveManifest_InstallOperation* op =
366 manifest.add_install_operations();
367 op->set_data_offset(1);
368 op->set_data_length(3);
369 op = manifest.add_install_operations();
370 op->set_data_offset(0);
371 op->set_data_length(1);
Darin Petkov68c10d12010-10-14 09:24:37 -0700372
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700373 EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest,
374 orig_blobs,
375 new_blobs));
Darin Petkov68c10d12010-10-14 09:24:37 -0700376
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700377 string new_data;
378 EXPECT_TRUE(utils::ReadFileToString(new_blobs, &new_data));
379 EXPECT_EQ("bcda", new_data);
380 EXPECT_EQ(2, manifest.install_operations_size());
381 EXPECT_EQ(0, manifest.install_operations(0).data_offset());
382 EXPECT_EQ(3, manifest.install_operations(0).data_length());
383 EXPECT_EQ(3, manifest.install_operations(1).data_offset());
384 EXPECT_EQ(1, manifest.install_operations(1).data_length());
Darin Petkov68c10d12010-10-14 09:24:37 -0700385
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700386 unlink(orig_blobs.c_str());
387 unlink(new_blobs.c_str());
388}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000389
Andrew de los Reyesef017552010-10-06 17:57:52 -0700390TEST_F(DeltaDiffGeneratorTest, MoveFullOpsToBackTest) {
391 Graph graph(4);
392 graph[0].file_name = "A";
393 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
394 graph[1].file_name = "B";
395 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
396 graph[2].file_name = "C";
397 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
398 graph[3].file_name = "D";
399 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
400
401 vector<Vertex::Index> vect(graph.size());
402
403 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) {
404 vect[i] = i;
405 }
406 DeltaDiffGenerator::MoveFullOpsToBack(&graph, &vect);
407 EXPECT_EQ(vect.size(), graph.size());
408 EXPECT_EQ(graph[vect[0]].file_name, "B");
409 EXPECT_EQ(graph[vect[1]].file_name, "D");
410 EXPECT_EQ(graph[vect[2]].file_name, "A");
411 EXPECT_EQ(graph[vect[3]].file_name, "C");
412}
413
414namespace {
415
416#define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF
417#define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE
418#define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE
419#define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ
420
421void GenVertex(Vertex* out,
422 const vector<Extent>& src_extents,
423 const vector<Extent>& dst_extents,
424 const string& path,
425 DeltaArchiveManifest_InstallOperation_Type type) {
426 out->op.set_type(type);
427 out->file_name = path;
428 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents());
429 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents());
430}
431
432vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) {
433 return vector<Extent>(1, ExtentForRange(start_block, num_blocks));
434}
435
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700436vector<Extent> VectOfExts(uint64_t start_block1, uint64_t num_blocks1,
437 uint64_t start_block2, uint64_t num_blocks2) {
438 vector<Extent> ret(1, ExtentForRange(start_block1, num_blocks1));
439 ret.push_back(ExtentForRange(start_block2, num_blocks2));
440 return ret;
441}
442
Andrew de los Reyesef017552010-10-06 17:57:52 -0700443EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) {
444 EdgeProperties ret;
445 ret.extents = extents;
446 return ret;
447}
448
449EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) {
450 EdgeProperties ret;
451 ret.write_extents = extents;
452 return ret;
453}
454
455template<typename T>
456void DumpVect(const vector<T>& vect) {
457 std::stringstream ss(stringstream::out);
458 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end();
459 it != e; ++it) {
460 ss << *it << ", ";
461 }
462 LOG(INFO) << "{" << ss.str() << "}";
463}
464
465} // namespace {}
466
467TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksTest) {
468 Graph graph(9);
469 const vector<Extent> empt; // empty
470 const string kFilename = "/foo";
Darin Petkov68c10d12010-10-14 09:24:37 -0700471
Andrew de los Reyesef017552010-10-06 17:57:52 -0700472 // Some scratch space:
473 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
474 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
475 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
476
477 // A cycle that requires 10 blocks to break:
478 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF);
479 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9));
480 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF);
481 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
482
483 // A cycle that requires 9 blocks to break:
484 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF);
485 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10));
486 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF);
487 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
488
489 // A cycle that requires 40 blocks to break (which is too many):
490 GenVertex(&graph[7],
491 VectOfExt(120, 50),
492 VectOfExt(60, 40),
493 "",
494 OP_BSDIFF);
495 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40));
496 GenVertex(&graph[8],
497 VectOfExt(60, 40),
498 VectOfExt(120, 50),
499 kFilename,
500 OP_BSDIFF);
501 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
Darin Petkov68c10d12010-10-14 09:24:37 -0700502
Andrew de los Reyesef017552010-10-06 17:57:52 -0700503 graph_utils::DumpGraph(graph);
Darin Petkov68c10d12010-10-14 09:24:37 -0700504
Andrew de los Reyesef017552010-10-06 17:57:52 -0700505 vector<Vertex::Index> final_order;
506
507
508 // Prepare the filesystem with the minimum required for this to work
509 string temp_dir;
510 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksTest.XXXXXX",
511 &temp_dir));
512 ScopedDirRemover temp_dir_remover(temp_dir);
Darin Petkov68c10d12010-10-14 09:24:37 -0700513
Andrew de los Reyesef017552010-10-06 17:57:52 -0700514 const size_t kBlockSize = 4096;
515 vector<char> temp_data(kBlockSize * 50);
516 FillWithData(&temp_data);
517 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
518 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
Darin Petkov68c10d12010-10-14 09:24:37 -0700519
Andrew de los Reyesef017552010-10-06 17:57:52 -0700520 int fd;
521 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksTestData.XXXXXX",
522 NULL,
523 &fd));
524 ScopedFdCloser fd_closer(&fd);
525 off_t data_file_size = 0;
526
527
528 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
529 temp_dir,
530 fd,
531 &data_file_size,
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800532 &final_order,
533 Vertex::kInvalidIndex));
Andrew de los Reyesef017552010-10-06 17:57:52 -0700534
Darin Petkov68c10d12010-10-14 09:24:37 -0700535
Andrew de los Reyesef017552010-10-06 17:57:52 -0700536 Graph expected_graph(12);
537 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
538 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
539 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
540 GenVertex(&expected_graph[3],
541 VectOfExt(10, 11),
542 VectOfExt(0, 9),
543 "",
544 OP_BSDIFF);
545 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9));
546 GenVertex(&expected_graph[4],
547 VectOfExt(60, 9),
548 VectOfExt(10, 11),
549 "",
550 OP_BSDIFF);
551 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
552 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9));
553 GenVertex(&expected_graph[5],
554 VectOfExt(40, 11),
555 VectOfExt(30, 10),
556 "",
557 OP_BSDIFF);
558 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10));
559
560 GenVertex(&expected_graph[6],
561 VectOfExt(60, 10),
562 VectOfExt(40, 11),
563 "",
564 OP_BSDIFF);
565 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
566 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10));
Darin Petkov68c10d12010-10-14 09:24:37 -0700567
Andrew de los Reyesef017552010-10-06 17:57:52 -0700568 GenVertex(&expected_graph[7],
569 VectOfExt(120, 50),
570 VectOfExt(60, 40),
571 "",
572 OP_BSDIFF);
573 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10));
574
575 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ);
576 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
577
578 GenVertex(&expected_graph[9],
579 VectOfExt(0, 9),
580 VectOfExt(60, 9),
581 "",
582 OP_MOVE);
583
584 GenVertex(&expected_graph[10],
585 VectOfExt(30, 10),
586 VectOfExt(60, 10),
587 "",
588 OP_MOVE);
589 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
Darin Petkov68c10d12010-10-14 09:24:37 -0700590
Andrew de los Reyesef017552010-10-06 17:57:52 -0700591 EXPECT_EQ(12, graph.size());
592 EXPECT_FALSE(graph.back().valid);
593 for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
594 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
595 if (i == 8) {
596 // special case
597 } else {
598 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i;
599 }
600 }
601}
602
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700603TEST_F(DeltaDiffGeneratorTest, IsNoopOperationTest) {
604 DeltaArchiveManifest_InstallOperation op;
605 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
606 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
607 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
608 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
609 *(op.add_src_extents()) = ExtentForRange(3, 2);
610 *(op.add_dst_extents()) = ExtentForRange(3, 2);
611 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
612 *(op.add_src_extents()) = ExtentForRange(7, 5);
613 *(op.add_dst_extents()) = ExtentForRange(7, 5);
614 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
615 *(op.add_src_extents()) = ExtentForRange(20, 2);
616 *(op.add_dst_extents()) = ExtentForRange(20, 1);
617 *(op.add_dst_extents()) = ExtentForRange(21, 1);
618 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
619 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 2);
620 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 1);
621 *(op.add_dst_extents()) = ExtentForRange(kSparseHole, 3);
622 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
623 *(op.add_src_extents()) = ExtentForRange(24, 1);
624 *(op.add_dst_extents()) = ExtentForRange(25, 1);
625 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
626}
627
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700628TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksReuseTest) {
629 // AssignTempBlocks(Graph* graph,
630 // const string& new_root,
631 // int data_fd,
632 // off_t* data_file_size,
633 // vector<Vertex::Index>* op_indexes,
634 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
635 // const vector<CutEdgeVertexes>& cuts
636 Graph graph(9);
637
638 const vector<Extent> empt;
639 uint64_t tmp = kTempBlockStart;
640 const string kFilename = "/foo";
641
642 vector<CutEdgeVertexes> cuts;
643 cuts.resize(3);
644
645 // Simple broken loop:
646 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE);
647 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE);
648 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE);
649 // Corresponding edges:
650 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
651 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
652 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
653 // Store the cut:
654 cuts[0].old_dst = 1;
655 cuts[0].old_src = 0;
656 cuts[0].new_vertex = 2;
657 cuts[0].tmp_extents = VectOfExt(tmp, 1);
658 tmp++;
659
660 // Slightly more complex pair of loops:
661 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE);
662 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE);
663 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE);
664 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE);
665 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE);
666 // Corresponding edges:
667 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
668 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
669 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
670 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
671 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
672 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
673 // Store the cuts:
674 cuts[1].old_dst = 5;
675 cuts[1].old_src = 3;
676 cuts[1].new_vertex = 6;
677 cuts[1].tmp_extents = VectOfExt(tmp, 2);
678 cuts[2].old_dst = 5;
679 cuts[2].old_src = 4;
680 cuts[2].new_vertex = 7;
681 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
682
683 // Supplier of temp block:
684 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE);
685
686 // Specify the final order:
687 vector<Vertex::Index> op_indexes;
688 op_indexes.push_back(2);
689 op_indexes.push_back(0);
690 op_indexes.push_back(1);
691 op_indexes.push_back(6);
692 op_indexes.push_back(3);
693 op_indexes.push_back(7);
694 op_indexes.push_back(4);
695 op_indexes.push_back(5);
696 op_indexes.push_back(8);
697
698 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
699 DeltaDiffGenerator::GenerateReverseTopoOrderMap(op_indexes,
700 &reverse_op_indexes);
701
702 // Prepare the filesystem with the minimum required for this to work
703 string temp_dir;
704 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksReuseTest.XXXXXX",
705 &temp_dir));
706 ScopedDirRemover temp_dir_remover(temp_dir);
707
708 const size_t kBlockSize = 4096;
709 vector<char> temp_data(kBlockSize * 3);
710 FillWithData(&temp_data);
711 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
712 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
713
714 int fd;
715 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksReuseTest.XXXXXX",
716 NULL,
717 &fd));
718 ScopedFdCloser fd_closer(&fd);
719 off_t data_file_size = 0;
Thieu Le5c7d9752010-12-15 16:09:28 -0800720
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700721 EXPECT_TRUE(DeltaDiffGenerator::AssignTempBlocks(&graph,
722 temp_dir,
723 fd,
724 &data_file_size,
725 &op_indexes,
726 &reverse_op_indexes,
727 cuts));
728 EXPECT_FALSE(graph[6].valid);
729 EXPECT_FALSE(graph[7].valid);
730 EXPECT_EQ(1, graph[1].op.src_extents_size());
731 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block());
732 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks());
733 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type());
734}
735
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800736TEST_F(DeltaDiffGeneratorTest, CreateScratchNodeTest) {
737 Vertex vertex;
738 DeltaDiffGenerator::CreateScratchNode(12, 34, &vertex);
739 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ,
740 vertex.op.type());
741 EXPECT_EQ(0, vertex.op.data_offset());
742 EXPECT_EQ(0, vertex.op.data_length());
743 EXPECT_EQ(1, vertex.op.dst_extents_size());
744 EXPECT_EQ(12, vertex.op.dst_extents(0).start_block());
745 EXPECT_EQ(34, vertex.op.dst_extents(0).num_blocks());
746}
747
adlr@google.com3defe6a2009-12-04 20:57:17 +0000748} // namespace chromeos_update_engine