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