blob: f4570f9ea42b3b1868e8c2b36b7bb9afa1ab1b7b [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:
Gilad Arnold99dcdc82013-07-16 03:00:20 -070054 const string& old_path() { return old_path_; }
55 const string& new_path() { return new_path_; }
56
57 virtual void SetUp() {
58 ASSERT_TRUE(utils::MakeTempFile("DeltaDiffGeneratorTest-old_path-XXXXXX",
59 &old_path_, NULL));
60 ASSERT_TRUE(utils::MakeTempFile("DeltaDiffGeneratorTest-new_path-XXXXXX",
61 &new_path_, NULL));
62 }
63
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070064 virtual void TearDown() {
65 unlink(old_path().c_str());
66 unlink(new_path().c_str());
67 }
Gilad Arnold99dcdc82013-07-16 03:00:20 -070068
69 private:
70 string old_path_;
71 string new_path_;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070072};
73
74TEST_F(DeltaDiffGeneratorTest, RunAsRootMoveSmallTest) {
75 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
76 reinterpret_cast<const char*>(kRandomString),
77 sizeof(kRandomString)));
78 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
79 reinterpret_cast<const char*>(kRandomString),
80 sizeof(kRandomString)));
81 vector<char> data;
82 DeltaArchiveManifest_InstallOperation op;
83 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
84 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +020085 0, // chunk_offset
86 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -070087 true, // bsdiff_allowed
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070088 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -070089 &op,
90 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070091 EXPECT_TRUE(data.empty());
92
93 EXPECT_TRUE(op.has_type());
94 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
95 EXPECT_FALSE(op.has_data_offset());
96 EXPECT_FALSE(op.has_data_length());
97 EXPECT_EQ(1, op.src_extents_size());
98 EXPECT_EQ(sizeof(kRandomString), op.src_length());
99 EXPECT_EQ(1, op.dst_extents_size());
100 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
101 EXPECT_EQ(BlocksInExtents(op.src_extents()),
102 BlocksInExtents(op.dst_extents()));
103 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
104}
105
106TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffSmallTest) {
107 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
108 reinterpret_cast<const char*>(kRandomString),
109 sizeof(kRandomString) - 1));
110 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
111 reinterpret_cast<const char*>(kRandomString),
112 sizeof(kRandomString)));
113 vector<char> data;
114 DeltaArchiveManifest_InstallOperation op;
115 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
116 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200117 0, // chunk_offset
118 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700119 true, // bsdiff_allowed
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700120 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700121 &op,
122 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700123 EXPECT_FALSE(data.empty());
124
125 EXPECT_TRUE(op.has_type());
126 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
127 EXPECT_FALSE(op.has_data_offset());
128 EXPECT_FALSE(op.has_data_length());
129 EXPECT_EQ(1, op.src_extents_size());
130 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
131 EXPECT_EQ(1, op.dst_extents_size());
132 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
133 EXPECT_EQ(BlocksInExtents(op.src_extents()),
134 BlocksInExtents(op.dst_extents()));
135 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
136}
137
Don Garrett36e60772012-03-29 10:31:20 -0700138TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNotAllowedTest) {
Don Garrettf4b28742012-03-27 20:48:06 -0700139 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
140 reinterpret_cast<const char*>(kRandomString),
141 sizeof(kRandomString) - 1));
142 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
143 reinterpret_cast<const char*>(kRandomString),
144 sizeof(kRandomString)));
145 vector<char> data;
146 DeltaArchiveManifest_InstallOperation op;
147
Don Garrettf4b28742012-03-27 20:48:06 -0700148 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
149 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200150 0, // chunk_offset
151 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700152 false, // bsdiff_allowed
Don Garrettf4b28742012-03-27 20:48:06 -0700153 &data,
154 &op,
155 true));
156 EXPECT_FALSE(data.empty());
157
158 // The point of this test is that we don't use BSDIFF the way the above
159 // did. The rest of the details are to be caught in other tests.
160 EXPECT_TRUE(op.has_type());
161 EXPECT_NE(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
162}
163
Don Garrett36e60772012-03-29 10:31:20 -0700164TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNotAllowedMoveTest) {
Don Garrettf4b28742012-03-27 20:48:06 -0700165 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
166 reinterpret_cast<const char*>(kRandomString),
167 sizeof(kRandomString)));
168 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
169 reinterpret_cast<const char*>(kRandomString),
170 sizeof(kRandomString)));
171 vector<char> data;
172 DeltaArchiveManifest_InstallOperation op;
173
Don Garrettf4b28742012-03-27 20:48:06 -0700174 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
175 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200176 0, // chunk_offset
177 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700178 false, // bsdiff_allowed
Don Garrettf4b28742012-03-27 20:48:06 -0700179 &data,
180 &op,
181 true));
182 EXPECT_TRUE(data.empty());
183
184 // The point of this test is that we can still use a MOVE for a file
185 // that is blacklisted.
186 EXPECT_TRUE(op.has_type());
187 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
188}
189
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700190TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) {
191 vector<char> new_data;
192 for (int i = 0; i < 2; i++) {
193 new_data.insert(new_data.end(),
194 kRandomString,
195 kRandomString + sizeof(kRandomString));
196 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
197 &new_data[0],
198 new_data.size()));
199 vector<char> data;
200 DeltaArchiveManifest_InstallOperation op;
201 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
202 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200203 0, // chunk_offset
204 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700205 true, // bsdiff_allowed
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700206 &data,
Darin Petkov68c10d12010-10-14 09:24:37 -0700207 &op,
208 true));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700209 EXPECT_FALSE(data.empty());
210
211 EXPECT_TRUE(op.has_type());
212 const DeltaArchiveManifest_InstallOperation_Type expected_type =
213 (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE :
214 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
215 EXPECT_EQ(expected_type, op.type());
216 EXPECT_FALSE(op.has_data_offset());
217 EXPECT_FALSE(op.has_data_length());
218 EXPECT_EQ(0, op.src_extents_size());
219 EXPECT_FALSE(op.has_src_length());
220 EXPECT_EQ(1, op.dst_extents_size());
221 EXPECT_EQ(new_data.size(), op.dst_length());
222 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
223 }
224}
225
Darin Petkov68c10d12010-10-14 09:24:37 -0700226TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffNoGatherExtentsSmallTest) {
227 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
228 reinterpret_cast<const char*>(kRandomString),
229 sizeof(kRandomString) - 1));
230 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
231 reinterpret_cast<const char*>(kRandomString),
232 sizeof(kRandomString)));
233 vector<char> data;
234 DeltaArchiveManifest_InstallOperation op;
235 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
236 new_path(),
Darin Petkov8e447e02013-04-16 16:23:50 +0200237 0, // chunk_offset
238 -1, // chunk_size
Don Garrett36e60772012-03-29 10:31:20 -0700239 true, // bsdiff_allowed
Darin Petkov68c10d12010-10-14 09:24:37 -0700240 &data,
241 &op,
242 false));
243 EXPECT_FALSE(data.empty());
244
245 EXPECT_TRUE(op.has_type());
246 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
247 EXPECT_FALSE(op.has_data_offset());
248 EXPECT_FALSE(op.has_data_length());
249 EXPECT_EQ(1, op.src_extents_size());
250 EXPECT_EQ(0, op.src_extents().Get(0).start_block());
251 EXPECT_EQ(1, op.src_extents().Get(0).num_blocks());
252 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
253 EXPECT_EQ(1, op.dst_extents_size());
254 EXPECT_EQ(0, op.dst_extents().Get(0).start_block());
255 EXPECT_EQ(1, op.dst_extents().Get(0).num_blocks());
256 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
257}
258
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700259namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700260void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700261 vect->resize(vect->size() + 1);
262 vect->back().set_start_block(start);
263 vect->back().set_num_blocks(length);
264}
265void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700266 uint64_t start,
267 uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700268 Extent* extent = op->add_src_extents();
269 extent->set_start_block(start);
270 extent->set_num_blocks(length);
271}
272}
273
274TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
275 vector<Extent> remove_blocks;
276 AppendExtent(&remove_blocks, 3, 3);
277 AppendExtent(&remove_blocks, 7, 1);
278 vector<Extent> replace_blocks;
279 AppendExtent(&replace_blocks, 10, 2);
280 AppendExtent(&replace_blocks, 13, 2);
Andrew de los Reyesef017552010-10-06 17:57:52 -0700281 Vertex vertex;
282 DeltaArchiveManifest_InstallOperation& op = vertex.op;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700283 OpAppendExtent(&op, 4, 3);
284 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
285 OpAppendExtent(&op, 3, 1);
286 OpAppendExtent(&op, 7, 3);
Darin Petkov68c10d12010-10-14 09:24:37 -0700287
Andrew de los Reyesef017552010-10-06 17:57:52 -0700288 DeltaDiffGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700289
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700290 EXPECT_EQ(7, op.src_extents_size());
291 EXPECT_EQ(11, op.src_extents(0).start_block());
292 EXPECT_EQ(1, op.src_extents(0).num_blocks());
293 EXPECT_EQ(13, op.src_extents(1).start_block());
294 EXPECT_EQ(1, op.src_extents(1).num_blocks());
295 EXPECT_EQ(6, op.src_extents(2).start_block());
296 EXPECT_EQ(1, op.src_extents(2).num_blocks());
297 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
298 EXPECT_EQ(4, op.src_extents(3).num_blocks());
299 EXPECT_EQ(10, op.src_extents(4).start_block());
300 EXPECT_EQ(1, op.src_extents(4).num_blocks());
301 EXPECT_EQ(14, op.src_extents(5).start_block());
302 EXPECT_EQ(1, op.src_extents(5).num_blocks());
303 EXPECT_EQ(8, op.src_extents(6).start_block());
304 EXPECT_EQ(2, op.src_extents(6).num_blocks());
305}
306
307TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) {
308 Graph graph;
309 vector<Block> blocks(9);
Darin Petkov68c10d12010-10-14 09:24:37 -0700310
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700311 // Create nodes in graph
312 {
313 graph.resize(graph.size() + 1);
314 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
315 // Reads from blocks 3, 5, 7
316 vector<Extent> extents;
317 graph_utils::AppendBlockToExtents(&extents, 3);
318 graph_utils::AppendBlockToExtents(&extents, 5);
319 graph_utils::AppendBlockToExtents(&extents, 7);
320 DeltaDiffGenerator::StoreExtents(extents,
321 graph.back().op.mutable_src_extents());
322 blocks[3].reader = graph.size() - 1;
323 blocks[5].reader = graph.size() - 1;
324 blocks[7].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700325
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700326 // Writes to blocks 1, 2, 4
327 extents.clear();
328 graph_utils::AppendBlockToExtents(&extents, 1);
329 graph_utils::AppendBlockToExtents(&extents, 2);
330 graph_utils::AppendBlockToExtents(&extents, 4);
331 DeltaDiffGenerator::StoreExtents(extents,
332 graph.back().op.mutable_dst_extents());
333 blocks[1].writer = graph.size() - 1;
334 blocks[2].writer = graph.size() - 1;
335 blocks[4].writer = graph.size() - 1;
336 }
337 {
338 graph.resize(graph.size() + 1);
339 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
340 // Reads from blocks 1, 2, 4
341 vector<Extent> extents;
342 graph_utils::AppendBlockToExtents(&extents, 1);
343 graph_utils::AppendBlockToExtents(&extents, 2);
344 graph_utils::AppendBlockToExtents(&extents, 4);
345 DeltaDiffGenerator::StoreExtents(extents,
346 graph.back().op.mutable_src_extents());
347 blocks[1].reader = graph.size() - 1;
348 blocks[2].reader = graph.size() - 1;
349 blocks[4].reader = graph.size() - 1;
Darin Petkov68c10d12010-10-14 09:24:37 -0700350
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700351 // Writes to blocks 3, 5, 6
352 extents.clear();
353 graph_utils::AppendBlockToExtents(&extents, 3);
354 graph_utils::AppendBlockToExtents(&extents, 5);
355 graph_utils::AppendBlockToExtents(&extents, 6);
356 DeltaDiffGenerator::StoreExtents(extents,
357 graph.back().op.mutable_dst_extents());
358 blocks[3].writer = graph.size() - 1;
359 blocks[5].writer = graph.size() - 1;
360 blocks[6].writer = graph.size() - 1;
361 }
Darin Petkov68c10d12010-10-14 09:24:37 -0700362
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700363 // Create edges
364 DeltaDiffGenerator::CreateEdges(&graph, blocks);
Darin Petkov68c10d12010-10-14 09:24:37 -0700365
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700366 // Find cycles
367 CycleBreaker cycle_breaker;
368 set<Edge> cut_edges;
369 cycle_breaker.BreakCycles(graph, &cut_edges);
370
371 EXPECT_EQ(1, cut_edges.size());
372 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
373 0)));
374
Andrew de los Reyesef017552010-10-06 17:57:52 -0700375 vector<CutEdgeVertexes> cuts;
376 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts));
Darin Petkov68c10d12010-10-14 09:24:37 -0700377
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700378 EXPECT_EQ(3, graph.size());
Darin Petkov68c10d12010-10-14 09:24:37 -0700379
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700380 // Check new node in graph:
381 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
382 graph.back().op.type());
383 EXPECT_EQ(2, graph.back().op.src_extents_size());
Andrew de los Reyesef017552010-10-06 17:57:52 -0700384 EXPECT_EQ(1, graph.back().op.dst_extents_size());
385 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block());
386 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700387 EXPECT_TRUE(graph.back().out_edges.empty());
Darin Petkov68c10d12010-10-14 09:24:37 -0700388
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700389 // Check that old node reads from new blocks
Andrew de los Reyesef017552010-10-06 17:57:52 -0700390 EXPECT_EQ(2, graph[0].op.src_extents_size());
391 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block());
392 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks());
393 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700394 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700395
396 // And that the old dst extents haven't changed
397 EXPECT_EQ(2, graph[0].op.dst_extents_size());
398 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block());
399 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks());
400 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block());
401 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks());
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700402
403 // Ensure it only depends on the next node and the new temp node
404 EXPECT_EQ(2, graph[0].out_edges.size());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700405 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
Andrew de los Reyesd12784c2010-07-26 13:55:14 -0700406 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
407 1));
408
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700409 // Check second node has unchanged extents
410 EXPECT_EQ(2, graph[1].op.src_extents_size());
411 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block());
412 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks());
413 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block());
414 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks());
415
416 EXPECT_EQ(2, graph[1].op.dst_extents_size());
417 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block());
418 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks());
419 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block());
420 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks());
Darin Petkov68c10d12010-10-14 09:24:37 -0700421
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700422 // Ensure it only depends on the next node
423 EXPECT_EQ(1, graph[1].out_edges.size());
424 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
425}
426
427TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) {
428 string orig_blobs;
429 EXPECT_TRUE(
430 utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL));
431
432 string orig_data = "abcd";
433 EXPECT_TRUE(
434 utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
435
436 string new_blobs;
437 EXPECT_TRUE(
438 utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL));
Darin Petkov68c10d12010-10-14 09:24:37 -0700439
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700440 DeltaArchiveManifest manifest;
441 DeltaArchiveManifest_InstallOperation* op =
442 manifest.add_install_operations();
443 op->set_data_offset(1);
444 op->set_data_length(3);
445 op = manifest.add_install_operations();
446 op->set_data_offset(0);
447 op->set_data_length(1);
Darin Petkov68c10d12010-10-14 09:24:37 -0700448
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700449 EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest,
450 orig_blobs,
451 new_blobs));
Darin Petkov68c10d12010-10-14 09:24:37 -0700452
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700453 string new_data;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700454 EXPECT_TRUE(utils::ReadFile(new_blobs, &new_data));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700455 EXPECT_EQ("bcda", new_data);
456 EXPECT_EQ(2, manifest.install_operations_size());
457 EXPECT_EQ(0, manifest.install_operations(0).data_offset());
458 EXPECT_EQ(3, manifest.install_operations(0).data_length());
459 EXPECT_EQ(3, manifest.install_operations(1).data_offset());
460 EXPECT_EQ(1, manifest.install_operations(1).data_length());
Darin Petkov68c10d12010-10-14 09:24:37 -0700461
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700462 unlink(orig_blobs.c_str());
463 unlink(new_blobs.c_str());
464}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000465
Andrew de los Reyesef017552010-10-06 17:57:52 -0700466TEST_F(DeltaDiffGeneratorTest, MoveFullOpsToBackTest) {
467 Graph graph(4);
468 graph[0].file_name = "A";
469 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
470 graph[1].file_name = "B";
471 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
472 graph[2].file_name = "C";
473 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
474 graph[3].file_name = "D";
475 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
476
477 vector<Vertex::Index> vect(graph.size());
478
479 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) {
480 vect[i] = i;
481 }
482 DeltaDiffGenerator::MoveFullOpsToBack(&graph, &vect);
483 EXPECT_EQ(vect.size(), graph.size());
484 EXPECT_EQ(graph[vect[0]].file_name, "B");
485 EXPECT_EQ(graph[vect[1]].file_name, "D");
486 EXPECT_EQ(graph[vect[2]].file_name, "A");
487 EXPECT_EQ(graph[vect[3]].file_name, "C");
488}
489
490namespace {
491
492#define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF
493#define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE
494#define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE
495#define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ
496
497void GenVertex(Vertex* out,
498 const vector<Extent>& src_extents,
499 const vector<Extent>& dst_extents,
500 const string& path,
501 DeltaArchiveManifest_InstallOperation_Type type) {
502 out->op.set_type(type);
503 out->file_name = path;
504 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents());
505 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents());
506}
507
508vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) {
509 return vector<Extent>(1, ExtentForRange(start_block, num_blocks));
510}
511
512EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) {
513 EdgeProperties ret;
514 ret.extents = extents;
515 return ret;
516}
517
518EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) {
519 EdgeProperties ret;
520 ret.write_extents = extents;
521 return ret;
522}
523
524template<typename T>
525void DumpVect(const vector<T>& vect) {
526 std::stringstream ss(stringstream::out);
527 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end();
528 it != e; ++it) {
529 ss << *it << ", ";
530 }
531 LOG(INFO) << "{" << ss.str() << "}";
532}
533
534} // namespace {}
535
536TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksTest) {
537 Graph graph(9);
538 const vector<Extent> empt; // empty
539 const string kFilename = "/foo";
Darin Petkov68c10d12010-10-14 09:24:37 -0700540
Andrew de los Reyesef017552010-10-06 17:57:52 -0700541 // Some scratch space:
542 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
543 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
544 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
545
546 // A cycle that requires 10 blocks to break:
547 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF);
548 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9));
549 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF);
550 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
551
552 // A cycle that requires 9 blocks to break:
553 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF);
554 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10));
555 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF);
556 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
557
558 // A cycle that requires 40 blocks to break (which is too many):
559 GenVertex(&graph[7],
560 VectOfExt(120, 50),
561 VectOfExt(60, 40),
562 "",
563 OP_BSDIFF);
564 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40));
565 GenVertex(&graph[8],
566 VectOfExt(60, 40),
567 VectOfExt(120, 50),
568 kFilename,
569 OP_BSDIFF);
570 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
Darin Petkov68c10d12010-10-14 09:24:37 -0700571
Andrew de los Reyesef017552010-10-06 17:57:52 -0700572 graph_utils::DumpGraph(graph);
Darin Petkov68c10d12010-10-14 09:24:37 -0700573
Andrew de los Reyesef017552010-10-06 17:57:52 -0700574 vector<Vertex::Index> final_order;
575
576
577 // Prepare the filesystem with the minimum required for this to work
578 string temp_dir;
579 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksTest.XXXXXX",
580 &temp_dir));
581 ScopedDirRemover temp_dir_remover(temp_dir);
Darin Petkov68c10d12010-10-14 09:24:37 -0700582
Andrew de los Reyesef017552010-10-06 17:57:52 -0700583 const size_t kBlockSize = 4096;
584 vector<char> temp_data(kBlockSize * 50);
585 FillWithData(&temp_data);
586 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
587 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
Darin Petkov68c10d12010-10-14 09:24:37 -0700588
Andrew de los Reyesef017552010-10-06 17:57:52 -0700589 int fd;
590 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksTestData.XXXXXX",
591 NULL,
592 &fd));
593 ScopedFdCloser fd_closer(&fd);
594 off_t data_file_size = 0;
595
596
597 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
598 temp_dir,
599 fd,
600 &data_file_size,
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800601 &final_order,
602 Vertex::kInvalidIndex));
Andrew de los Reyesef017552010-10-06 17:57:52 -0700603
Darin Petkov68c10d12010-10-14 09:24:37 -0700604
Andrew de los Reyesef017552010-10-06 17:57:52 -0700605 Graph expected_graph(12);
606 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE);
607 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE);
608 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE);
609 GenVertex(&expected_graph[3],
610 VectOfExt(10, 11),
611 VectOfExt(0, 9),
612 "",
613 OP_BSDIFF);
614 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9));
615 GenVertex(&expected_graph[4],
616 VectOfExt(60, 9),
617 VectOfExt(10, 11),
618 "",
619 OP_BSDIFF);
620 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
621 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9));
622 GenVertex(&expected_graph[5],
623 VectOfExt(40, 11),
624 VectOfExt(30, 10),
625 "",
626 OP_BSDIFF);
627 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10));
628
629 GenVertex(&expected_graph[6],
630 VectOfExt(60, 10),
631 VectOfExt(40, 11),
632 "",
633 OP_BSDIFF);
634 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
635 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10));
Darin Petkov68c10d12010-10-14 09:24:37 -0700636
Andrew de los Reyesef017552010-10-06 17:57:52 -0700637 GenVertex(&expected_graph[7],
638 VectOfExt(120, 50),
639 VectOfExt(60, 40),
640 "",
641 OP_BSDIFF);
642 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10));
643
644 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ);
645 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
646
647 GenVertex(&expected_graph[9],
648 VectOfExt(0, 9),
649 VectOfExt(60, 9),
650 "",
651 OP_MOVE);
652
653 GenVertex(&expected_graph[10],
654 VectOfExt(30, 10),
655 VectOfExt(60, 10),
656 "",
657 OP_MOVE);
658 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
Darin Petkov68c10d12010-10-14 09:24:37 -0700659
Andrew de los Reyesef017552010-10-06 17:57:52 -0700660 EXPECT_EQ(12, graph.size());
661 EXPECT_FALSE(graph.back().valid);
662 for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
663 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
664 if (i == 8) {
665 // special case
666 } else {
667 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i;
668 }
669 }
670}
671
Darin Petkov94817cb2013-05-08 14:33:24 +0200672// Test that sparse holes are not used as scratch. More specifically, test that
673// if all full operations write to sparse holes and there's no extra scratch
674// space, delta operations that need scratch are converted to full. See
675// crbug.com/238440.
676TEST_F(DeltaDiffGeneratorTest, RunAsRootNoSparseAsTempTest) {
677 Graph graph(3);
678 const vector<Extent> kEmpty;
679 const string kFilename = "/foo";
680
681 // Make sure this sparse hole is not used as scratch.
682 GenVertex(&graph[0], kEmpty, VectOfExt(kSparseHole, 1), "", OP_REPLACE);
683
684 // Create a single-block cycle.
685 GenVertex(&graph[1], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_BSDIFF);
686 graph[1].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
687 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(0, 1), kFilename, OP_BSDIFF);
688 graph[2].out_edges[1] = EdgeWithReadDep(VectOfExt(0, 1));
689
690 graph_utils::DumpGraph(graph);
691
692 vector<Vertex::Index> final_order;
693
694 // Prepare the filesystem with the minimum required for this to work.
695 string temp_dir;
696 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/NoSparseAsTempTest.XXXXXX",
697 &temp_dir));
698 ScopedDirRemover temp_dir_remover(temp_dir);
699
700 const size_t kBlockSize = 4096;
701 vector<char> temp_data(kBlockSize);
702 FillWithData(&temp_data);
703 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
704 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
705
706 int fd = -1;
707 EXPECT_TRUE(utils::MakeTempFile("/tmp/NoSparseAsTempTestData.XXXXXX",
708 NULL,
709 &fd));
710 ScopedFdCloser fd_closer(&fd);
711 off_t data_file_size = 0;
712
713 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
714 temp_dir,
715 fd,
716 &data_file_size,
717 &final_order,
718 Vertex::kInvalidIndex));
719
720 ASSERT_EQ(4, graph.size());
721
722 // The second BSDIFF operation must have been converted to a full operation
723 // (due to insufficient scratch space).
724 EXPECT_TRUE(graph[2].op.type() == OP_REPLACE ||
725 graph[2].op.type() == OP_REPLACE_BZ);
726
727 // The temporary node created for breaking the cycle must have been marked as
728 // invalid.
729 EXPECT_FALSE(graph[3].valid);
730}
731
732// Test that sparse holes are not used as scratch. More specifically, test that
733// if scratch space comes only from full operations writing to real blocks as
734// well as sparse holes, only the real blocks are utilized. See
735// crbug.com/238440.
736TEST_F(DeltaDiffGeneratorTest, NoSparseAsTempTest) {
737 Graph graph;
738 vector<Block> blocks(4);
739
740 // Create nodes in |graph|.
741 {
742 graph.resize(graph.size() + 1);
743 graph.back().op.set_type(
744 DeltaArchiveManifest_InstallOperation_Type_REPLACE);
745
746 // Write to a sparse hole -- basically a no-op to ensure sparse holes are
747 // not used as scratch.
748 vector<Extent> extents;
749 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
750 DeltaDiffGenerator::StoreExtents(extents,
751 graph.back().op.mutable_dst_extents());
752 }
753 {
754 graph.resize(graph.size() + 1);
755 graph.back().op.set_type(OP_REPLACE);
756
757 // Scratch space: write to block 0 with sparse holes around.
758 vector<Extent> extents;
759 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
760 graph_utils::AppendBlockToExtents(&extents, 0);
761 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
762 DeltaDiffGenerator::StoreExtents(extents,
763 graph.back().op.mutable_dst_extents());
764 blocks[0].writer = graph.size() - 1;
765 }
766 {
767 graph.resize(graph.size() + 1);
768 graph.back().op.set_type(OP_REPLACE);
769
770 // Write to a sparse hole.
771 vector<Extent> extents;
772 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
773 DeltaDiffGenerator::StoreExtents(extents,
774 graph.back().op.mutable_dst_extents());
775 }
776 // Create a two-node cycle between (2, sparse, sparse) and (1, sparse, 3).
777 {
778 graph.resize(graph.size() + 1);
779 graph.back().op.set_type(OP_MOVE);
780 // Read from (2, sparse, sparse).
781 vector<Extent> extents;
782 graph_utils::AppendBlockToExtents(&extents, 2);
783 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
784 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
785 DeltaDiffGenerator::StoreExtents(extents,
786 graph.back().op.mutable_src_extents());
787 blocks[2].reader = graph.size() - 1;
788
789 // Write to (1, sparse, 3).
790 extents.clear();
791 graph_utils::AppendBlockToExtents(&extents, 1);
792 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
793 graph_utils::AppendBlockToExtents(&extents, 3);
794 DeltaDiffGenerator::StoreExtents(extents,
795 graph.back().op.mutable_dst_extents());
796 blocks[1].writer = graph.size() - 1;
797 blocks[3].writer = graph.size() - 1;
798 }
799 {
800 graph.resize(graph.size() + 1);
801 graph.back().op.set_type(OP_MOVE);
802 // Read from (1, sparse, 3).
803 vector<Extent> extents;
804 graph_utils::AppendBlockToExtents(&extents, 1);
805 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
806 graph_utils::AppendBlockToExtents(&extents, 3);
807 DeltaDiffGenerator::StoreExtents(extents,
808 graph.back().op.mutable_src_extents());
809 blocks[1].reader = graph.size() - 1;
810 blocks[3].reader = graph.size() - 1;
811
812 // Write to (2, sparse, sparse).
813 extents.clear();
814 graph_utils::AppendBlockToExtents(&extents, 2);
815 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
816 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
817 DeltaDiffGenerator::StoreExtents(extents,
818 graph.back().op.mutable_dst_extents());
819 blocks[2].writer = graph.size() - 1;
820 }
821
822 graph_utils::DumpGraph(graph);
823
824 // Create edges
825 DeltaDiffGenerator::CreateEdges(&graph, blocks);
826
827 graph_utils::DumpGraph(graph);
828
829 vector<Vertex::Index> final_order;
830 off_t data_file_size = 0;
831 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
832 "/non/existent/dir",
833 -1,
834 &data_file_size,
835 &final_order,
836 Vertex::kInvalidIndex));
837
838 // Check for a single temporary node writing to scratch.
839 ASSERT_EQ(6, graph.size());
840 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
841 graph[5].op.type());
842 EXPECT_EQ(1, graph[5].op.src_extents_size());
843 ASSERT_EQ(1, graph[5].op.dst_extents_size());
844 EXPECT_EQ(0, graph[5].op.dst_extents(0).start_block());
845 EXPECT_EQ(1, graph[5].op.dst_extents(0).num_blocks());
846
847 // Make sure the cycle nodes still read from and write to sparse holes.
848 for (int i = 3; i < 5; i++) {
849 ASSERT_GE(graph[i].op.src_extents_size(), 2);
850 EXPECT_EQ(kSparseHole, graph[i].op.src_extents(1).start_block());
851 ASSERT_GE(graph[i].op.dst_extents_size(), 2);
852 EXPECT_EQ(kSparseHole, graph[i].op.dst_extents(1).start_block());
853 }
854}
855
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700856TEST_F(DeltaDiffGeneratorTest, IsNoopOperationTest) {
857 DeltaArchiveManifest_InstallOperation op;
858 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
859 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
860 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
861 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
862 *(op.add_src_extents()) = ExtentForRange(3, 2);
863 *(op.add_dst_extents()) = ExtentForRange(3, 2);
864 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
865 *(op.add_src_extents()) = ExtentForRange(7, 5);
866 *(op.add_dst_extents()) = ExtentForRange(7, 5);
867 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
868 *(op.add_src_extents()) = ExtentForRange(20, 2);
869 *(op.add_dst_extents()) = ExtentForRange(20, 1);
870 *(op.add_dst_extents()) = ExtentForRange(21, 1);
871 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
872 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 2);
873 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 1);
874 *(op.add_dst_extents()) = ExtentForRange(kSparseHole, 3);
875 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
876 *(op.add_src_extents()) = ExtentForRange(24, 1);
877 *(op.add_dst_extents()) = ExtentForRange(25, 1);
878 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
879}
880
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700881TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksReuseTest) {
882 // AssignTempBlocks(Graph* graph,
883 // const string& new_root,
884 // int data_fd,
885 // off_t* data_file_size,
886 // vector<Vertex::Index>* op_indexes,
887 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
888 // const vector<CutEdgeVertexes>& cuts
889 Graph graph(9);
890
891 const vector<Extent> empt;
892 uint64_t tmp = kTempBlockStart;
893 const string kFilename = "/foo";
894
895 vector<CutEdgeVertexes> cuts;
896 cuts.resize(3);
897
898 // Simple broken loop:
899 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE);
900 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE);
901 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE);
902 // Corresponding edges:
903 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
904 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
905 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
906 // Store the cut:
907 cuts[0].old_dst = 1;
908 cuts[0].old_src = 0;
909 cuts[0].new_vertex = 2;
910 cuts[0].tmp_extents = VectOfExt(tmp, 1);
911 tmp++;
912
913 // Slightly more complex pair of loops:
914 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE);
915 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE);
916 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE);
917 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE);
918 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE);
919 // Corresponding edges:
920 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
921 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
922 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
923 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
924 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
925 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
926 // Store the cuts:
927 cuts[1].old_dst = 5;
928 cuts[1].old_src = 3;
929 cuts[1].new_vertex = 6;
930 cuts[1].tmp_extents = VectOfExt(tmp, 2);
931 cuts[2].old_dst = 5;
932 cuts[2].old_src = 4;
933 cuts[2].new_vertex = 7;
934 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
935
936 // Supplier of temp block:
937 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE);
938
939 // Specify the final order:
940 vector<Vertex::Index> op_indexes;
941 op_indexes.push_back(2);
942 op_indexes.push_back(0);
943 op_indexes.push_back(1);
944 op_indexes.push_back(6);
945 op_indexes.push_back(3);
946 op_indexes.push_back(7);
947 op_indexes.push_back(4);
948 op_indexes.push_back(5);
949 op_indexes.push_back(8);
950
951 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
952 DeltaDiffGenerator::GenerateReverseTopoOrderMap(op_indexes,
953 &reverse_op_indexes);
954
955 // Prepare the filesystem with the minimum required for this to work
956 string temp_dir;
957 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksReuseTest.XXXXXX",
958 &temp_dir));
959 ScopedDirRemover temp_dir_remover(temp_dir);
960
961 const size_t kBlockSize = 4096;
962 vector<char> temp_data(kBlockSize * 3);
963 FillWithData(&temp_data);
964 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
965 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
966
967 int fd;
968 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksReuseTest.XXXXXX",
969 NULL,
970 &fd));
971 ScopedFdCloser fd_closer(&fd);
972 off_t data_file_size = 0;
Thieu Le5c7d9752010-12-15 16:09:28 -0800973
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700974 EXPECT_TRUE(DeltaDiffGenerator::AssignTempBlocks(&graph,
975 temp_dir,
976 fd,
977 &data_file_size,
978 &op_indexes,
979 &reverse_op_indexes,
980 cuts));
981 EXPECT_FALSE(graph[6].valid);
982 EXPECT_FALSE(graph[7].valid);
983 EXPECT_EQ(1, graph[1].op.src_extents_size());
984 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block());
985 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks());
986 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type());
987}
988
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800989TEST_F(DeltaDiffGeneratorTest, CreateScratchNodeTest) {
990 Vertex vertex;
991 DeltaDiffGenerator::CreateScratchNode(12, 34, &vertex);
992 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ,
993 vertex.op.type());
994 EXPECT_EQ(0, vertex.op.data_offset());
995 EXPECT_EQ(0, vertex.op.data_length());
996 EXPECT_EQ(1, vertex.op.dst_extents_size());
997 EXPECT_EQ(12, vertex.op.dst_extents(0).start_block());
998 EXPECT_EQ(34, vertex.op.dst_extents(0).num_blocks());
999}
1000
adlr@google.com3defe6a2009-12-04 20:57:17 +00001001} // namespace chromeos_update_engine