blob: 632b8e7dc47eb4c9064a493a7a2a85c975f53202 [file] [log] [blame]
Don Garrettf4b28742012-03-27 20:48:06 -07001// Copyright (c) 2012 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(),
Don Garrettf4b28742012-03-27 20:48:06 -070073 std::set<string>(),
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070074 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -070075 &op,
76 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070077 EXPECT_TRUE(data.empty());
78
79 EXPECT_TRUE(op.has_type());
80 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
81 EXPECT_FALSE(op.has_data_offset());
82 EXPECT_FALSE(op.has_data_length());
83 EXPECT_EQ(1, op.src_extents_size());
84 EXPECT_EQ(sizeof(kRandomString), op.src_length());
85 EXPECT_EQ(1, op.dst_extents_size());
86 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
87 EXPECT_EQ(BlocksInExtents(op.src_extents()),
88 BlocksInExtents(op.dst_extents()));
89 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
90}
91
92TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffSmallTest) {
93 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
94 reinterpret_cast<const char*>(kRandomString),
95 sizeof(kRandomString) - 1));
96 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
97 reinterpret_cast<const char*>(kRandomString),
98 sizeof(kRandomString)));
99 vector<char> data;
100 DeltaArchiveManifest_InstallOperation op;
101 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
102 new_path(),
Don Garrettf4b28742012-03-27 20:48:06 -0700103 std::set<string>(),
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700104 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700105 &op,
106 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700107 EXPECT_FALSE(data.empty());
108
109 EXPECT_TRUE(op.has_type());
110 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
111 EXPECT_FALSE(op.has_data_offset());
112 EXPECT_FALSE(op.has_data_length());
113 EXPECT_EQ(1, op.src_extents_size());
114 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
115 EXPECT_EQ(1, op.dst_extents_size());
116 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
117 EXPECT_EQ(BlocksInExtents(op.src_extents()),
118 BlocksInExtents(op.dst_extents()));
119 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
120}
121
Don Garrettf4b28742012-03-27 20:48:06 -0700122TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffBlacklistNoMatchTest) {
123 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
124 reinterpret_cast<const char*>(kRandomString),
125 sizeof(kRandomString) - 1));
126 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
127 reinterpret_cast<const char*>(kRandomString),
128 sizeof(kRandomString)));
129 vector<char> data;
130 DeltaArchiveManifest_InstallOperation op;
131
132 std::set<string> bsdiff_blacklist;
133 bsdiff_blacklist.insert("fuzzy_bunny"); // Not the new_path
134
135 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
136 new_path(),
137 bsdiff_blacklist,
138 &data,
139 &op,
140 true));
141 EXPECT_FALSE(data.empty());
142
143 EXPECT_TRUE(op.has_type());
144 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
145 EXPECT_FALSE(op.has_data_offset());
146 EXPECT_FALSE(op.has_data_length());
147 EXPECT_EQ(1, op.src_extents_size());
148 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
149 EXPECT_EQ(1, op.dst_extents_size());
150 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
151 EXPECT_EQ(BlocksInExtents(op.src_extents()),
152 BlocksInExtents(op.dst_extents()));
153 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
154}
155
156
157TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffBlacklistMatchTest) {
158 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
159 reinterpret_cast<const char*>(kRandomString),
160 sizeof(kRandomString) - 1));
161 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
162 reinterpret_cast<const char*>(kRandomString),
163 sizeof(kRandomString)));
164 vector<char> data;
165 DeltaArchiveManifest_InstallOperation op;
166
167 std::set<string> bsdiff_blacklist;
168 bsdiff_blacklist.insert("fuzzy_bunny");
169 bsdiff_blacklist.insert(old_path());
170
171 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
172 new_path(),
173 bsdiff_blacklist,
174 &data,
175 &op,
176 true));
177 EXPECT_FALSE(data.empty());
178
179 // The point of this test is that we don't use BSDIFF the way the above
180 // did. The rest of the details are to be caught in other tests.
181 EXPECT_TRUE(op.has_type());
182 EXPECT_NE(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
183}
184
185TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffBlacklistMoveMatchTest) {
186 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
187 reinterpret_cast<const char*>(kRandomString),
188 sizeof(kRandomString)));
189 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
190 reinterpret_cast<const char*>(kRandomString),
191 sizeof(kRandomString)));
192 vector<char> data;
193 DeltaArchiveManifest_InstallOperation op;
194
195 std::set<string> bsdiff_blacklist;
196 bsdiff_blacklist.insert("fuzzy_bunny");
197 bsdiff_blacklist.insert(old_path());
198
199 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
200 new_path(),
201 bsdiff_blacklist,
202 &data,
203 &op,
204 true));
205 EXPECT_TRUE(data.empty());
206
207 // The point of this test is that we can still use a MOVE for a file
208 // that is blacklisted.
209 EXPECT_TRUE(op.has_type());
210 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
211}
212
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700213TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) {
214 vector<char> new_data;
215 for (int i = 0; i < 2; i++) {
216 new_data.insert(new_data.end(),
217 kRandomString,
218 kRandomString + sizeof(kRandomString));
219 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
220 &new_data[0],
221 new_data.size()));
222 vector<char> data;
223 DeltaArchiveManifest_InstallOperation op;
224 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
225 new_path(),
Don Garrettf4b28742012-03-27 20:48:06 -0700226 std::set<string>(),
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700227 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700228 &op,
229 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700230 EXPECT_FALSE(data.empty());
231
232 EXPECT_TRUE(op.has_type());
233 const DeltaArchiveManifest_InstallOperation_Type expected_type =
234 (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE :
235 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
236 EXPECT_EQ(expected_type, op.type());
237 EXPECT_FALSE(op.has_data_offset());
238 EXPECT_FALSE(op.has_data_length());
239 EXPECT_EQ(0, op.src_extents_size());
240 EXPECT_FALSE(op.has_src_length());
241 EXPECT_EQ(1, op.dst_extents_size());
242 EXPECT_EQ(new_data.size(), op.dst_length());
243 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
244 }
245}
246
Darin Petkov68c10d12010-10-14 09:24:37 -0700247TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNoGatherExtentsSmallTest) {
248 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
249 reinterpret_cast<const char*>(kRandomString),
250 sizeof(kRandomString) - 1));
251 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
252 reinterpret_cast<const char*>(kRandomString),
253 sizeof(kRandomString)));
254 vector<char> data;
255 DeltaArchiveManifest_InstallOperation op;
256 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
257 new_path(),
Don Garrettf4b28742012-03-27 20:48:06 -0700258 std::set<string>(),
Darin Petkov68c10d12010-10-14 09:24:37 -0700259 &data,
260 &op,
261 false));
262 EXPECT_FALSE(data.empty());
263
264 EXPECT_TRUE(op.has_type());
265 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
266 EXPECT_FALSE(op.has_data_offset());
267 EXPECT_FALSE(op.has_data_length());
268 EXPECT_EQ(1, op.src_extents_size());
269 EXPECT_EQ(0, op.src_extents().Get(0).start_block());
270 EXPECT_EQ(1, op.src_extents().Get(0).num_blocks());
271 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
272 EXPECT_EQ(1, op.dst_extents_size());
273 EXPECT_EQ(0, op.dst_extents().Get(0).start_block());
274 EXPECT_EQ(1, op.dst_extents().Get(0).num_blocks());
275 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
276}
277
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700278namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700279void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700280 vect->resize(vect->size() + 1);
281 vect->back().set_start_block(start);
282 vect->back().set_num_blocks(length);
283}
284void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700285 uint64_t start,
286 uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700287 Extent* extent = op->add_src_extents();
288 extent->set_start_block(start);
289 extent->set_num_blocks(length);
290}
291}
292
293TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
294 vector<Extent> remove_blocks;
295 AppendExtent(&remove_blocks, 3, 3);
296 AppendExtent(&remove_blocks, 7, 1);
297 vector<Extent> replace_blocks;
298 AppendExtent(&replace_blocks, 10, 2);
299 AppendExtent(&replace_blocks, 13, 2);
Andrew de los Reyesef017552010-10-06 17:57:52 -0700300 Vertex vertex;
301 DeltaArchiveManifest_InstallOperation& op = vertex.op;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700302 OpAppendExtent(&op, 4, 3);
303 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
304 OpAppendExtent(&op, 3, 1);
305 OpAppendExtent(&op, 7, 3);
Darin Petkov68c10d12010-10-14 09:24:37 -0700306
Andrew de los Reyesef017552010-10-06 17:57:52 -0700307 DeltaDiffGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700308
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700309 EXPECT_EQ(7, op.src_extents_size());
310 EXPECT_EQ(11, op.src_extents(0).start_block());
311 EXPECT_EQ(1, op.src_extents(0).num_blocks());
312 EXPECT_EQ(13, op.src_extents(1).start_block());
313 EXPECT_EQ(1, op.src_extents(1).num_blocks());
314 EXPECT_EQ(6, op.src_extents(2).start_block());
315 EXPECT_EQ(1, op.src_extents(2).num_blocks());
316 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
317 EXPECT_EQ(4, op.src_extents(3).num_blocks());
318 EXPECT_EQ(10, op.src_extents(4).start_block());
319 EXPECT_EQ(1, op.src_extents(4).num_blocks());
320 EXPECT_EQ(14, op.src_extents(5).start_block());
321 EXPECT_EQ(1, op.src_extents(5).num_blocks());
322 EXPECT_EQ(8, op.src_extents(6).start_block());
323 EXPECT_EQ(2, op.src_extents(6).num_blocks());
324}
325
326TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) {
327 Graph graph;
328 vector<Block> blocks(9);
Darin Petkov68c10d12010-10-14 09:24:37 -0700329
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700330 // Create nodes in graph
331 {
332 graph.resize(graph.size() + 1);
333 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
334 // Reads from blocks 3, 5, 7
335 vector<Extent> extents;
336 graph_utils::AppendBlockToExtents(&extents, 3);
337 graph_utils::AppendBlockToExtents(&extents, 5);
338 graph_utils::AppendBlockToExtents(&extents, 7);
339 DeltaDiffGenerator::StoreExtents(extents,
340 graph.back().op.mutable_src_extents());
341 blocks[3].reader = graph.size() - 1;
342 blocks[5].reader = graph.size() - 1;
343 blocks[7].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700344
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700345 // Writes to blocks 1, 2, 4
346 extents.clear();
347 graph_utils::AppendBlockToExtents(&extents, 1);
348 graph_utils::AppendBlockToExtents(&extents, 2);
349 graph_utils::AppendBlockToExtents(&extents, 4);
350 DeltaDiffGenerator::StoreExtents(extents,
351 graph.back().op.mutable_dst_extents());
352 blocks[1].writer = graph.size() - 1;
353 blocks[2].writer = graph.size() - 1;
354 blocks[4].writer = graph.size() - 1;
355 }
356 {
357 graph.resize(graph.size() + 1);
358 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
359 // Reads from blocks 1, 2, 4
360 vector<Extent> extents;
361 graph_utils::AppendBlockToExtents(&extents, 1);
362 graph_utils::AppendBlockToExtents(&extents, 2);
363 graph_utils::AppendBlockToExtents(&extents, 4);
364 DeltaDiffGenerator::StoreExtents(extents,
365 graph.back().op.mutable_src_extents());
366 blocks[1].reader = graph.size() - 1;
367 blocks[2].reader = graph.size() - 1;
368 blocks[4].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700369
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700370 // Writes to blocks 3, 5, 6
371 extents.clear();
372 graph_utils::AppendBlockToExtents(&extents, 3);
373 graph_utils::AppendBlockToExtents(&extents, 5);
374 graph_utils::AppendBlockToExtents(&extents, 6);
375 DeltaDiffGenerator::StoreExtents(extents,
376 graph.back().op.mutable_dst_extents());
377 blocks[3].writer = graph.size() - 1;
378 blocks[5].writer = graph.size() - 1;
379 blocks[6].writer = graph.size() - 1;
380 }
Darin Petkov68c10d12010-10-14 09:24:37 -0700381
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700382 // Create edges
383 DeltaDiffGenerator::CreateEdges(&graph, blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700384
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700385 // Find cycles
386 CycleBreaker cycle_breaker;
387 set<Edge> cut_edges;
388 cycle_breaker.BreakCycles(graph, &cut_edges);
389
390 EXPECT_EQ(1, cut_edges.size());
391 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
392 0)));
393
Andrew de los Reyesef017552010-10-06 17:57:52 -0700394 vector<CutEdgeVertexes> cuts;
395 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts));
Darin Petkov68c10d12010-10-14 09:24:37 -0700396
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700397 EXPECT_EQ(3, graph.size());
Darin Petkov68c10d12010-10-14 09:24:37 -0700398
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700399 // Check new node in graph:
400 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
401 graph.back().op.type());
402 EXPECT_EQ(2, graph.back().op.src_extents_size());
Andrew de los Reyesef017552010-10-06 17:57:52 -0700403 EXPECT_EQ(1, graph.back().op.dst_extents_size());
404 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block());
405 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700406 EXPECT_TRUE(graph.back().out_edges.empty());
Darin Petkov68c10d12010-10-14 09:24:37 -0700407
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700408 // Check that old node reads from new blocks
Andrew de los Reyesef017552010-10-06 17:57:52 -0700409 EXPECT_EQ(2, graph[0].op.src_extents_size());
410 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block());
411 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks());
412 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700413 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700414
415 // And that the old dst extents haven't changed
416 EXPECT_EQ(2, graph[0].op.dst_extents_size());
417 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block());
418 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks());
419 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block());
420 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks());
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700421
422 // Ensure it only depends on the next node and the new temp node
423 EXPECT_EQ(2, graph[0].out_edges.size());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700424 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700425 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
426 1));
427
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700428 // Check second node has unchanged extents
429 EXPECT_EQ(2, graph[1].op.src_extents_size());
430 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block());
431 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks());
432 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block());
433 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks());
434
435 EXPECT_EQ(2, graph[1].op.dst_extents_size());
436 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block());
437 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks());
438 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block());
439 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks());
Darin Petkov68c10d12010-10-14 09:24:37 -0700440
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700441 // Ensure it only depends on the next node
442 EXPECT_EQ(1, graph[1].out_edges.size());
443 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
444}
445
446TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) {
447 string orig_blobs;
448 EXPECT_TRUE(
449 utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL));
450
451 string orig_data = "abcd";
452 EXPECT_TRUE(
453 utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
454
455 string new_blobs;
456 EXPECT_TRUE(
457 utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL));
Darin Petkov68c10d12010-10-14 09:24:37 -0700458
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700459 DeltaArchiveManifest manifest;
460 DeltaArchiveManifest_InstallOperation* op =
461 manifest.add_install_operations();
462 op->set_data_offset(1);
463 op->set_data_length(3);
464 op = manifest.add_install_operations();
465 op->set_data_offset(0);
466 op->set_data_length(1);
Darin Petkov68c10d12010-10-14 09:24:37 -0700467
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700468 EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest,
469 orig_blobs,
470 new_blobs));
Darin Petkov68c10d12010-10-14 09:24:37 -0700471
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700472 string new_data;
473 EXPECT_TRUE(utils::ReadFileToString(new_blobs, &new_data));
474 EXPECT_EQ("bcda", new_data);
475 EXPECT_EQ(2, manifest.install_operations_size());
476 EXPECT_EQ(0, manifest.install_operations(0).data_offset());
477 EXPECT_EQ(3, manifest.install_operations(0).data_length());
478 EXPECT_EQ(3, manifest.install_operations(1).data_offset());
479 EXPECT_EQ(1, manifest.install_operations(1).data_length());
Darin Petkov68c10d12010-10-14 09:24:37 -0700480
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700481 unlink(orig_blobs.c_str());
482 unlink(new_blobs.c_str());
483}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000484
Andrew de los Reyesef017552010-10-06 17:57:52 -0700485TEST_F(DeltaDiffGeneratorTest, MoveFullOpsToBackTest) {
486 Graph graph(4);
487 graph[0].file_name = "A";
488 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
489 graph[1].file_name = "B";
490 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
491 graph[2].file_name = "C";
492 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
493 graph[3].file_name = "D";
494 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
495
496 vector<Vertex::Index> vect(graph.size());
497
498 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) {
499 vect[i] = i;
500 }
501 DeltaDiffGenerator::MoveFullOpsToBack(&graph, &vect);
502 EXPECT_EQ(vect.size(), graph.size());
503 EXPECT_EQ(graph[vect[0]].file_name, "B");
504 EXPECT_EQ(graph[vect[1]].file_name, "D");
505 EXPECT_EQ(graph[vect[2]].file_name, "A");
506 EXPECT_EQ(graph[vect[3]].file_name, "C");
507}
508
509namespace {
510
511#define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF
512#define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE
513#define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE
514#define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ
515
516void GenVertex(Vertex* out,
517 const vector<Extent>& src_extents,
518 const vector<Extent>& dst_extents,
519 const string& path,
520 DeltaArchiveManifest_InstallOperation_Type type) {
521 out->op.set_type(type);
522 out->file_name = path;
523 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents());
524 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents());
525}
526
527vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) {
528 return vector<Extent>(1, ExtentForRange(start_block, num_blocks));
529}
530
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700531vector<Extent> VectOfExts(uint64_t start_block1, uint64_t num_blocks1,
532 uint64_t start_block2, uint64_t num_blocks2) {
533 vector<Extent> ret(1, ExtentForRange(start_block1, num_blocks1));
534 ret.push_back(ExtentForRange(start_block2, num_blocks2));
535 return ret;
536}
537
Andrew de los Reyesef017552010-10-06 17:57:52 -0700538EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) {
539 EdgeProperties ret;
540 ret.extents = extents;
541 return ret;
542}
543
544EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) {
545 EdgeProperties ret;
546 ret.write_extents = extents;
547 return ret;
548}
549
550template<typename T>
551void DumpVect(const vector<T>& vect) {
552 std::stringstream ss(stringstream::out);
553 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end();
554 it != e; ++it) {
555 ss << *it << ", ";
556 }
557 LOG(INFO) << "{" << ss.str() << "}";
558}
559
560} // namespace {}
561
562TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksTest) {
563 Graph graph(9);
564 const vector<Extent> empt; // empty
565 const string kFilename = "/foo";
Darin Petkov68c10d12010-10-14 09:24:37 -0700566
Andrew de los Reyesef017552010-10-06 17:57:52 -0700567 // Some scratch space:
568 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
569 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
570 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
571
572 // A cycle that requires 10 blocks to break:
573 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF);
574 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9));
575 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF);
576 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
577
578 // A cycle that requires 9 blocks to break:
579 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF);
580 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10));
581 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF);
582 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
583
584 // A cycle that requires 40 blocks to break (which is too many):
585 GenVertex(&graph[7],
586 VectOfExt(120, 50),
587 VectOfExt(60, 40),
588 "",
589 OP_BSDIFF);
590 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40));
591 GenVertex(&graph[8],
592 VectOfExt(60, 40),
593 VectOfExt(120, 50),
594 kFilename,
595 OP_BSDIFF);
596 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
Darin Petkov68c10d12010-10-14 09:24:37 -0700597
Andrew de los Reyesef017552010-10-06 17:57:52 -0700598 graph_utils::DumpGraph(graph);
Darin Petkov68c10d12010-10-14 09:24:37 -0700599
Andrew de los Reyesef017552010-10-06 17:57:52 -0700600 vector<Vertex::Index> final_order;
601
602
603 // Prepare the filesystem with the minimum required for this to work
604 string temp_dir;
605 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksTest.XXXXXX",
606 &temp_dir));
607 ScopedDirRemover temp_dir_remover(temp_dir);
Darin Petkov68c10d12010-10-14 09:24:37 -0700608
Andrew de los Reyesef017552010-10-06 17:57:52 -0700609 const size_t kBlockSize = 4096;
610 vector<char> temp_data(kBlockSize * 50);
611 FillWithData(&temp_data);
612 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
613 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
Darin Petkov68c10d12010-10-14 09:24:37 -0700614
Andrew de los Reyesef017552010-10-06 17:57:52 -0700615 int fd;
616 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksTestData.XXXXXX",
617 NULL,
618 &fd));
619 ScopedFdCloser fd_closer(&fd);
620 off_t data_file_size = 0;
621
622
623 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
624 temp_dir,
625 fd,
626 &data_file_size,
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800627 &final_order,
628 Vertex::kInvalidIndex));
Andrew de los Reyesef017552010-10-06 17:57:52 -0700629
Darin Petkov68c10d12010-10-14 09:24:37 -0700630
Andrew de los Reyesef017552010-10-06 17:57:52 -0700631 Graph expected_graph(12);
632 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
633 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
634 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
635 GenVertex(&expected_graph[3],
636 VectOfExt(10, 11),
637 VectOfExt(0, 9),
638 "",
639 OP_BSDIFF);
640 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9));
641 GenVertex(&expected_graph[4],
642 VectOfExt(60, 9),
643 VectOfExt(10, 11),
644 "",
645 OP_BSDIFF);
646 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
647 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9));
648 GenVertex(&expected_graph[5],
649 VectOfExt(40, 11),
650 VectOfExt(30, 10),
651 "",
652 OP_BSDIFF);
653 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10));
654
655 GenVertex(&expected_graph[6],
656 VectOfExt(60, 10),
657 VectOfExt(40, 11),
658 "",
659 OP_BSDIFF);
660 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
661 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10));
Darin Petkov68c10d12010-10-14 09:24:37 -0700662
Andrew de los Reyesef017552010-10-06 17:57:52 -0700663 GenVertex(&expected_graph[7],
664 VectOfExt(120, 50),
665 VectOfExt(60, 40),
666 "",
667 OP_BSDIFF);
668 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10));
669
670 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ);
671 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
672
673 GenVertex(&expected_graph[9],
674 VectOfExt(0, 9),
675 VectOfExt(60, 9),
676 "",
677 OP_MOVE);
678
679 GenVertex(&expected_graph[10],
680 VectOfExt(30, 10),
681 VectOfExt(60, 10),
682 "",
683 OP_MOVE);
684 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
Darin Petkov68c10d12010-10-14 09:24:37 -0700685
Andrew de los Reyesef017552010-10-06 17:57:52 -0700686 EXPECT_EQ(12, graph.size());
687 EXPECT_FALSE(graph.back().valid);
688 for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
689 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
690 if (i == 8) {
691 // special case
692 } else {
693 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i;
694 }
695 }
696}
697
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700698TEST_F(DeltaDiffGeneratorTest, IsNoopOperationTest) {
699 DeltaArchiveManifest_InstallOperation op;
700 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
701 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
702 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
703 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
704 *(op.add_src_extents()) = ExtentForRange(3, 2);
705 *(op.add_dst_extents()) = ExtentForRange(3, 2);
706 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
707 *(op.add_src_extents()) = ExtentForRange(7, 5);
708 *(op.add_dst_extents()) = ExtentForRange(7, 5);
709 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
710 *(op.add_src_extents()) = ExtentForRange(20, 2);
711 *(op.add_dst_extents()) = ExtentForRange(20, 1);
712 *(op.add_dst_extents()) = ExtentForRange(21, 1);
713 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
714 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 2);
715 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 1);
716 *(op.add_dst_extents()) = ExtentForRange(kSparseHole, 3);
717 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
718 *(op.add_src_extents()) = ExtentForRange(24, 1);
719 *(op.add_dst_extents()) = ExtentForRange(25, 1);
720 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
721}
722
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700723TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksReuseTest) {
724 // AssignTempBlocks(Graph* graph,
725 // const string& new_root,
726 // int data_fd,
727 // off_t* data_file_size,
728 // vector<Vertex::Index>* op_indexes,
729 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
730 // const vector<CutEdgeVertexes>& cuts
731 Graph graph(9);
732
733 const vector<Extent> empt;
734 uint64_t tmp = kTempBlockStart;
735 const string kFilename = "/foo";
736
737 vector<CutEdgeVertexes> cuts;
738 cuts.resize(3);
739
740 // Simple broken loop:
741 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE);
742 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE);
743 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE);
744 // Corresponding edges:
745 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
746 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
747 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
748 // Store the cut:
749 cuts[0].old_dst = 1;
750 cuts[0].old_src = 0;
751 cuts[0].new_vertex = 2;
752 cuts[0].tmp_extents = VectOfExt(tmp, 1);
753 tmp++;
754
755 // Slightly more complex pair of loops:
756 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE);
757 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE);
758 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE);
759 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE);
760 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE);
761 // Corresponding edges:
762 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
763 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
764 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
765 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
766 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
767 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
768 // Store the cuts:
769 cuts[1].old_dst = 5;
770 cuts[1].old_src = 3;
771 cuts[1].new_vertex = 6;
772 cuts[1].tmp_extents = VectOfExt(tmp, 2);
773 cuts[2].old_dst = 5;
774 cuts[2].old_src = 4;
775 cuts[2].new_vertex = 7;
776 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
777
778 // Supplier of temp block:
779 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE);
780
781 // Specify the final order:
782 vector<Vertex::Index> op_indexes;
783 op_indexes.push_back(2);
784 op_indexes.push_back(0);
785 op_indexes.push_back(1);
786 op_indexes.push_back(6);
787 op_indexes.push_back(3);
788 op_indexes.push_back(7);
789 op_indexes.push_back(4);
790 op_indexes.push_back(5);
791 op_indexes.push_back(8);
792
793 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
794 DeltaDiffGenerator::GenerateReverseTopoOrderMap(op_indexes,
795 &reverse_op_indexes);
796
797 // Prepare the filesystem with the minimum required for this to work
798 string temp_dir;
799 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksReuseTest.XXXXXX",
800 &temp_dir));
801 ScopedDirRemover temp_dir_remover(temp_dir);
802
803 const size_t kBlockSize = 4096;
804 vector<char> temp_data(kBlockSize * 3);
805 FillWithData(&temp_data);
806 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
807 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
808
809 int fd;
810 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksReuseTest.XXXXXX",
811 NULL,
812 &fd));
813 ScopedFdCloser fd_closer(&fd);
814 off_t data_file_size = 0;
Thieu Le5c7d9752010-12-15 16:09:28 -0800815
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700816 EXPECT_TRUE(DeltaDiffGenerator::AssignTempBlocks(&graph,
817 temp_dir,
818 fd,
819 &data_file_size,
820 &op_indexes,
821 &reverse_op_indexes,
822 cuts));
823 EXPECT_FALSE(graph[6].valid);
824 EXPECT_FALSE(graph[7].valid);
825 EXPECT_EQ(1, graph[1].op.src_extents_size());
826 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block());
827 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks());
828 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type());
829}
830
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800831TEST_F(DeltaDiffGeneratorTest, CreateScratchNodeTest) {
832 Vertex vertex;
833 DeltaDiffGenerator::CreateScratchNode(12, 34, &vertex);
834 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ,
835 vertex.op.type());
836 EXPECT_EQ(0, vertex.op.data_offset());
837 EXPECT_EQ(0, vertex.op.data_length());
838 EXPECT_EQ(1, vertex.op.dst_extents_size());
839 EXPECT_EQ(12, vertex.op.dst_extents(0).start_block());
840 EXPECT_EQ(34, vertex.op.dst_extents(0).num_blocks());
841}
842
adlr@google.com3defe6a2009-12-04 20:57:17 +0000843} // namespace chromeos_update_engine