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