blob: 6d989a1b6715a5ee0c652971ae285a5a5692ea53 [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 Garrett36e60772012-03-29 10:31:20 -070073 true, // bsdiff_allowed
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 Garrett36e60772012-03-29 10:31:20 -0700103 true, // bsdiff_allowed
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 Garrett36e60772012-03-29 10:31:20 -0700122TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNotAllowedTest) {
Don Garrettf4b28742012-03-27 20:48:06 -0700123 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
Don Garrettf4b28742012-03-27 20:48:06 -0700132 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
133 new_path(),
Don Garrett36e60772012-03-29 10:31:20 -0700134 false, // bsdiff_allowed
Don Garrettf4b28742012-03-27 20:48:06 -0700135 &data,
136 &op,
137 true));
138 EXPECT_FALSE(data.empty());
139
140 // The point of this test is that we don't use BSDIFF the way the above
141 // did. The rest of the details are to be caught in other tests.
142 EXPECT_TRUE(op.has_type());
143 EXPECT_NE(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
144}
145
Don Garrett36e60772012-03-29 10:31:20 -0700146TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNotAllowedMoveTest) {
Don Garrettf4b28742012-03-27 20:48:06 -0700147 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
148 reinterpret_cast<const char*>(kRandomString),
149 sizeof(kRandomString)));
150 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
151 reinterpret_cast<const char*>(kRandomString),
152 sizeof(kRandomString)));
153 vector<char> data;
154 DeltaArchiveManifest_InstallOperation op;
155
Don Garrettf4b28742012-03-27 20:48:06 -0700156 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
157 new_path(),
Don Garrett36e60772012-03-29 10:31:20 -0700158 false, // bsdiff_allowed
Don Garrettf4b28742012-03-27 20:48:06 -0700159 &data,
160 &op,
161 true));
162 EXPECT_TRUE(data.empty());
163
164 // The point of this test is that we can still use a MOVE for a file
165 // that is blacklisted.
166 EXPECT_TRUE(op.has_type());
167 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
168}
169
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700170TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) {
171 vector<char> new_data;
172 for (int i = 0; i < 2; i++) {
173 new_data.insert(new_data.end(),
174 kRandomString,
175 kRandomString + sizeof(kRandomString));
176 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
177 &new_data[0],
178 new_data.size()));
179 vector<char> data;
180 DeltaArchiveManifest_InstallOperation op;
181 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
182 new_path(),
Don Garrett36e60772012-03-29 10:31:20 -0700183 true, // bsdiff_allowed
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700184 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700185 &op,
186 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700187 EXPECT_FALSE(data.empty());
188
189 EXPECT_TRUE(op.has_type());
190 const DeltaArchiveManifest_InstallOperation_Type expected_type =
191 (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE :
192 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
193 EXPECT_EQ(expected_type, op.type());
194 EXPECT_FALSE(op.has_data_offset());
195 EXPECT_FALSE(op.has_data_length());
196 EXPECT_EQ(0, op.src_extents_size());
197 EXPECT_FALSE(op.has_src_length());
198 EXPECT_EQ(1, op.dst_extents_size());
199 EXPECT_EQ(new_data.size(), op.dst_length());
200 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
201 }
202}
203
Darin Petkov68c10d12010-10-14 09:24:37 -0700204TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNoGatherExtentsSmallTest) {
205 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
206 reinterpret_cast<const char*>(kRandomString),
207 sizeof(kRandomString) - 1));
208 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
209 reinterpret_cast<const char*>(kRandomString),
210 sizeof(kRandomString)));
211 vector<char> data;
212 DeltaArchiveManifest_InstallOperation op;
213 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
214 new_path(),
Don Garrett36e60772012-03-29 10:31:20 -0700215 true, // bsdiff_allowed
Darin Petkov68c10d12010-10-14 09:24:37 -0700216 &data,
217 &op,
218 false));
219 EXPECT_FALSE(data.empty());
220
221 EXPECT_TRUE(op.has_type());
222 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
223 EXPECT_FALSE(op.has_data_offset());
224 EXPECT_FALSE(op.has_data_length());
225 EXPECT_EQ(1, op.src_extents_size());
226 EXPECT_EQ(0, op.src_extents().Get(0).start_block());
227 EXPECT_EQ(1, op.src_extents().Get(0).num_blocks());
228 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
229 EXPECT_EQ(1, op.dst_extents_size());
230 EXPECT_EQ(0, op.dst_extents().Get(0).start_block());
231 EXPECT_EQ(1, op.dst_extents().Get(0).num_blocks());
232 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
233}
234
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700235namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700236void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700237 vect->resize(vect->size() + 1);
238 vect->back().set_start_block(start);
239 vect->back().set_num_blocks(length);
240}
241void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700242 uint64_t start,
243 uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700244 Extent* extent = op->add_src_extents();
245 extent->set_start_block(start);
246 extent->set_num_blocks(length);
247}
248}
249
250TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
251 vector<Extent> remove_blocks;
252 AppendExtent(&remove_blocks, 3, 3);
253 AppendExtent(&remove_blocks, 7, 1);
254 vector<Extent> replace_blocks;
255 AppendExtent(&replace_blocks, 10, 2);
256 AppendExtent(&replace_blocks, 13, 2);
Andrew de los Reyesef017552010-10-06 17:57:52 -0700257 Vertex vertex;
258 DeltaArchiveManifest_InstallOperation& op = vertex.op;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700259 OpAppendExtent(&op, 4, 3);
260 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
261 OpAppendExtent(&op, 3, 1);
262 OpAppendExtent(&op, 7, 3);
Darin Petkov68c10d12010-10-14 09:24:37 -0700263
Andrew de los Reyesef017552010-10-06 17:57:52 -0700264 DeltaDiffGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700265
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700266 EXPECT_EQ(7, op.src_extents_size());
267 EXPECT_EQ(11, op.src_extents(0).start_block());
268 EXPECT_EQ(1, op.src_extents(0).num_blocks());
269 EXPECT_EQ(13, op.src_extents(1).start_block());
270 EXPECT_EQ(1, op.src_extents(1).num_blocks());
271 EXPECT_EQ(6, op.src_extents(2).start_block());
272 EXPECT_EQ(1, op.src_extents(2).num_blocks());
273 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
274 EXPECT_EQ(4, op.src_extents(3).num_blocks());
275 EXPECT_EQ(10, op.src_extents(4).start_block());
276 EXPECT_EQ(1, op.src_extents(4).num_blocks());
277 EXPECT_EQ(14, op.src_extents(5).start_block());
278 EXPECT_EQ(1, op.src_extents(5).num_blocks());
279 EXPECT_EQ(8, op.src_extents(6).start_block());
280 EXPECT_EQ(2, op.src_extents(6).num_blocks());
281}
282
283TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) {
284 Graph graph;
285 vector<Block> blocks(9);
Darin Petkov68c10d12010-10-14 09:24:37 -0700286
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700287 // Create nodes in graph
288 {
289 graph.resize(graph.size() + 1);
290 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
291 // Reads from blocks 3, 5, 7
292 vector<Extent> extents;
293 graph_utils::AppendBlockToExtents(&extents, 3);
294 graph_utils::AppendBlockToExtents(&extents, 5);
295 graph_utils::AppendBlockToExtents(&extents, 7);
296 DeltaDiffGenerator::StoreExtents(extents,
297 graph.back().op.mutable_src_extents());
298 blocks[3].reader = graph.size() - 1;
299 blocks[5].reader = graph.size() - 1;
300 blocks[7].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700301
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700302 // Writes to blocks 1, 2, 4
303 extents.clear();
304 graph_utils::AppendBlockToExtents(&extents, 1);
305 graph_utils::AppendBlockToExtents(&extents, 2);
306 graph_utils::AppendBlockToExtents(&extents, 4);
307 DeltaDiffGenerator::StoreExtents(extents,
308 graph.back().op.mutable_dst_extents());
309 blocks[1].writer = graph.size() - 1;
310 blocks[2].writer = graph.size() - 1;
311 blocks[4].writer = graph.size() - 1;
312 }
313 {
314 graph.resize(graph.size() + 1);
315 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
316 // Reads from blocks 1, 2, 4
317 vector<Extent> extents;
318 graph_utils::AppendBlockToExtents(&extents, 1);
319 graph_utils::AppendBlockToExtents(&extents, 2);
320 graph_utils::AppendBlockToExtents(&extents, 4);
321 DeltaDiffGenerator::StoreExtents(extents,
322 graph.back().op.mutable_src_extents());
323 blocks[1].reader = graph.size() - 1;
324 blocks[2].reader = graph.size() - 1;
325 blocks[4].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700326
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700327 // Writes to blocks 3, 5, 6
328 extents.clear();
329 graph_utils::AppendBlockToExtents(&extents, 3);
330 graph_utils::AppendBlockToExtents(&extents, 5);
331 graph_utils::AppendBlockToExtents(&extents, 6);
332 DeltaDiffGenerator::StoreExtents(extents,
333 graph.back().op.mutable_dst_extents());
334 blocks[3].writer = graph.size() - 1;
335 blocks[5].writer = graph.size() - 1;
336 blocks[6].writer = graph.size() - 1;
337 }
Darin Petkov68c10d12010-10-14 09:24:37 -0700338
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700339 // Create edges
340 DeltaDiffGenerator::CreateEdges(&graph, blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700341
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700342 // Find cycles
343 CycleBreaker cycle_breaker;
344 set<Edge> cut_edges;
345 cycle_breaker.BreakCycles(graph, &cut_edges);
346
347 EXPECT_EQ(1, cut_edges.size());
348 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
349 0)));
350
Andrew de los Reyesef017552010-10-06 17:57:52 -0700351 vector<CutEdgeVertexes> cuts;
352 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts));
Darin Petkov68c10d12010-10-14 09:24:37 -0700353
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700354 EXPECT_EQ(3, graph.size());
Darin Petkov68c10d12010-10-14 09:24:37 -0700355
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700356 // Check new node in graph:
357 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
358 graph.back().op.type());
359 EXPECT_EQ(2, graph.back().op.src_extents_size());
Andrew de los Reyesef017552010-10-06 17:57:52 -0700360 EXPECT_EQ(1, graph.back().op.dst_extents_size());
361 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block());
362 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700363 EXPECT_TRUE(graph.back().out_edges.empty());
Darin Petkov68c10d12010-10-14 09:24:37 -0700364
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700365 // Check that old node reads from new blocks
Andrew de los Reyesef017552010-10-06 17:57:52 -0700366 EXPECT_EQ(2, graph[0].op.src_extents_size());
367 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block());
368 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks());
369 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700370 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700371
372 // And that the old dst extents haven't changed
373 EXPECT_EQ(2, graph[0].op.dst_extents_size());
374 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block());
375 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks());
376 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block());
377 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks());
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700378
379 // Ensure it only depends on the next node and the new temp node
380 EXPECT_EQ(2, graph[0].out_edges.size());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700381 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700382 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
383 1));
384
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700385 // Check second node has unchanged extents
386 EXPECT_EQ(2, graph[1].op.src_extents_size());
387 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block());
388 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks());
389 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block());
390 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks());
391
392 EXPECT_EQ(2, graph[1].op.dst_extents_size());
393 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block());
394 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks());
395 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block());
396 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks());
Darin Petkov68c10d12010-10-14 09:24:37 -0700397
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700398 // Ensure it only depends on the next node
399 EXPECT_EQ(1, graph[1].out_edges.size());
400 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
401}
402
403TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) {
404 string orig_blobs;
405 EXPECT_TRUE(
406 utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL));
407
408 string orig_data = "abcd";
409 EXPECT_TRUE(
410 utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
411
412 string new_blobs;
413 EXPECT_TRUE(
414 utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL));
Darin Petkov68c10d12010-10-14 09:24:37 -0700415
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700416 DeltaArchiveManifest manifest;
417 DeltaArchiveManifest_InstallOperation* op =
418 manifest.add_install_operations();
419 op->set_data_offset(1);
420 op->set_data_length(3);
421 op = manifest.add_install_operations();
422 op->set_data_offset(0);
423 op->set_data_length(1);
Darin Petkov68c10d12010-10-14 09:24:37 -0700424
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700425 EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest,
426 orig_blobs,
427 new_blobs));
Darin Petkov68c10d12010-10-14 09:24:37 -0700428
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700429 string new_data;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700430 EXPECT_TRUE(utils::ReadFile(new_blobs, &new_data));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700431 EXPECT_EQ("bcda", new_data);
432 EXPECT_EQ(2, manifest.install_operations_size());
433 EXPECT_EQ(0, manifest.install_operations(0).data_offset());
434 EXPECT_EQ(3, manifest.install_operations(0).data_length());
435 EXPECT_EQ(3, manifest.install_operations(1).data_offset());
436 EXPECT_EQ(1, manifest.install_operations(1).data_length());
Darin Petkov68c10d12010-10-14 09:24:37 -0700437
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700438 unlink(orig_blobs.c_str());
439 unlink(new_blobs.c_str());
440}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000441
Andrew de los Reyesef017552010-10-06 17:57:52 -0700442TEST_F(DeltaDiffGeneratorTest, MoveFullOpsToBackTest) {
443 Graph graph(4);
444 graph[0].file_name = "A";
445 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
446 graph[1].file_name = "B";
447 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
448 graph[2].file_name = "C";
449 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
450 graph[3].file_name = "D";
451 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
452
453 vector<Vertex::Index> vect(graph.size());
454
455 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) {
456 vect[i] = i;
457 }
458 DeltaDiffGenerator::MoveFullOpsToBack(&graph, &vect);
459 EXPECT_EQ(vect.size(), graph.size());
460 EXPECT_EQ(graph[vect[0]].file_name, "B");
461 EXPECT_EQ(graph[vect[1]].file_name, "D");
462 EXPECT_EQ(graph[vect[2]].file_name, "A");
463 EXPECT_EQ(graph[vect[3]].file_name, "C");
464}
465
466namespace {
467
468#define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF
469#define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE
470#define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE
471#define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ
472
473void GenVertex(Vertex* out,
474 const vector<Extent>& src_extents,
475 const vector<Extent>& dst_extents,
476 const string& path,
477 DeltaArchiveManifest_InstallOperation_Type type) {
478 out->op.set_type(type);
479 out->file_name = path;
480 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents());
481 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents());
482}
483
484vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) {
485 return vector<Extent>(1, ExtentForRange(start_block, num_blocks));
486}
487
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700488vector<Extent> VectOfExts(uint64_t start_block1, uint64_t num_blocks1,
489 uint64_t start_block2, uint64_t num_blocks2) {
490 vector<Extent> ret(1, ExtentForRange(start_block1, num_blocks1));
491 ret.push_back(ExtentForRange(start_block2, num_blocks2));
492 return ret;
493}
494
Andrew de los Reyesef017552010-10-06 17:57:52 -0700495EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) {
496 EdgeProperties ret;
497 ret.extents = extents;
498 return ret;
499}
500
501EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) {
502 EdgeProperties ret;
503 ret.write_extents = extents;
504 return ret;
505}
506
507template<typename T>
508void DumpVect(const vector<T>& vect) {
509 std::stringstream ss(stringstream::out);
510 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end();
511 it != e; ++it) {
512 ss << *it << ", ";
513 }
514 LOG(INFO) << "{" << ss.str() << "}";
515}
516
517} // namespace {}
518
519TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksTest) {
520 Graph graph(9);
521 const vector<Extent> empt; // empty
522 const string kFilename = "/foo";
Darin Petkov68c10d12010-10-14 09:24:37 -0700523
Andrew de los Reyesef017552010-10-06 17:57:52 -0700524 // Some scratch space:
525 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
526 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
527 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
528
529 // A cycle that requires 10 blocks to break:
530 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF);
531 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9));
532 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF);
533 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
534
535 // A cycle that requires 9 blocks to break:
536 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF);
537 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10));
538 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF);
539 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
540
541 // A cycle that requires 40 blocks to break (which is too many):
542 GenVertex(&graph[7],
543 VectOfExt(120, 50),
544 VectOfExt(60, 40),
545 "",
546 OP_BSDIFF);
547 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40));
548 GenVertex(&graph[8],
549 VectOfExt(60, 40),
550 VectOfExt(120, 50),
551 kFilename,
552 OP_BSDIFF);
553 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
Darin Petkov68c10d12010-10-14 09:24:37 -0700554
Andrew de los Reyesef017552010-10-06 17:57:52 -0700555 graph_utils::DumpGraph(graph);
Darin Petkov68c10d12010-10-14 09:24:37 -0700556
Andrew de los Reyesef017552010-10-06 17:57:52 -0700557 vector<Vertex::Index> final_order;
558
559
560 // Prepare the filesystem with the minimum required for this to work
561 string temp_dir;
562 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksTest.XXXXXX",
563 &temp_dir));
564 ScopedDirRemover temp_dir_remover(temp_dir);
Darin Petkov68c10d12010-10-14 09:24:37 -0700565
Andrew de los Reyesef017552010-10-06 17:57:52 -0700566 const size_t kBlockSize = 4096;
567 vector<char> temp_data(kBlockSize * 50);
568 FillWithData(&temp_data);
569 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
570 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
Darin Petkov68c10d12010-10-14 09:24:37 -0700571
Andrew de los Reyesef017552010-10-06 17:57:52 -0700572 int fd;
573 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksTestData.XXXXXX",
574 NULL,
575 &fd));
576 ScopedFdCloser fd_closer(&fd);
577 off_t data_file_size = 0;
578
579
580 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
581 temp_dir,
582 fd,
583 &data_file_size,
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800584 &final_order,
585 Vertex::kInvalidIndex));
Andrew de los Reyesef017552010-10-06 17:57:52 -0700586
Darin Petkov68c10d12010-10-14 09:24:37 -0700587
Andrew de los Reyesef017552010-10-06 17:57:52 -0700588 Graph expected_graph(12);
589 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
590 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
591 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
592 GenVertex(&expected_graph[3],
593 VectOfExt(10, 11),
594 VectOfExt(0, 9),
595 "",
596 OP_BSDIFF);
597 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9));
598 GenVertex(&expected_graph[4],
599 VectOfExt(60, 9),
600 VectOfExt(10, 11),
601 "",
602 OP_BSDIFF);
603 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
604 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9));
605 GenVertex(&expected_graph[5],
606 VectOfExt(40, 11),
607 VectOfExt(30, 10),
608 "",
609 OP_BSDIFF);
610 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10));
611
612 GenVertex(&expected_graph[6],
613 VectOfExt(60, 10),
614 VectOfExt(40, 11),
615 "",
616 OP_BSDIFF);
617 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
618 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10));
Darin Petkov68c10d12010-10-14 09:24:37 -0700619
Andrew de los Reyesef017552010-10-06 17:57:52 -0700620 GenVertex(&expected_graph[7],
621 VectOfExt(120, 50),
622 VectOfExt(60, 40),
623 "",
624 OP_BSDIFF);
625 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10));
626
627 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ);
628 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
629
630 GenVertex(&expected_graph[9],
631 VectOfExt(0, 9),
632 VectOfExt(60, 9),
633 "",
634 OP_MOVE);
635
636 GenVertex(&expected_graph[10],
637 VectOfExt(30, 10),
638 VectOfExt(60, 10),
639 "",
640 OP_MOVE);
641 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
Darin Petkov68c10d12010-10-14 09:24:37 -0700642
Andrew de los Reyesef017552010-10-06 17:57:52 -0700643 EXPECT_EQ(12, graph.size());
644 EXPECT_FALSE(graph.back().valid);
645 for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
646 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
647 if (i == 8) {
648 // special case
649 } else {
650 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i;
651 }
652 }
653}
654
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700655TEST_F(DeltaDiffGeneratorTest, IsNoopOperationTest) {
656 DeltaArchiveManifest_InstallOperation op;
657 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
658 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
659 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
660 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
661 *(op.add_src_extents()) = ExtentForRange(3, 2);
662 *(op.add_dst_extents()) = ExtentForRange(3, 2);
663 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
664 *(op.add_src_extents()) = ExtentForRange(7, 5);
665 *(op.add_dst_extents()) = ExtentForRange(7, 5);
666 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
667 *(op.add_src_extents()) = ExtentForRange(20, 2);
668 *(op.add_dst_extents()) = ExtentForRange(20, 1);
669 *(op.add_dst_extents()) = ExtentForRange(21, 1);
670 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
671 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 2);
672 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 1);
673 *(op.add_dst_extents()) = ExtentForRange(kSparseHole, 3);
674 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
675 *(op.add_src_extents()) = ExtentForRange(24, 1);
676 *(op.add_dst_extents()) = ExtentForRange(25, 1);
677 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
678}
679
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700680TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksReuseTest) {
681 // AssignTempBlocks(Graph* graph,
682 // const string& new_root,
683 // int data_fd,
684 // off_t* data_file_size,
685 // vector<Vertex::Index>* op_indexes,
686 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
687 // const vector<CutEdgeVertexes>& cuts
688 Graph graph(9);
689
690 const vector<Extent> empt;
691 uint64_t tmp = kTempBlockStart;
692 const string kFilename = "/foo";
693
694 vector<CutEdgeVertexes> cuts;
695 cuts.resize(3);
696
697 // Simple broken loop:
698 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE);
699 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE);
700 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE);
701 // Corresponding edges:
702 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
703 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
704 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
705 // Store the cut:
706 cuts[0].old_dst = 1;
707 cuts[0].old_src = 0;
708 cuts[0].new_vertex = 2;
709 cuts[0].tmp_extents = VectOfExt(tmp, 1);
710 tmp++;
711
712 // Slightly more complex pair of loops:
713 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE);
714 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE);
715 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE);
716 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE);
717 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE);
718 // Corresponding edges:
719 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
720 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
721 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
722 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
723 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
724 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
725 // Store the cuts:
726 cuts[1].old_dst = 5;
727 cuts[1].old_src = 3;
728 cuts[1].new_vertex = 6;
729 cuts[1].tmp_extents = VectOfExt(tmp, 2);
730 cuts[2].old_dst = 5;
731 cuts[2].old_src = 4;
732 cuts[2].new_vertex = 7;
733 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
734
735 // Supplier of temp block:
736 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE);
737
738 // Specify the final order:
739 vector<Vertex::Index> op_indexes;
740 op_indexes.push_back(2);
741 op_indexes.push_back(0);
742 op_indexes.push_back(1);
743 op_indexes.push_back(6);
744 op_indexes.push_back(3);
745 op_indexes.push_back(7);
746 op_indexes.push_back(4);
747 op_indexes.push_back(5);
748 op_indexes.push_back(8);
749
750 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
751 DeltaDiffGenerator::GenerateReverseTopoOrderMap(op_indexes,
752 &reverse_op_indexes);
753
754 // Prepare the filesystem with the minimum required for this to work
755 string temp_dir;
756 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksReuseTest.XXXXXX",
757 &temp_dir));
758 ScopedDirRemover temp_dir_remover(temp_dir);
759
760 const size_t kBlockSize = 4096;
761 vector<char> temp_data(kBlockSize * 3);
762 FillWithData(&temp_data);
763 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
764 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
765
766 int fd;
767 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksReuseTest.XXXXXX",
768 NULL,
769 &fd));
770 ScopedFdCloser fd_closer(&fd);
771 off_t data_file_size = 0;
Thieu Le5c7d9752010-12-15 16:09:28 -0800772
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700773 EXPECT_TRUE(DeltaDiffGenerator::AssignTempBlocks(&graph,
774 temp_dir,
775 fd,
776 &data_file_size,
777 &op_indexes,
778 &reverse_op_indexes,
779 cuts));
780 EXPECT_FALSE(graph[6].valid);
781 EXPECT_FALSE(graph[7].valid);
782 EXPECT_EQ(1, graph[1].op.src_extents_size());
783 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block());
784 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks());
785 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type());
786}
787
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800788TEST_F(DeltaDiffGeneratorTest, CreateScratchNodeTest) {
789 Vertex vertex;
790 DeltaDiffGenerator::CreateScratchNode(12, 34, &vertex);
791 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ,
792 vertex.op.type());
793 EXPECT_EQ(0, vertex.op.data_offset());
794 EXPECT_EQ(0, vertex.op.data_length());
795 EXPECT_EQ(1, vertex.op.dst_extents_size());
796 EXPECT_EQ(12, vertex.op.dst_extents(0).start_block());
797 EXPECT_EQ(34, vertex.op.dst_extents(0).num_blocks());
798}
799
adlr@google.com3defe6a2009-12-04 20:57:17 +0000800} // namespace chromeos_update_engine