blob: 181fd27663c872f671223c6a1a53ce7b46a30c74 [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 Petkov94817cb2013-05-08 14:33:24 +0200660// Test that sparse holes are not used as scratch. More specifically, test that
661// if all full operations write to sparse holes and there's no extra scratch
662// space, delta operations that need scratch are converted to full. See
663// crbug.com/238440.
664TEST_F(DeltaDiffGeneratorTest, RunAsRootNoSparseAsTempTest) {
665 Graph graph(3);
666 const vector<Extent> kEmpty;
667 const string kFilename = "/foo";
668
669 // Make sure this sparse hole is not used as scratch.
670 GenVertex(&graph[0], kEmpty, VectOfExt(kSparseHole, 1), "", OP_REPLACE);
671
672 // Create a single-block cycle.
673 GenVertex(&graph[1], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_BSDIFF);
674 graph[1].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
675 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(0, 1), kFilename, OP_BSDIFF);
676 graph[2].out_edges[1] = EdgeWithReadDep(VectOfExt(0, 1));
677
678 graph_utils::DumpGraph(graph);
679
680 vector<Vertex::Index> final_order;
681
682 // Prepare the filesystem with the minimum required for this to work.
683 string temp_dir;
684 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/NoSparseAsTempTest.XXXXXX",
685 &temp_dir));
686 ScopedDirRemover temp_dir_remover(temp_dir);
687
688 const size_t kBlockSize = 4096;
689 vector<char> temp_data(kBlockSize);
690 FillWithData(&temp_data);
691 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
692 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
693
694 int fd = -1;
695 EXPECT_TRUE(utils::MakeTempFile("/tmp/NoSparseAsTempTestData.XXXXXX",
696 NULL,
697 &fd));
698 ScopedFdCloser fd_closer(&fd);
699 off_t data_file_size = 0;
700
701 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
702 temp_dir,
703 fd,
704 &data_file_size,
705 &final_order,
706 Vertex::kInvalidIndex));
707
708 ASSERT_EQ(4, graph.size());
709
710 // The second BSDIFF operation must have been converted to a full operation
711 // (due to insufficient scratch space).
712 EXPECT_TRUE(graph[2].op.type() == OP_REPLACE ||
713 graph[2].op.type() == OP_REPLACE_BZ);
714
715 // The temporary node created for breaking the cycle must have been marked as
716 // invalid.
717 EXPECT_FALSE(graph[3].valid);
718}
719
720// Test that sparse holes are not used as scratch. More specifically, test that
721// if scratch space comes only from full operations writing to real blocks as
722// well as sparse holes, only the real blocks are utilized. See
723// crbug.com/238440.
724TEST_F(DeltaDiffGeneratorTest, NoSparseAsTempTest) {
725 Graph graph;
726 vector<Block> blocks(4);
727
728 // Create nodes in |graph|.
729 {
730 graph.resize(graph.size() + 1);
731 graph.back().op.set_type(
732 DeltaArchiveManifest_InstallOperation_Type_REPLACE);
733
734 // Write to a sparse hole -- basically a no-op to ensure sparse holes are
735 // not used as scratch.
736 vector<Extent> extents;
737 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
738 DeltaDiffGenerator::StoreExtents(extents,
739 graph.back().op.mutable_dst_extents());
740 }
741 {
742 graph.resize(graph.size() + 1);
743 graph.back().op.set_type(OP_REPLACE);
744
745 // Scratch space: write to block 0 with sparse holes around.
746 vector<Extent> extents;
747 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
748 graph_utils::AppendBlockToExtents(&extents, 0);
749 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
750 DeltaDiffGenerator::StoreExtents(extents,
751 graph.back().op.mutable_dst_extents());
752 blocks[0].writer = graph.size() - 1;
753 }
754 {
755 graph.resize(graph.size() + 1);
756 graph.back().op.set_type(OP_REPLACE);
757
758 // Write to a sparse hole.
759 vector<Extent> extents;
760 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
761 DeltaDiffGenerator::StoreExtents(extents,
762 graph.back().op.mutable_dst_extents());
763 }
764 // Create a two-node cycle between (2, sparse, sparse) and (1, sparse, 3).
765 {
766 graph.resize(graph.size() + 1);
767 graph.back().op.set_type(OP_MOVE);
768 // Read from (2, sparse, sparse).
769 vector<Extent> extents;
770 graph_utils::AppendBlockToExtents(&extents, 2);
771 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
772 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
773 DeltaDiffGenerator::StoreExtents(extents,
774 graph.back().op.mutable_src_extents());
775 blocks[2].reader = graph.size() - 1;
776
777 // Write to (1, sparse, 3).
778 extents.clear();
779 graph_utils::AppendBlockToExtents(&extents, 1);
780 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
781 graph_utils::AppendBlockToExtents(&extents, 3);
782 DeltaDiffGenerator::StoreExtents(extents,
783 graph.back().op.mutable_dst_extents());
784 blocks[1].writer = graph.size() - 1;
785 blocks[3].writer = graph.size() - 1;
786 }
787 {
788 graph.resize(graph.size() + 1);
789 graph.back().op.set_type(OP_MOVE);
790 // Read from (1, sparse, 3).
791 vector<Extent> extents;
792 graph_utils::AppendBlockToExtents(&extents, 1);
793 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
794 graph_utils::AppendBlockToExtents(&extents, 3);
795 DeltaDiffGenerator::StoreExtents(extents,
796 graph.back().op.mutable_src_extents());
797 blocks[1].reader = graph.size() - 1;
798 blocks[3].reader = graph.size() - 1;
799
800 // Write to (2, sparse, sparse).
801 extents.clear();
802 graph_utils::AppendBlockToExtents(&extents, 2);
803 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
804 graph_utils::AppendBlockToExtents(&extents, kSparseHole);
805 DeltaDiffGenerator::StoreExtents(extents,
806 graph.back().op.mutable_dst_extents());
807 blocks[2].writer = graph.size() - 1;
808 }
809
810 graph_utils::DumpGraph(graph);
811
812 // Create edges
813 DeltaDiffGenerator::CreateEdges(&graph, blocks);
814
815 graph_utils::DumpGraph(graph);
816
817 vector<Vertex::Index> final_order;
818 off_t data_file_size = 0;
819 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph,
820 "/non/existent/dir",
821 -1,
822 &data_file_size,
823 &final_order,
824 Vertex::kInvalidIndex));
825
826 // Check for a single temporary node writing to scratch.
827 ASSERT_EQ(6, graph.size());
828 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
829 graph[5].op.type());
830 EXPECT_EQ(1, graph[5].op.src_extents_size());
831 ASSERT_EQ(1, graph[5].op.dst_extents_size());
832 EXPECT_EQ(0, graph[5].op.dst_extents(0).start_block());
833 EXPECT_EQ(1, graph[5].op.dst_extents(0).num_blocks());
834
835 // Make sure the cycle nodes still read from and write to sparse holes.
836 for (int i = 3; i < 5; i++) {
837 ASSERT_GE(graph[i].op.src_extents_size(), 2);
838 EXPECT_EQ(kSparseHole, graph[i].op.src_extents(1).start_block());
839 ASSERT_GE(graph[i].op.dst_extents_size(), 2);
840 EXPECT_EQ(kSparseHole, graph[i].op.dst_extents(1).start_block());
841 }
842}
843
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700844TEST_F(DeltaDiffGeneratorTest, IsNoopOperationTest) {
845 DeltaArchiveManifest_InstallOperation op;
846 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
847 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
848 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
849 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
850 *(op.add_src_extents()) = ExtentForRange(3, 2);
851 *(op.add_dst_extents()) = ExtentForRange(3, 2);
852 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
853 *(op.add_src_extents()) = ExtentForRange(7, 5);
854 *(op.add_dst_extents()) = ExtentForRange(7, 5);
855 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
856 *(op.add_src_extents()) = ExtentForRange(20, 2);
857 *(op.add_dst_extents()) = ExtentForRange(20, 1);
858 *(op.add_dst_extents()) = ExtentForRange(21, 1);
859 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
860 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 2);
861 *(op.add_src_extents()) = ExtentForRange(kSparseHole, 1);
862 *(op.add_dst_extents()) = ExtentForRange(kSparseHole, 3);
863 EXPECT_TRUE(DeltaDiffGenerator::IsNoopOperation(op));
864 *(op.add_src_extents()) = ExtentForRange(24, 1);
865 *(op.add_dst_extents()) = ExtentForRange(25, 1);
866 EXPECT_FALSE(DeltaDiffGenerator::IsNoopOperation(op));
867}
868
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700869TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksReuseTest) {
870 // AssignTempBlocks(Graph* graph,
871 // const string& new_root,
872 // int data_fd,
873 // off_t* data_file_size,
874 // vector<Vertex::Index>* op_indexes,
875 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
876 // const vector<CutEdgeVertexes>& cuts
877 Graph graph(9);
878
879 const vector<Extent> empt;
880 uint64_t tmp = kTempBlockStart;
881 const string kFilename = "/foo";
882
883 vector<CutEdgeVertexes> cuts;
884 cuts.resize(3);
885
886 // Simple broken loop:
887 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE);
888 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE);
889 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE);
890 // Corresponding edges:
891 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
892 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
893 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
894 // Store the cut:
895 cuts[0].old_dst = 1;
896 cuts[0].old_src = 0;
897 cuts[0].new_vertex = 2;
898 cuts[0].tmp_extents = VectOfExt(tmp, 1);
899 tmp++;
900
901 // Slightly more complex pair of loops:
902 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE);
903 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE);
904 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE);
905 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE);
906 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE);
907 // Corresponding edges:
908 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
909 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
910 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
911 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
912 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
913 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
914 // Store the cuts:
915 cuts[1].old_dst = 5;
916 cuts[1].old_src = 3;
917 cuts[1].new_vertex = 6;
918 cuts[1].tmp_extents = VectOfExt(tmp, 2);
919 cuts[2].old_dst = 5;
920 cuts[2].old_src = 4;
921 cuts[2].new_vertex = 7;
922 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
923
924 // Supplier of temp block:
925 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE);
926
927 // Specify the final order:
928 vector<Vertex::Index> op_indexes;
929 op_indexes.push_back(2);
930 op_indexes.push_back(0);
931 op_indexes.push_back(1);
932 op_indexes.push_back(6);
933 op_indexes.push_back(3);
934 op_indexes.push_back(7);
935 op_indexes.push_back(4);
936 op_indexes.push_back(5);
937 op_indexes.push_back(8);
938
939 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
940 DeltaDiffGenerator::GenerateReverseTopoOrderMap(op_indexes,
941 &reverse_op_indexes);
942
943 // Prepare the filesystem with the minimum required for this to work
944 string temp_dir;
945 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksReuseTest.XXXXXX",
946 &temp_dir));
947 ScopedDirRemover temp_dir_remover(temp_dir);
948
949 const size_t kBlockSize = 4096;
950 vector<char> temp_data(kBlockSize * 3);
951 FillWithData(&temp_data);
952 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data));
953 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename);
954
955 int fd;
956 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksReuseTest.XXXXXX",
957 NULL,
958 &fd));
959 ScopedFdCloser fd_closer(&fd);
960 off_t data_file_size = 0;
Thieu Le5c7d9752010-12-15 16:09:28 -0800961
Andrew de los Reyes4ba850d2010-10-25 12:12:40 -0700962 EXPECT_TRUE(DeltaDiffGenerator::AssignTempBlocks(&graph,
963 temp_dir,
964 fd,
965 &data_file_size,
966 &op_indexes,
967 &reverse_op_indexes,
968 cuts));
969 EXPECT_FALSE(graph[6].valid);
970 EXPECT_FALSE(graph[7].valid);
971 EXPECT_EQ(1, graph[1].op.src_extents_size());
972 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block());
973 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks());
974 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type());
975}
976
Andrew de los Reyes927179d2010-12-02 11:26:48 -0800977TEST_F(DeltaDiffGeneratorTest, CreateScratchNodeTest) {
978 Vertex vertex;
979 DeltaDiffGenerator::CreateScratchNode(12, 34, &vertex);
980 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ,
981 vertex.op.type());
982 EXPECT_EQ(0, vertex.op.data_offset());
983 EXPECT_EQ(0, vertex.op.data_length());
984 EXPECT_EQ(1, vertex.op.dst_extents_size());
985 EXPECT_EQ(12, vertex.op.dst_extents(0).start_block());
986 EXPECT_EQ(34, vertex.op.dst_extents(0).num_blocks());
987}
988
adlr@google.com3defe6a2009-12-04 20:57:17 +0000989} // namespace chromeos_update_engine