blob: 50f1180440f29b97e6a00f9ffc5fa234c70dd899 [file] [log] [blame]
adlr@google.com3defe6a2009-12-04 20:57:17 +00001// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// 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>
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -08009#include <set>
adlr@google.com3defe6a2009-12-04 20:57:17 +000010#include <string>
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070011#include <utility>
adlr@google.com3defe6a2009-12-04 20:57:17 +000012#include <vector>
adlr@google.com3defe6a2009-12-04 20:57:17 +000013#include <gtest/gtest.h>
14#include "chromeos/obsolete_logging.h"
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070015#include "update_engine/cycle_breaker.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000016#include "update_engine/delta_diff_generator.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070017#include "update_engine/delta_performer.h"
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070018#include "update_engine/graph_types.h"
19#include "update_engine/graph_utils.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000020#include "update_engine/subprocess.h"
21#include "update_engine/test_utils.h"
22#include "update_engine/utils.h"
23
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070024using std::make_pair;
25using std::set;
26using std::string;
27using std::vector;
28
adlr@google.com3defe6a2009-12-04 20:57:17 +000029namespace chromeos_update_engine {
30
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070031typedef DeltaDiffGenerator::Block Block;
32
33namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070034int64_t BlocksInExtents(
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070035 const google::protobuf::RepeatedPtrField<Extent>& extents) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070036 int64_t ret = 0;
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070037 for (int i = 0; i < extents.size(); i++) {
38 ret += extents.Get(i).num_blocks();
39 }
40 return ret;
41}
42} // namespace {}
43
44class DeltaDiffGeneratorTest : public ::testing::Test {
45 protected:
46 const string old_path() { return "DeltaDiffGeneratorTest-old_path"; }
47 const string new_path() { return "DeltaDiffGeneratorTest-new_path"; }
48 virtual void TearDown() {
49 unlink(old_path().c_str());
50 unlink(new_path().c_str());
51 }
52};
53
54TEST_F(DeltaDiffGeneratorTest, RunAsRootMoveSmallTest) {
55 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
56 reinterpret_cast<const char*>(kRandomString),
57 sizeof(kRandomString)));
58 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
59 reinterpret_cast<const char*>(kRandomString),
60 sizeof(kRandomString)));
61 vector<char> data;
62 DeltaArchiveManifest_InstallOperation op;
63 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
64 new_path(),
65 &data,
66 &op));
67 EXPECT_TRUE(data.empty());
68
69 EXPECT_TRUE(op.has_type());
70 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, op.type());
71 EXPECT_FALSE(op.has_data_offset());
72 EXPECT_FALSE(op.has_data_length());
73 EXPECT_EQ(1, op.src_extents_size());
74 EXPECT_EQ(sizeof(kRandomString), op.src_length());
75 EXPECT_EQ(1, op.dst_extents_size());
76 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
77 EXPECT_EQ(BlocksInExtents(op.src_extents()),
78 BlocksInExtents(op.dst_extents()));
79 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
80}
81
82TEST_F(DeltaDiffGeneratorTest, RunAsRootBsdiffSmallTest) {
83 EXPECT_TRUE(utils::WriteFile(old_path().c_str(),
84 reinterpret_cast<const char*>(kRandomString),
85 sizeof(kRandomString) - 1));
86 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
87 reinterpret_cast<const char*>(kRandomString),
88 sizeof(kRandomString)));
89 vector<char> data;
90 DeltaArchiveManifest_InstallOperation op;
91 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
92 new_path(),
93 &data,
94 &op));
95 EXPECT_FALSE(data.empty());
96
97 EXPECT_TRUE(op.has_type());
98 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_BSDIFF, op.type());
99 EXPECT_FALSE(op.has_data_offset());
100 EXPECT_FALSE(op.has_data_length());
101 EXPECT_EQ(1, op.src_extents_size());
102 EXPECT_EQ(sizeof(kRandomString) - 1, op.src_length());
103 EXPECT_EQ(1, op.dst_extents_size());
104 EXPECT_EQ(sizeof(kRandomString), op.dst_length());
105 EXPECT_EQ(BlocksInExtents(op.src_extents()),
106 BlocksInExtents(op.dst_extents()));
107 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
108}
109
110TEST_F(DeltaDiffGeneratorTest, RunAsRootReplaceSmallTest) {
111 vector<char> new_data;
112 for (int i = 0; i < 2; i++) {
113 new_data.insert(new_data.end(),
114 kRandomString,
115 kRandomString + sizeof(kRandomString));
116 EXPECT_TRUE(utils::WriteFile(new_path().c_str(),
117 &new_data[0],
118 new_data.size()));
119 vector<char> data;
120 DeltaArchiveManifest_InstallOperation op;
121 EXPECT_TRUE(DeltaDiffGenerator::ReadFileToDiff(old_path(),
122 new_path(),
123 &data,
124 &op));
125 EXPECT_FALSE(data.empty());
126
127 EXPECT_TRUE(op.has_type());
128 const DeltaArchiveManifest_InstallOperation_Type expected_type =
129 (i == 0 ? DeltaArchiveManifest_InstallOperation_Type_REPLACE :
130 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
131 EXPECT_EQ(expected_type, op.type());
132 EXPECT_FALSE(op.has_data_offset());
133 EXPECT_FALSE(op.has_data_length());
134 EXPECT_EQ(0, op.src_extents_size());
135 EXPECT_FALSE(op.has_src_length());
136 EXPECT_EQ(1, op.dst_extents_size());
137 EXPECT_EQ(new_data.size(), op.dst_length());
138 EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
139 }
140}
141
142namespace {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700143void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700144 vect->resize(vect->size() + 1);
145 vect->back().set_start_block(start);
146 vect->back().set_num_blocks(length);
147}
148void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700149 uint64_t start,
150 uint64_t length) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700151 Extent* extent = op->add_src_extents();
152 extent->set_start_block(start);
153 extent->set_num_blocks(length);
154}
155}
156
157TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
158 vector<Extent> remove_blocks;
159 AppendExtent(&remove_blocks, 3, 3);
160 AppendExtent(&remove_blocks, 7, 1);
161 vector<Extent> replace_blocks;
162 AppendExtent(&replace_blocks, 10, 2);
163 AppendExtent(&replace_blocks, 13, 2);
164 DeltaArchiveManifest_InstallOperation op;
165 OpAppendExtent(&op, 4, 3);
166 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
167 OpAppendExtent(&op, 3, 1);
168 OpAppendExtent(&op, 7, 3);
169
170 DeltaDiffGenerator::SubstituteBlocks(&op, remove_blocks, replace_blocks);
171
172 EXPECT_EQ(7, op.src_extents_size());
173 EXPECT_EQ(11, op.src_extents(0).start_block());
174 EXPECT_EQ(1, op.src_extents(0).num_blocks());
175 EXPECT_EQ(13, op.src_extents(1).start_block());
176 EXPECT_EQ(1, op.src_extents(1).num_blocks());
177 EXPECT_EQ(6, op.src_extents(2).start_block());
178 EXPECT_EQ(1, op.src_extents(2).num_blocks());
179 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
180 EXPECT_EQ(4, op.src_extents(3).num_blocks());
181 EXPECT_EQ(10, op.src_extents(4).start_block());
182 EXPECT_EQ(1, op.src_extents(4).num_blocks());
183 EXPECT_EQ(14, op.src_extents(5).start_block());
184 EXPECT_EQ(1, op.src_extents(5).num_blocks());
185 EXPECT_EQ(8, op.src_extents(6).start_block());
186 EXPECT_EQ(2, op.src_extents(6).num_blocks());
187}
188
189TEST_F(DeltaDiffGeneratorTest, CutEdgesTest) {
190 Graph graph;
191 vector<Block> blocks(9);
192
193 // Create nodes in graph
194 {
195 graph.resize(graph.size() + 1);
196 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
197 // Reads from blocks 3, 5, 7
198 vector<Extent> extents;
199 graph_utils::AppendBlockToExtents(&extents, 3);
200 graph_utils::AppendBlockToExtents(&extents, 5);
201 graph_utils::AppendBlockToExtents(&extents, 7);
202 DeltaDiffGenerator::StoreExtents(extents,
203 graph.back().op.mutable_src_extents());
204 blocks[3].reader = graph.size() - 1;
205 blocks[5].reader = graph.size() - 1;
206 blocks[7].reader = graph.size() - 1;
207
208 // Writes to blocks 1, 2, 4
209 extents.clear();
210 graph_utils::AppendBlockToExtents(&extents, 1);
211 graph_utils::AppendBlockToExtents(&extents, 2);
212 graph_utils::AppendBlockToExtents(&extents, 4);
213 DeltaDiffGenerator::StoreExtents(extents,
214 graph.back().op.mutable_dst_extents());
215 blocks[1].writer = graph.size() - 1;
216 blocks[2].writer = graph.size() - 1;
217 blocks[4].writer = graph.size() - 1;
218 }
219 {
220 graph.resize(graph.size() + 1);
221 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
222 // Reads from blocks 1, 2, 4
223 vector<Extent> extents;
224 graph_utils::AppendBlockToExtents(&extents, 1);
225 graph_utils::AppendBlockToExtents(&extents, 2);
226 graph_utils::AppendBlockToExtents(&extents, 4);
227 DeltaDiffGenerator::StoreExtents(extents,
228 graph.back().op.mutable_src_extents());
229 blocks[1].reader = graph.size() - 1;
230 blocks[2].reader = graph.size() - 1;
231 blocks[4].reader = graph.size() - 1;
232
233 // Writes to blocks 3, 5, 6
234 extents.clear();
235 graph_utils::AppendBlockToExtents(&extents, 3);
236 graph_utils::AppendBlockToExtents(&extents, 5);
237 graph_utils::AppendBlockToExtents(&extents, 6);
238 DeltaDiffGenerator::StoreExtents(extents,
239 graph.back().op.mutable_dst_extents());
240 blocks[3].writer = graph.size() - 1;
241 blocks[5].writer = graph.size() - 1;
242 blocks[6].writer = graph.size() - 1;
243 }
244
245 // Create edges
246 DeltaDiffGenerator::CreateEdges(&graph, blocks);
247
248 // Find cycles
249 CycleBreaker cycle_breaker;
250 set<Edge> cut_edges;
251 cycle_breaker.BreakCycles(graph, &cut_edges);
252
253 EXPECT_EQ(1, cut_edges.size());
254 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
255 0)));
256
257 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, blocks, cut_edges));
258
259 EXPECT_EQ(3, graph.size());
260
261 // Check new node in graph:
262 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE,
263 graph.back().op.type());
264 EXPECT_EQ(2, graph.back().op.src_extents_size());
265 EXPECT_EQ(2, graph.back().op.dst_extents_size());
266 EXPECT_EQ(0, graph.back().op.dst_extents(0).start_block());
267 EXPECT_EQ(1, graph.back().op.dst_extents(0).num_blocks());
268 EXPECT_EQ(8, graph.back().op.dst_extents(1).start_block());
269 EXPECT_EQ(1, graph.back().op.dst_extents(1).num_blocks());
270 EXPECT_TRUE(graph.back().out_edges.empty());
271
272 // Check that old node reads from new blocks
273 EXPECT_EQ(3, graph[0].op.src_extents_size());
274 EXPECT_EQ(0, graph[0].op.src_extents(0).start_block());
275 EXPECT_EQ(1, graph[0].op.src_extents(0).num_blocks());
276 EXPECT_EQ(8, graph[0].op.src_extents(1).start_block());
277 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks());
278 EXPECT_EQ(7, graph[0].op.src_extents(2).start_block());
279 EXPECT_EQ(1, graph[0].op.src_extents(2).num_blocks());
280
281 // And that the old dst extents haven't changed
282 EXPECT_EQ(2, graph[0].op.dst_extents_size());
283 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block());
284 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks());
285 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block());
286 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks());
287
288 // Ensure it only depends on the next node
289 EXPECT_EQ(1, graph[0].out_edges.size());
290 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
291
292 // Check second node has unchanged extents
293 EXPECT_EQ(2, graph[1].op.src_extents_size());
294 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block());
295 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks());
296 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block());
297 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks());
298
299 EXPECT_EQ(2, graph[1].op.dst_extents_size());
300 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block());
301 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks());
302 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block());
303 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks());
304
305 // Ensure it only depends on the next node
306 EXPECT_EQ(1, graph[1].out_edges.size());
307 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
308}
309
310TEST_F(DeltaDiffGeneratorTest, ReorderBlobsTest) {
311 string orig_blobs;
312 EXPECT_TRUE(
313 utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs, NULL));
314
315 string orig_data = "abcd";
316 EXPECT_TRUE(
317 utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
318
319 string new_blobs;
320 EXPECT_TRUE(
321 utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, NULL));
322
323 DeltaArchiveManifest manifest;
324 DeltaArchiveManifest_InstallOperation* op =
325 manifest.add_install_operations();
326 op->set_data_offset(1);
327 op->set_data_length(3);
328 op = manifest.add_install_operations();
329 op->set_data_offset(0);
330 op->set_data_length(1);
331
332 EXPECT_TRUE(DeltaDiffGenerator::ReorderDataBlobs(&manifest,
333 orig_blobs,
334 new_blobs));
335
336 string new_data;
337 EXPECT_TRUE(utils::ReadFileToString(new_blobs, &new_data));
338 EXPECT_EQ("bcda", new_data);
339 EXPECT_EQ(2, manifest.install_operations_size());
340 EXPECT_EQ(0, manifest.install_operations(0).data_offset());
341 EXPECT_EQ(3, manifest.install_operations(0).data_length());
342 EXPECT_EQ(3, manifest.install_operations(1).data_offset());
343 EXPECT_EQ(1, manifest.install_operations(1).data_length());
344
345 unlink(orig_blobs.c_str());
346 unlink(new_blobs.c_str());
347}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000348
349} // namespace chromeos_update_engine