ab_generator_unittest.cc revision 14158570d3995008dc93a628004118b87a6bca01
1// Copyright 2015 The Chromium OS 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 "update_engine/payload_generator/ab_generator.h"
6
7#include <fcntl.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10
11#include <string>
12#include <vector>
13
14#include <gtest/gtest.h>
15
16#include "update_engine/bzip.h"
17#include "update_engine/payload_generator/annotated_operation.h"
18#include "update_engine/payload_generator/delta_diff_generator.h"
19#include "update_engine/payload_generator/extent_ranges.h"
20#include "update_engine/payload_generator/extent_utils.h"
21#include "update_engine/test_utils.h"
22#include "update_engine/utils.h"
23
24using std::string;
25using std::vector;
26
27namespace chromeos_update_engine {
28
29namespace {
30
31bool ExtentEquals(Extent ext, uint64_t start_block, uint64_t num_blocks) {
32  return ext.start_block() == start_block && ext.num_blocks() == num_blocks;
33}
34
35// Tests splitting of a REPLACE/REPLACE_BZ operation.
36void TestSplitReplaceOrReplaceBzOperation(
37    DeltaArchiveManifest_InstallOperation_Type orig_type,
38    bool compressible) {
39  const size_t op_ex1_start_block = 2;
40  const size_t op_ex1_num_blocks = 2;
41  const size_t op_ex2_start_block = 6;
42  const size_t op_ex2_num_blocks = 1;
43  const size_t part_num_blocks = 7;
44
45  // Create the target partition data.
46  string part_path;
47  EXPECT_TRUE(utils::MakeTempFile(
48      "SplitReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
49  ScopedPathUnlinker part_path_unlinker(part_path);
50  const size_t part_size = part_num_blocks * kBlockSize;
51  chromeos::Blob part_data;
52  if (compressible) {
53    part_data.resize(part_size);
54    test_utils::FillWithData(&part_data);
55  } else {
56    std::mt19937 gen(12345);
57    std::uniform_int_distribution<uint8_t> dis(0, 255);
58    for (uint32_t i = 0; i < part_size; i++)
59      part_data.push_back(dis(gen));
60  }
61  ASSERT_EQ(part_size, part_data.size());
62  ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
63
64  // Create original operation and blob data.
65  const size_t op_ex1_offset = op_ex1_start_block * kBlockSize;
66  const size_t op_ex1_size = op_ex1_num_blocks * kBlockSize;
67  const size_t op_ex2_offset = op_ex2_start_block * kBlockSize;
68  const size_t op_ex2_size = op_ex2_num_blocks * kBlockSize;
69  DeltaArchiveManifest_InstallOperation op;
70  op.set_type(orig_type);
71  *(op.add_dst_extents()) = ExtentForRange(op_ex1_start_block,
72                                           op_ex1_num_blocks);
73  *(op.add_dst_extents()) = ExtentForRange(op_ex2_start_block,
74                                           op_ex2_num_blocks);
75  op.set_dst_length(op_ex1_num_blocks + op_ex2_num_blocks);
76
77  chromeos::Blob op_data;
78  op_data.insert(op_data.end(),
79                 part_data.begin() + op_ex1_offset,
80                 part_data.begin() + op_ex1_offset + op_ex1_size);
81  op_data.insert(op_data.end(),
82                 part_data.begin() + op_ex2_offset,
83                 part_data.begin() + op_ex2_offset + op_ex2_size);
84  chromeos::Blob op_blob;
85  if (orig_type == DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
86    op_blob = op_data;
87  } else {
88    ASSERT_TRUE(BzipCompress(op_data, &op_blob));
89  }
90  op.set_data_offset(0);
91  op.set_data_length(op_blob.size());
92
93  AnnotatedOperation aop;
94  aop.op = op;
95  aop.name = "SplitTestOp";
96
97  // Create the data file.
98  string data_path;
99  EXPECT_TRUE(utils::MakeTempFile(
100      "SplitReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr));
101  ScopedPathUnlinker data_path_unlinker(data_path);
102  int data_fd = open(data_path.c_str(), O_RDWR, 000);
103  EXPECT_GE(data_fd, 0);
104  ScopedFdCloser data_fd_closer(&data_fd);
105  EXPECT_TRUE(utils::WriteFile(data_path.c_str(), op_blob.data(),
106                               op_blob.size()));
107  off_t data_file_size = op_blob.size();
108
109  // Split the operation.
110  vector<AnnotatedOperation> result_ops;
111  ASSERT_TRUE(ABGenerator::SplitReplaceOrReplaceBz(
112          aop, &result_ops, part_path, data_fd, &data_file_size));
113
114  // Check the result.
115  DeltaArchiveManifest_InstallOperation_Type expected_type =
116      compressible ?
117      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ :
118      DeltaArchiveManifest_InstallOperation_Type_REPLACE;
119
120  ASSERT_EQ(2, result_ops.size());
121
122  EXPECT_EQ("SplitTestOp:0", result_ops[0].name);
123  DeltaArchiveManifest_InstallOperation first_op = result_ops[0].op;
124  EXPECT_EQ(expected_type, first_op.type());
125  EXPECT_EQ(op_ex1_size, first_op.dst_length());
126  EXPECT_EQ(1, first_op.dst_extents().size());
127  EXPECT_TRUE(ExtentEquals(first_op.dst_extents(0), op_ex1_start_block,
128                           op_ex1_num_blocks));
129  // Obtain the expected blob.
130  chromeos::Blob first_expected_data(
131      part_data.begin() + op_ex1_offset,
132      part_data.begin() + op_ex1_offset + op_ex1_size);
133  chromeos::Blob first_expected_blob;
134  if (compressible) {
135    ASSERT_TRUE(BzipCompress(first_expected_data, &first_expected_blob));
136  } else {
137    first_expected_blob = first_expected_data;
138  }
139  EXPECT_EQ(first_expected_blob.size(), first_op.data_length());
140  // Check that the actual blob matches what's expected.
141  chromeos::Blob first_data_blob(first_op.data_length());
142  ssize_t bytes_read;
143  ASSERT_TRUE(utils::PReadAll(data_fd,
144                              first_data_blob.data(),
145                              first_op.data_length(),
146                              first_op.data_offset(),
147                              &bytes_read));
148  ASSERT_EQ(bytes_read, first_op.data_length());
149  EXPECT_EQ(first_expected_blob, first_data_blob);
150
151  EXPECT_EQ("SplitTestOp:1", result_ops[1].name);
152  DeltaArchiveManifest_InstallOperation second_op = result_ops[1].op;
153  EXPECT_EQ(expected_type, second_op.type());
154  EXPECT_EQ(op_ex2_size, second_op.dst_length());
155  EXPECT_EQ(1, second_op.dst_extents().size());
156  EXPECT_TRUE(ExtentEquals(second_op.dst_extents(0), op_ex2_start_block,
157                           op_ex2_num_blocks));
158  // Obtain the expected blob.
159  chromeos::Blob second_expected_data(
160      part_data.begin() + op_ex2_offset,
161      part_data.begin() + op_ex2_offset + op_ex2_size);
162  chromeos::Blob second_expected_blob;
163  if (compressible) {
164    ASSERT_TRUE(BzipCompress(second_expected_data, &second_expected_blob));
165  } else {
166    second_expected_blob = second_expected_data;
167  }
168  EXPECT_EQ(second_expected_blob.size(), second_op.data_length());
169  // Check that the actual blob matches what's expected.
170  chromeos::Blob second_data_blob(second_op.data_length());
171  ASSERT_TRUE(utils::PReadAll(data_fd,
172                              second_data_blob.data(),
173                              second_op.data_length(),
174                              second_op.data_offset(),
175                              &bytes_read));
176  ASSERT_EQ(bytes_read, second_op.data_length());
177  EXPECT_EQ(second_expected_blob, second_data_blob);
178
179  // Check relative layout of data blobs.
180  EXPECT_EQ(first_op.data_offset() + first_op.data_length(),
181            second_op.data_offset());
182  EXPECT_EQ(second_op.data_offset() + second_op.data_length(), data_file_size);
183  // If we split a REPLACE into multiple ones, ensure reuse of preexisting blob.
184  if (!compressible &&
185      orig_type == DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
186    EXPECT_EQ(0, first_op.data_offset());
187  }
188}
189
190// Tests merging of REPLACE/REPLACE_BZ operations.
191void TestMergeReplaceOrReplaceBzOperations(
192    DeltaArchiveManifest_InstallOperation_Type orig_type,
193    bool compressible) {
194  const size_t first_op_num_blocks = 1;
195  const size_t second_op_num_blocks = 2;
196  const size_t total_op_num_blocks = first_op_num_blocks + second_op_num_blocks;
197  const size_t part_num_blocks = total_op_num_blocks + 2;
198
199  // Create the target partition data.
200  string part_path;
201  EXPECT_TRUE(utils::MakeTempFile(
202      "MergeReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
203  ScopedPathUnlinker part_path_unlinker(part_path);
204  const size_t part_size = part_num_blocks * kBlockSize;
205  chromeos::Blob part_data;
206  if (compressible) {
207    part_data.resize(part_size);
208    test_utils::FillWithData(&part_data);
209  } else {
210    std::mt19937 gen(12345);
211    std::uniform_int_distribution<uint8_t> dis(0, 255);
212    for (uint32_t i = 0; i < part_size; i++)
213      part_data.push_back(dis(gen));
214  }
215  ASSERT_EQ(part_size, part_data.size());
216  ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
217
218  // Create original operations and blob data.
219  vector<AnnotatedOperation> aops;
220  chromeos::Blob blob_data;
221  const size_t total_op_size = total_op_num_blocks * kBlockSize;
222
223  DeltaArchiveManifest_InstallOperation first_op;
224  first_op.set_type(orig_type);
225  const size_t first_op_size = first_op_num_blocks * kBlockSize;
226  first_op.set_dst_length(first_op_size);
227  *(first_op.add_dst_extents()) = ExtentForRange(0, first_op_num_blocks);
228  chromeos::Blob first_op_data(part_data.begin(),
229                               part_data.begin() + first_op_size);
230  chromeos::Blob first_op_blob;
231  if (orig_type == DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
232    first_op_blob = first_op_data;
233  } else {
234    ASSERT_TRUE(BzipCompress(first_op_data, &first_op_blob));
235  }
236  first_op.set_data_offset(0);
237  first_op.set_data_length(first_op_blob.size());
238  blob_data.insert(blob_data.end(), first_op_blob.begin(), first_op_blob.end());
239  AnnotatedOperation first_aop;
240  first_aop.op = first_op;
241  first_aop.name = "first";
242  aops.push_back(first_aop);
243
244  DeltaArchiveManifest_InstallOperation second_op;
245  second_op.set_type(orig_type);
246  const size_t second_op_size = second_op_num_blocks * kBlockSize;
247  second_op.set_dst_length(second_op_size);
248  *(second_op.add_dst_extents()) = ExtentForRange(first_op_num_blocks,
249                                                  second_op_num_blocks);
250  chromeos::Blob second_op_data(part_data.begin() + first_op_size,
251                                part_data.begin() + total_op_size);
252  chromeos::Blob second_op_blob;
253  if (orig_type == DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
254    second_op_blob = second_op_data;
255  } else {
256    ASSERT_TRUE(BzipCompress(second_op_data, &second_op_blob));
257  }
258  second_op.set_data_offset(first_op_blob.size());
259  second_op.set_data_length(second_op_blob.size());
260  blob_data.insert(blob_data.end(), second_op_blob.begin(),
261                   second_op_blob.end());
262  AnnotatedOperation second_aop;
263  second_aop.op = second_op;
264  second_aop.name = "second";
265  aops.push_back(second_aop);
266
267  // Create the data file.
268  string data_path;
269  EXPECT_TRUE(utils::MakeTempFile(
270      "MergeReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr));
271  ScopedPathUnlinker data_path_unlinker(data_path);
272  int data_fd = open(data_path.c_str(), O_RDWR, 000);
273  EXPECT_GE(data_fd, 0);
274  ScopedFdCloser data_fd_closer(&data_fd);
275  EXPECT_TRUE(utils::WriteFile(data_path.c_str(), blob_data.data(),
276                               blob_data.size()));
277  off_t data_file_size = blob_data.size();
278
279  // Merge the operations.
280  EXPECT_TRUE(ABGenerator::MergeOperations(
281      &aops, 5 * kBlockSize, part_path, data_fd, &data_file_size));
282
283  // Check the result.
284  DeltaArchiveManifest_InstallOperation_Type expected_op_type =
285      compressible ?
286      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ :
287      DeltaArchiveManifest_InstallOperation_Type_REPLACE;
288  EXPECT_EQ(1, aops.size());
289  DeltaArchiveManifest_InstallOperation new_op = aops[0].op;
290  EXPECT_EQ(expected_op_type, new_op.type());
291  EXPECT_FALSE(new_op.has_src_length());
292  EXPECT_EQ(total_op_num_blocks * kBlockSize, new_op.dst_length());
293  EXPECT_EQ(1, new_op.dst_extents().size());
294  EXPECT_TRUE(ExtentEquals(new_op.dst_extents(0), 0, total_op_num_blocks));
295  EXPECT_EQ("first,second", aops[0].name);
296
297  // Check to see if the blob pointed to in the new extent has what we expect.
298  chromeos::Blob expected_data(part_data.begin(),
299                               part_data.begin() + total_op_size);
300  chromeos::Blob expected_blob;
301  if (compressible) {
302    ASSERT_TRUE(BzipCompress(expected_data, &expected_blob));
303  } else {
304    expected_blob = expected_data;
305  }
306  ASSERT_EQ(expected_blob.size(), new_op.data_length());
307  ASSERT_EQ(blob_data.size() + expected_blob.size(), data_file_size);
308  chromeos::Blob new_op_blob(new_op.data_length());
309  ssize_t bytes_read;
310  ASSERT_TRUE(utils::PReadAll(data_fd,
311                              new_op_blob.data(),
312                              new_op.data_length(),
313                              new_op.data_offset(),
314                              &bytes_read));
315  ASSERT_EQ(new_op.data_length(), bytes_read);
316  EXPECT_EQ(expected_blob, new_op_blob);
317}
318
319}  // namespace
320
321class ABGeneratorTest : public ::testing::Test {};
322
323TEST_F(ABGeneratorTest, SplitSourceCopyTest) {
324  DeltaArchiveManifest_InstallOperation op;
325  op.set_type(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY);
326  *(op.add_src_extents()) = ExtentForRange(2, 3);
327  *(op.add_src_extents()) = ExtentForRange(6, 1);
328  *(op.add_src_extents()) = ExtentForRange(8, 4);
329  *(op.add_dst_extents()) = ExtentForRange(10, 2);
330  *(op.add_dst_extents()) = ExtentForRange(14, 3);
331  *(op.add_dst_extents()) = ExtentForRange(18, 3);
332
333  AnnotatedOperation aop;
334  aop.op = op;
335  aop.name = "SplitSourceCopyTestOp";
336  vector<AnnotatedOperation> result_ops;
337  EXPECT_TRUE(ABGenerator::SplitSourceCopy(aop, &result_ops));
338  EXPECT_EQ(result_ops.size(), 3);
339
340  EXPECT_EQ("SplitSourceCopyTestOp:0", result_ops[0].name);
341  DeltaArchiveManifest_InstallOperation first_op = result_ops[0].op;
342  EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY,
343            first_op.type());
344  EXPECT_EQ(kBlockSize * 2, first_op.src_length());
345  EXPECT_EQ(1, first_op.src_extents().size());
346  EXPECT_EQ(2, first_op.src_extents(0).start_block());
347  EXPECT_EQ(2, first_op.src_extents(0).num_blocks());
348  EXPECT_EQ(kBlockSize * 2, first_op.dst_length());
349  EXPECT_EQ(1, first_op.dst_extents().size());
350  EXPECT_EQ(10, first_op.dst_extents(0).start_block());
351  EXPECT_EQ(2, first_op.dst_extents(0).num_blocks());
352
353  EXPECT_EQ("SplitSourceCopyTestOp:1", result_ops[1].name);
354  DeltaArchiveManifest_InstallOperation second_op = result_ops[1].op;
355  EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY,
356            second_op.type());
357  EXPECT_EQ(kBlockSize * 3, second_op.src_length());
358  EXPECT_EQ(3, second_op.src_extents().size());
359  EXPECT_EQ(4, second_op.src_extents(0).start_block());
360  EXPECT_EQ(1, second_op.src_extents(0).num_blocks());
361  EXPECT_EQ(6, second_op.src_extents(1).start_block());
362  EXPECT_EQ(1, second_op.src_extents(1).num_blocks());
363  EXPECT_EQ(8, second_op.src_extents(2).start_block());
364  EXPECT_EQ(1, second_op.src_extents(2).num_blocks());
365  EXPECT_EQ(kBlockSize * 3, second_op.dst_length());
366  EXPECT_EQ(1, second_op.dst_extents().size());
367  EXPECT_EQ(14, second_op.dst_extents(0).start_block());
368  EXPECT_EQ(3, second_op.dst_extents(0).num_blocks());
369
370  EXPECT_EQ("SplitSourceCopyTestOp:2", result_ops[2].name);
371  DeltaArchiveManifest_InstallOperation third_op = result_ops[2].op;
372  EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY,
373            third_op.type());
374  EXPECT_EQ(kBlockSize * 3, third_op.src_length());
375  EXPECT_EQ(1, third_op.src_extents().size());
376  EXPECT_EQ(9, third_op.src_extents(0).start_block());
377  EXPECT_EQ(3, third_op.src_extents(0).num_blocks());
378  EXPECT_EQ(kBlockSize * 3, third_op.dst_length());
379  EXPECT_EQ(1, third_op.dst_extents().size());
380  EXPECT_EQ(18, third_op.dst_extents(0).start_block());
381  EXPECT_EQ(3, third_op.dst_extents(0).num_blocks());
382}
383
384TEST_F(ABGeneratorTest, SplitReplaceTest) {
385  TestSplitReplaceOrReplaceBzOperation(
386      DeltaArchiveManifest_InstallOperation_Type_REPLACE, false);
387}
388
389TEST_F(ABGeneratorTest, SplitReplaceIntoReplaceBzTest) {
390  TestSplitReplaceOrReplaceBzOperation(
391      DeltaArchiveManifest_InstallOperation_Type_REPLACE, true);
392}
393
394TEST_F(ABGeneratorTest, SplitReplaceBzTest) {
395  TestSplitReplaceOrReplaceBzOperation(
396      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ, true);
397}
398
399TEST_F(ABGeneratorTest, SplitReplaceBzIntoReplaceTest) {
400  TestSplitReplaceOrReplaceBzOperation(
401      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ, false);
402}
403
404TEST_F(ABGeneratorTest, SortOperationsByDestinationTest) {
405  vector<AnnotatedOperation> aops;
406  // One operation with multiple destination extents.
407  DeltaArchiveManifest_InstallOperation first_op;
408  *(first_op.add_dst_extents()) = ExtentForRange(6, 1);
409  *(first_op.add_dst_extents()) = ExtentForRange(10, 2);
410  AnnotatedOperation first_aop;
411  first_aop.op = first_op;
412  first_aop.name = "first";
413  aops.push_back(first_aop);
414
415  // One with no destination extent. Should end up at the end of the vector.
416  DeltaArchiveManifest_InstallOperation second_op;
417  AnnotatedOperation second_aop;
418  second_aop.op = second_op;
419  second_aop.name = "second";
420  aops.push_back(second_aop);
421
422  // One with one destination extent.
423  DeltaArchiveManifest_InstallOperation third_op;
424  *(third_op.add_dst_extents()) = ExtentForRange(3, 2);
425  AnnotatedOperation third_aop;
426  third_aop.op = third_op;
427  third_aop.name = "third";
428  aops.push_back(third_aop);
429
430  ABGenerator::SortOperationsByDestination(&aops);
431  EXPECT_EQ(aops.size(), 3);
432  EXPECT_EQ(third_aop.name, aops[0].name);
433  EXPECT_EQ(first_aop.name, aops[1].name);
434  EXPECT_EQ(second_aop.name, aops[2].name);
435}
436
437TEST_F(ABGeneratorTest, MergeSourceCopyOperationsTest) {
438  vector<AnnotatedOperation> aops;
439  DeltaArchiveManifest_InstallOperation first_op;
440  first_op.set_type(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY);
441  first_op.set_src_length(kBlockSize);
442  first_op.set_dst_length(kBlockSize);
443  *(first_op.add_src_extents()) = ExtentForRange(1, 1);
444  *(first_op.add_dst_extents()) = ExtentForRange(6, 1);
445  AnnotatedOperation first_aop;
446  first_aop.op = first_op;
447  first_aop.name = "1";
448  aops.push_back(first_aop);
449
450  DeltaArchiveManifest_InstallOperation second_op;
451  second_op.set_type(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY);
452  second_op.set_src_length(3 * kBlockSize);
453  second_op.set_dst_length(3 * kBlockSize);
454  *(second_op.add_src_extents()) = ExtentForRange(2, 2);
455  *(second_op.add_src_extents()) = ExtentForRange(8, 2);
456  *(second_op.add_dst_extents()) = ExtentForRange(7, 3);
457  *(second_op.add_dst_extents()) = ExtentForRange(11, 1);
458  AnnotatedOperation second_aop;
459  second_aop.op = second_op;
460  second_aop.name = "2";
461  aops.push_back(second_aop);
462
463  DeltaArchiveManifest_InstallOperation third_op;
464  third_op.set_type(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY);
465  third_op.set_src_length(kBlockSize);
466  third_op.set_dst_length(kBlockSize);
467  *(third_op.add_src_extents()) = ExtentForRange(11, 1);
468  *(third_op.add_dst_extents()) = ExtentForRange(12, 1);
469  AnnotatedOperation third_aop;
470  third_aop.op = third_op;
471  third_aop.name = "3";
472  aops.push_back(third_aop);
473
474  EXPECT_TRUE(ABGenerator::MergeOperations(&aops, 5 * kBlockSize,
475                                           "", 0, nullptr));
476
477  EXPECT_EQ(aops.size(), 1);
478  DeltaArchiveManifest_InstallOperation first_result_op = aops[0].op;
479  EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_SOURCE_COPY,
480            first_result_op.type());
481  EXPECT_EQ(kBlockSize * 5, first_result_op.src_length());
482  EXPECT_EQ(3, first_result_op.src_extents().size());
483  EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(0), 1, 3));
484  EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(1), 8, 2));
485  EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(2), 11, 1));
486  EXPECT_EQ(kBlockSize * 5, first_result_op.dst_length());
487  EXPECT_EQ(2, first_result_op.dst_extents().size());
488  EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(0), 6, 4));
489  EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(1), 11, 2));
490  EXPECT_EQ(aops[0].name, "1,2,3");
491}
492
493TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) {
494  TestMergeReplaceOrReplaceBzOperations(
495      DeltaArchiveManifest_InstallOperation_Type_REPLACE, false);
496}
497
498TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) {
499  TestMergeReplaceOrReplaceBzOperations(
500      DeltaArchiveManifest_InstallOperation_Type_REPLACE, true);
501}
502
503TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) {
504  TestMergeReplaceOrReplaceBzOperations(
505      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ, true);
506}
507
508TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) {
509  TestMergeReplaceOrReplaceBzOperations(
510      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ, false);
511}
512
513TEST_F(ABGeneratorTest, NoMergeOperationsTest) {
514  // Test to make sure we don't merge operations that shouldn't be merged.
515  vector<AnnotatedOperation> aops;
516  DeltaArchiveManifest_InstallOperation first_op;
517  first_op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
518  *(first_op.add_dst_extents()) = ExtentForRange(0, 1);
519  first_op.set_data_length(kBlockSize);
520  AnnotatedOperation first_aop;
521  first_aop.op = first_op;
522  aops.push_back(first_aop);
523
524  // Should merge with first, except op types don't match...
525  DeltaArchiveManifest_InstallOperation second_op;
526  second_op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
527  *(second_op.add_dst_extents()) = ExtentForRange(1, 2);
528  second_op.set_data_length(2 * kBlockSize);
529  AnnotatedOperation second_aop;
530  second_aop.op = second_op;
531  aops.push_back(second_aop);
532
533  // Should merge with second, except it would exceed chunk size...
534  DeltaArchiveManifest_InstallOperation third_op;
535  third_op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
536  *(third_op.add_dst_extents()) = ExtentForRange(3, 3);
537  third_op.set_data_length(3 * kBlockSize);
538  AnnotatedOperation third_aop;
539  third_aop.op = third_op;
540  aops.push_back(third_aop);
541
542  // Should merge with third, except they aren't contiguous...
543  DeltaArchiveManifest_InstallOperation fourth_op;
544  fourth_op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
545  *(fourth_op.add_dst_extents()) = ExtentForRange(7, 2);
546  fourth_op.set_data_length(2 * kBlockSize);
547  AnnotatedOperation fourth_aop;
548  fourth_aop.op = fourth_op;
549  aops.push_back(fourth_aop);
550
551  EXPECT_TRUE(ABGenerator::MergeOperations(
552      &aops, 4 * kBlockSize, "", 0, nullptr));
553
554  // No operations were merged, the number of ops is the same.
555  EXPECT_EQ(aops.size(), 4);
556}
557
558}  // namespace chromeos_update_engine
559