blob: 7fa28c35580300ad72cc4c7bfdd3630ecfd53136 [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(),
Darin Petkov8e447e02013-04-16 16:23:50 +020073 0, // chunk_offset
74 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -070075 true, // bsdiff_allowed
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070076 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -070077 &op,
78 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070079 EXPECT_TRUE(data.empty());
80
81 EXPECT_TRUE(op.has_type());
82 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
83 EXPECT_FALSE(op.has_data_offset());
84 EXPECT_FALSE(op.has_data_length());
85 EXPECT_EQ(1, op.src_extents_size());
86 EXPECT_EQ(sizeof(kRandomString), op.src_length());
87 EXPECT_EQ(1, op.dst_extents_size());
88 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
89 EXPECT_EQ(BlocksInExtents(op.src_extents()),
90 BlocksInExtents(op.dst_extents()));
91 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
92}
93
94TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffSmallTest) {
95 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
96 reinterpret_cast<const char*>(kRandomString),
97 sizeof(kRandomString) - 1));
98 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
99 reinterpret_cast<const char*>(kRandomString),
100 sizeof(kRandomString)));
101 vector<char> data;
102 DeltaArchiveManifest_InstallOperation op;
103 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
104 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200105 0, // chunk_offset
106 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700107 true, // bsdiff_allowed
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700108 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700109 &op,
110 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700111 EXPECT_FALSE(data.empty());
112
113 EXPECT_TRUE(op.has_type());
114 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
115 EXPECT_FALSE(op.has_data_offset());
116 EXPECT_FALSE(op.has_data_length());
117 EXPECT_EQ(1, op.src_extents_size());
118 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
119 EXPECT_EQ(1, op.dst_extents_size());
120 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
121 EXPECT_EQ(BlocksInExtents(op.src_extents()),
122 BlocksInExtents(op.dst_extents()));
123 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
124}
125
Don Garrett36e60772012-03-29 10:31:20 -0700126TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNotAllowedTest) {
Don Garrettf4b28742012-03-27 20:48:06 -0700127 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
128 reinterpret_cast<const char*>(kRandomString),
129 sizeof(kRandomString) - 1));
130 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
131 reinterpret_cast<const char*>(kRandomString),
132 sizeof(kRandomString)));
133 vector<char> data;
134 DeltaArchiveManifest_InstallOperation op;
135
Don Garrettf4b28742012-03-27 20:48:06 -0700136 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
137 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200138 0, // chunk_offset
139 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700140 false, // bsdiff_allowed
Don Garrettf4b28742012-03-27 20:48:06 -0700141 &data,
142 &op,
143 true));
144 EXPECT_FALSE(data.empty());
145
146 // The point of this test is that we don't use BSDIFF the way the above
147 // did. The rest of the details are to be caught in other tests.
148 EXPECT_TRUE(op.has_type());
149 EXPECT_NE(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
150}
151
Don Garrett36e60772012-03-29 10:31:20 -0700152TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNotAllowedMoveTest) {
Don Garrettf4b28742012-03-27 20:48:06 -0700153 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
154 reinterpret_cast<const char*>(kRandomString),
155 sizeof(kRandomString)));
156 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
157 reinterpret_cast<const char*>(kRandomString),
158 sizeof(kRandomString)));
159 vector<char> data;
160 DeltaArchiveManifest_InstallOperation op;
161
Don Garrettf4b28742012-03-27 20:48:06 -0700162 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
163 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200164 0, // chunk_offset
165 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700166 false, // bsdiff_allowed
Don Garrettf4b28742012-03-27 20:48:06 -0700167 &data,
168 &op,
169 true));
170 EXPECT_TRUE(data.empty());
171
172 // The point of this test is that we can still use a MOVE for a file
173 // that is blacklisted.
174 EXPECT_TRUE(op.has_type());
175 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
176}
177
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700178TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) {
179 vector<char> new_data;
180 for (int i = 0; i < 2; i++) {
181 new_data.insert(new_data.end(),
182 kRandomString,
183 kRandomString + sizeof(kRandomString));
184 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
185 &new_data[0],
186 new_data.size()));
187 vector<char> data;
188 DeltaArchiveManifest_InstallOperation op;
189 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
190 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200191 0, // chunk_offset
192 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700193 true, // bsdiff_allowed
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700194 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700195 &op,
196 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700197 EXPECT_FALSE(data.empty());
198
199 EXPECT_TRUE(op.has_type());
200 const DeltaArchiveManifest_InstallOperation_Type expected_type =
201 (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE :
202 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
203 EXPECT_EQ(expected_type, op.type());
204 EXPECT_FALSE(op.has_data_offset());
205 EXPECT_FALSE(op.has_data_length());
206 EXPECT_EQ(0, op.src_extents_size());
207 EXPECT_FALSE(op.has_src_length());
208 EXPECT_EQ(1, op.dst_extents_size());
209 EXPECT_EQ(new_data.size(), op.dst_length());
210 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
211 }
212}
213
Darin Petkov68c10d12010-10-14 09:24:37 -0700214TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNoGatherExtentsSmallTest) {
215 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
216 reinterpret_cast<const char*>(kRandomString),
217 sizeof(kRandomString) - 1));
218 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
219 reinterpret_cast<const char*>(kRandomString),
220 sizeof(kRandomString)));
221 vector<char> data;
222 DeltaArchiveManifest_InstallOperation op;
223 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
224 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200225 0, // chunk_offset
226 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700227 true, // bsdiff_allowed
Darin Petkov68c10d12010-10-14 09:24:37 -0700228 &data,
229 &op,
230 false));
231 EXPECT_FALSE(data.empty());
232
233 EXPECT_TRUE(op.has_type());
234 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
235 EXPECT_FALSE(op.has_data_offset());
236 EXPECT_FALSE(op.has_data_length());
237 EXPECT_EQ(1, op.src_extents_size());
238 EXPECT_EQ(0, op.src_extents().Get(0).start_block());
239 EXPECT_EQ(1, op.src_extents().Get(0).num_blocks());
240 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
241 EXPECT_EQ(1, op.dst_extents_size());
242 EXPECT_EQ(0, op.dst_extents().Get(0).start_block());
243 EXPECT_EQ(1, op.dst_extents().Get(0).num_blocks());
244 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
245}
246
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700247namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700248void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700249 vect->resize(vect->size() + 1);
250 vect->back().set_start_block(start);
251 vect->back().set_num_blocks(length);
252}
253void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700254 uint64_t start,
255 uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700256 Extent* extent = op->add_src_extents();
257 extent->set_start_block(start);
258 extent->set_num_blocks(length);
259}
260}
261
262TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
263 vector<Extent> remove_blocks;
264 AppendExtent(&remove_blocks, 3, 3);
265 AppendExtent(&remove_blocks, 7, 1);
266 vector<Extent> replace_blocks;
267 AppendExtent(&replace_blocks, 10, 2);
268 AppendExtent(&replace_blocks, 13, 2);
Andrew de los Reyesef017552010-10-06 17:57:52 -0700269 Vertex vertex;
270 DeltaArchiveManifest_InstallOperation& op = vertex.op;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700271 OpAppendExtent(&op, 4, 3);
272 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
273 OpAppendExtent(&op, 3, 1);
274 OpAppendExtent(&op, 7, 3);
Darin Petkov68c10d12010-10-14 09:24:37 -0700275
Andrew de los Reyesef017552010-10-06 17:57:52 -0700276 DeltaDiffGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700277
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700278 EXPECT_EQ(7, op.src_extents_size());
279 EXPECT_EQ(11, op.src_extents(0).start_block());
280 EXPECT_EQ(1, op.src_extents(0).num_blocks());
281 EXPECT_EQ(13, op.src_extents(1).start_block());
282 EXPECT_EQ(1, op.src_extents(1).num_blocks());
283 EXPECT_EQ(6, op.src_extents(2).start_block());
284 EXPECT_EQ(1, op.src_extents(2).num_blocks());
285 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
286 EXPECT_EQ(4, op.src_extents(3).num_blocks());
287 EXPECT_EQ(10, op.src_extents(4).start_block());
288 EXPECT_EQ(1, op.src_extents(4).num_blocks());
289 EXPECT_EQ(14, op.src_extents(5).start_block());
290 EXPECT_EQ(1, op.src_extents(5).num_blocks());
291 EXPECT_EQ(8, op.src_extents(6).start_block());
292 EXPECT_EQ(2, op.src_extents(6).num_blocks());
293}
294
295TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) {
296 Graph graph;
297 vector<Block> blocks(9);
Darin Petkov68c10d12010-10-14 09:24:37 -0700298
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700299 // Create nodes in graph
300 {
301 graph.resize(graph.size() + 1);
302 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
303 // Reads from blocks 3, 5, 7
304 vector<Extent> extents;
305 graph_utils::AppendBlockToExtents(&extents, 3);
306 graph_utils::AppendBlockToExtents(&extents, 5);
307 graph_utils::AppendBlockToExtents(&extents, 7);
308 DeltaDiffGenerator::StoreExtents(extents,
309 graph.back().op.mutable_src_extents());
310 blocks[3].reader = graph.size() - 1;
311 blocks[5].reader = graph.size() - 1;
312 blocks[7].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700313
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700314 // Writes to blocks 1, 2, 4
315 extents.clear();
316 graph_utils::AppendBlockToExtents(&extents, 1);
317 graph_utils::AppendBlockToExtents(&extents, 2);
318 graph_utils::AppendBlockToExtents(&extents, 4);
319 DeltaDiffGenerator::StoreExtents(extents,
320 graph.back().op.mutable_dst_extents());
321 blocks[1].writer = graph.size() - 1;
322 blocks[2].writer = graph.size() - 1;
323 blocks[4].writer = graph.size() - 1;
324 }
325 {
326 graph.resize(graph.size() + 1);
327 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
328 // Reads from blocks 1, 2, 4
329 vector<Extent> extents;
330 graph_utils::AppendBlockToExtents(&extents, 1);
331 graph_utils::AppendBlockToExtents(&extents, 2);
332 graph_utils::AppendBlockToExtents(&extents, 4);
333 DeltaDiffGenerator::StoreExtents(extents,
334 graph.back().op.mutable_src_extents());
335 blocks[1].reader = graph.size() - 1;
336 blocks[2].reader = graph.size() - 1;
337 blocks[4].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700338
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700339 // Writes to blocks 3, 5, 6
340 extents.clear();
341 graph_utils::AppendBlockToExtents(&extents, 3);
342 graph_utils::AppendBlockToExtents(&extents, 5);
343 graph_utils::AppendBlockToExtents(&extents, 6);
344 DeltaDiffGenerator::StoreExtents(extents,
345 graph.back().op.mutable_dst_extents());
346 blocks[3].writer = graph.size() - 1;
347 blocks[5].writer = graph.size() - 1;
348 blocks[6].writer = graph.size() - 1;
349 }
Darin Petkov68c10d12010-10-14 09:24:37 -0700350
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700351 // Create edges
352 DeltaDiffGenerator::CreateEdges(&graph, blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700353
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700354 // Find cycles
355 CycleBreaker cycle_breaker;
356 set<Edge> cut_edges;
357 cycle_breaker.BreakCycles(graph, &cut_edges);
358
359 EXPECT_EQ(1, cut_edges.size());
360 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
361 0)));
362
Andrew de los Reyesef017552010-10-06 17:57:52 -0700363 vector<CutEdgeVertexes> cuts;
364 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts));
Darin Petkov68c10d12010-10-14 09:24:37 -0700365
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700366 EXPECT_EQ(3, graph.size());
Darin Petkov68c10d12010-10-14 09:24:37 -0700367
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700368 // Check new node in graph:
369 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
370 graph.back().op.type());
371 EXPECT_EQ(2, graph.back().op.src_extents_size());
Andrew de los Reyesef017552010-10-06 17:57:52 -0700372 EXPECT_EQ(1, graph.back().op.dst_extents_size());
373 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block());
374 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700375 EXPECT_TRUE(graph.back().out_edges.empty());
Darin Petkov68c10d12010-10-14 09:24:37 -0700376
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700377 // Check that old node reads from new blocks
Andrew de los Reyesef017552010-10-06 17:57:52 -0700378 EXPECT_EQ(2, graph[0].op.src_extents_size());
379 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block());
380 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks());
381 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700382 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700383
384 // And that the old dst extents haven't changed
385 EXPECT_EQ(2, graph[0].op.dst_extents_size());
386 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block());
387 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks());
388 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block());
389 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks());
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700390
391 // Ensure it only depends on the next node and the new temp node
392 EXPECT_EQ(2, graph[0].out_edges.size());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700393 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700394 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
395 1));
396
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700397 // Check second node has unchanged extents
398 EXPECT_EQ(2, graph[1].op.src_extents_size());
399 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block());
400 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks());
401 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block());
402 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks());
403
404 EXPECT_EQ(2, graph[1].op.dst_extents_size());
405 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block());
406 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks());
407 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block());
408 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks());
Darin Petkov68c10d12010-10-14 09:24:37 -0700409
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700410 // Ensure it only depends on the next node
411 EXPECT_EQ(1, graph[1].out_edges.size());
412 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
413}
414
415TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) {
416 string orig_blobs;
417 EXPECT_TRUE(
418 utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL));
419
420 string orig_data = "abcd";
421 EXPECT_TRUE(
422 utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
423
424 string new_blobs;
425 EXPECT_TRUE(
426 utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL));
Darin Petkov68c10d12010-10-14 09:24:37 -0700427
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700428 DeltaArchiveManifest manifest;
429 DeltaArchiveManifest_InstallOperation* op =
430 manifest.add_install_operations();
431 op->set_data_offset(1);
432 op->set_data_length(3);
433 op = manifest.add_install_operations();
434 op->set_data_offset(0);
435 op->set_data_length(1);
Darin Petkov68c10d12010-10-14 09:24:37 -0700436
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700437 EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest,
438 orig_blobs,
439 new_blobs));
Darin Petkov68c10d12010-10-14 09:24:37 -0700440
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700441 string new_data;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700442 EXPECT_TRUE(utils::ReadFile(new_blobs, &new_data));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700443 EXPECT_EQ("bcda", new_data);
444 EXPECT_EQ(2, manifest.install_operations_size());
445 EXPECT_EQ(0, manifest.install_operations(0).data_offset());
446 EXPECT_EQ(3, manifest.install_operations(0).data_length());
447 EXPECT_EQ(3, manifest.install_operations(1).data_offset());
448 EXPECT_EQ(1, manifest.install_operations(1).data_length());
Darin Petkov68c10d12010-10-14 09:24:37 -0700449
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700450 unlink(orig_blobs.c_str());
451 unlink(new_blobs.c_str());
452}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000453
Andrew de los Reyesef017552010-10-06 17:57:52 -0700454TEST_F(DeltaDiffGeneratorTest, MoveFullOpsToBackTest) {
455 Graph graph(4);
456 graph[0].file_name = "A";
457 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
458 graph[1].file_name = "B";
459 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
460 graph[2].file_name = "C";
461 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
462 graph[3].file_name = "D";
463 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
464
465 vector<Vertex::Index> vect(graph.size());
466
467 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) {
468 vect[i] = i;
469 }
470 DeltaDiffGenerator::MoveFullOpsToBack(&graph, &vect);
471 EXPECT_EQ(vect.size(), graph.size());
472 EXPECT_EQ(graph[vect[0]].file_name, "B");
473 EXPECT_EQ(graph[vect[1]].file_name, "D");
474 EXPECT_EQ(graph[vect[2]].file_name, "A");
475 EXPECT_EQ(graph[vect[3]].file_name, "C");
476}
477
478namespace {
479
480#define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF
481#define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE
482#define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE
483#define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ
484
485void GenVertex(Vertex* out,
486 const vector<Extent>& src_extents,
487 const vector<Extent>& dst_extents,
488 const string& path,
489 DeltaArchiveManifest_InstallOperation_Type type) {
490 out->op.set_type(type);
491 out->file_name = path;
492 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents());
493 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents());
494}
495
496vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) {
497 return vector<Extent>(1, ExtentForRange(start_block, num_blocks));
498}
499
500EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) {
501 EdgeProperties ret;
502 ret.extents = extents;
503 return ret;
504}
505
506EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) {
507 EdgeProperties ret;
508 ret.write_extents = extents;
509 return ret;
510}
511
512template<typename T>
513void DumpVect(const vector<T>& vect) {
514 std::stringstream ss(stringstream::out);
515 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end();
516 it != e; ++it) {
517 ss << *it << ", ";
518 }
519 LOG(INFO) << "{" << ss.str() << "}";
520}
521
522} // namespace {}
523
524TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksTest) {
525 Graph graph(9);
526 const vector<Extent> empt; // empty
527 const string kFilename = "/foo";
Darin Petkov68c10d12010-10-14 09:24:37 -0700528
Andrew de los Reyesef017552010-10-06 17:57:52 -0700529 // Some scratch space:
530 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
531 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
532 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
533
534 // A cycle that requires 10 blocks to break:
535 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF);
536 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9));
537 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF);
538 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
539
540 // A cycle that requires 9 blocks to break:
541 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF);
542 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10));
543 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF);
544 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
545
546 // A cycle that requires 40 blocks to break (which is too many):
547 GenVertex(&graph[7],
548 VectOfExt(120, 50),
549 VectOfExt(60, 40),
550 "",
551 OP_BSDIFF);
552 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40));
553 GenVertex(&graph[8],
554 VectOfExt(60, 40),
555 VectOfExt(120, 50),
556 kFilename,
557 OP_BSDIFF);
558 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
Darin Petkov68c10d12010-10-14 09:24:37 -0700559
Andrew de los Reyesef017552010-10-06 17:57:52 -0700560 graph_utils::DumpGraph(graph);
Darin Petkov68c10d12010-10-14 09:24:37 -0700561
Andrew de los Reyesef017552010-10-06 17:57:52 -0700562 vector<Vertex::Index> final_order;
563
564
565 // Prepare the filesystem with the minimum required for this to work
566 string temp_dir;
567 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksTest.XXXXXX",
568 &temp_dir));
569 ScopedDirRemover temp_dir_remover(temp_dir);
Darin Petkov68c10d12010-10-14 09:24:37 -0700570
Andrew de los Reyesef017552010-10-06 17:57:52 -0700571 const size_t kBlockSize = 4096;
572 vector<char> temp_data(kBlockSize * 50);
573 FillWithData(&temp_data);
574 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
575 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
Darin Petkov68c10d12010-10-14 09:24:37 -0700576
Andrew de los Reyesef017552010-10-06 17:57:52 -0700577 int fd;
578 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksTestData.XXXXXX",
579 NULL,
580 &fd));
581 ScopedFdCloser fd_closer(&fd);
582 off_t data_file_size = 0;
583
584
585 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
586 temp_dir,
587 fd,
588 &data_file_size,
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800589 &final_order,
590 Vertex::kInvalidIndex));
Andrew de los Reyesef017552010-10-06 17:57:52 -0700591
Darin Petkov68c10d12010-10-14 09:24:37 -0700592
Andrew de los Reyesef017552010-10-06 17:57:52 -0700593 Graph expected_graph(12);
594 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
595 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
596 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
597 GenVertex(&expected_graph[3],
598 VectOfExt(10, 11),
599 VectOfExt(0, 9),
600 "",
601 OP_BSDIFF);
602 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9));
603 GenVertex(&expected_graph[4],
604 VectOfExt(60, 9),
605 VectOfExt(10, 11),
606 "",
607 OP_BSDIFF);
608 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
609 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9));
610 GenVertex(&expected_graph[5],
611 VectOfExt(40, 11),
612 VectOfExt(30, 10),
613 "",
614 OP_BSDIFF);
615 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10));
616
617 GenVertex(&expected_graph[6],
618 VectOfExt(60, 10),
619 VectOfExt(40, 11),
620 "",
621 OP_BSDIFF);
622 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
623 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10));
Darin Petkov68c10d12010-10-14 09:24:37 -0700624
Andrew de los Reyesef017552010-10-06 17:57:52 -0700625 GenVertex(&expected_graph[7],
626 VectOfExt(120, 50),
627 VectOfExt(60, 40),
628 "",
629 OP_BSDIFF);
630 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10));
631
632 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ);
633 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
634
635 GenVertex(&expected_graph[9],
636 VectOfExt(0, 9),
637 VectOfExt(60, 9),
638 "",
639 OP_MOVE);
640
641 GenVertex(&expected_graph[10],
642 VectOfExt(30, 10),
643 VectOfExt(60, 10),
644 "",
645 OP_MOVE);
646 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
Darin Petkov68c10d12010-10-14 09:24:37 -0700647
Andrew de los Reyesef017552010-10-06 17:57:52 -0700648 EXPECT_EQ(12, graph.size());
649 EXPECT_FALSE(graph.back().valid);
650 for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
651 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
652 if (i == 8) {
653 // special case
654 } else {
655 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i;
656 }
657 }
658}
659
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700660TEST_F(DeltaDiffGeneratorTest, IsNoopOperationTest) {
661 DeltaArchiveManifest_InstallOperation op;
662 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
663 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
664 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
665 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
666 *(op.add_src_extents()) = ExtentForRange(3, 2);
667 *(op.add_dst_extents()) = ExtentForRange(3, 2);
668 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
669 *(op.add_src_extents()) = ExtentForRange(7, 5);
670 *(op.add_dst_extents()) = ExtentForRange(7, 5);
671 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
672 *(op.add_src_extents()) = ExtentForRange(20, 2);
673 *(op.add_dst_extents()) = ExtentForRange(20, 1);
674 *(op.add_dst_extents()) = ExtentForRange(21, 1);
675 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
676 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 2);
677 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 1);
678 *(op.add_dst_extents()) = ExtentForRange(kSparseHole, 3);
679 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
680 *(op.add_src_extents()) = ExtentForRange(24, 1);
681 *(op.add_dst_extents()) = ExtentForRange(25, 1);
682 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
683}
684
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700685TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksReuseTest) {
686 // AssignTempBlocks(Graph* graph,
687 // const string& new_root,
688 // int data_fd,
689 // off_t* data_file_size,
690 // vector<Vertex::Index>* op_indexes,
691 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
692 // const vector<CutEdgeVertexes>& cuts
693 Graph graph(9);
694
695 const vector<Extent> empt;
696 uint64_t tmp = kTempBlockStart;
697 const string kFilename = "/foo";
698
699 vector<CutEdgeVertexes> cuts;
700 cuts.resize(3);
701
702 // Simple broken loop:
703 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE);
704 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE);
705 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE);
706 // Corresponding edges:
707 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
708 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
709 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
710 // Store the cut:
711 cuts[0].old_dst = 1;
712 cuts[0].old_src = 0;
713 cuts[0].new_vertex = 2;
714 cuts[0].tmp_extents = VectOfExt(tmp, 1);
715 tmp++;
716
717 // Slightly more complex pair of loops:
718 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE);
719 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE);
720 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE);
721 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE);
722 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE);
723 // Corresponding edges:
724 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
725 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
726 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
727 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
728 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
729 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
730 // Store the cuts:
731 cuts[1].old_dst = 5;
732 cuts[1].old_src = 3;
733 cuts[1].new_vertex = 6;
734 cuts[1].tmp_extents = VectOfExt(tmp, 2);
735 cuts[2].old_dst = 5;
736 cuts[2].old_src = 4;
737 cuts[2].new_vertex = 7;
738 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
739
740 // Supplier of temp block:
741 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE);
742
743 // Specify the final order:
744 vector<Vertex::Index> op_indexes;
745 op_indexes.push_back(2);
746 op_indexes.push_back(0);
747 op_indexes.push_back(1);
748 op_indexes.push_back(6);
749 op_indexes.push_back(3);
750 op_indexes.push_back(7);
751 op_indexes.push_back(4);
752 op_indexes.push_back(5);
753 op_indexes.push_back(8);
754
755 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
756 DeltaDiffGenerator::GenerateReverseTopoOrderMap(op_indexes,
757 &reverse_op_indexes);
758
759 // Prepare the filesystem with the minimum required for this to work
760 string temp_dir;
761 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksReuseTest.XXXXXX",
762 &temp_dir));
763 ScopedDirRemover temp_dir_remover(temp_dir);
764
765 const size_t kBlockSize = 4096;
766 vector<char> temp_data(kBlockSize * 3);
767 FillWithData(&temp_data);
768 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
769 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
770
771 int fd;
772 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksReuseTest.XXXXXX",
773 NULL,
774 &fd));
775 ScopedFdCloser fd_closer(&fd);
776 off_t data_file_size = 0;
Thieu Le5c7d9752010-12-15 16:09:28 -0800777
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700778 EXPECT_TRUE(DeltaDiffGenerator::AssignTempBlocks(&graph,
779 temp_dir,
780 fd,
781 &data_file_size,
782 &op_indexes,
783 &reverse_op_indexes,
784 cuts));
785 EXPECT_FALSE(graph[6].valid);
786 EXPECT_FALSE(graph[7].valid);
787 EXPECT_EQ(1, graph[1].op.src_extents_size());
788 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block());
789 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks());
790 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type());
791}
792
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800793TEST_F(DeltaDiffGeneratorTest, CreateScratchNodeTest) {
794 Vertex vertex;
795 DeltaDiffGenerator::CreateScratchNode(12, 34, &vertex);
796 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ,
797 vertex.op.type());
798 EXPECT_EQ(0, vertex.op.data_offset());
799 EXPECT_EQ(0, vertex.op.data_length());
800 EXPECT_EQ(1, vertex.op.dst_extents_size());
801 EXPECT_EQ(12, vertex.op.dst_extents(0).start_block());
802 EXPECT_EQ(34, vertex.op.dst_extents(0).num_blocks());
803}
804
adlr@google.com3defe6a2009-12-04 20:57:17 +0000805} // namespace chromeos_update_engine