full_update_generator_unittest.cc revision a12ee11c78ac6d7c2605921a4006b6a7416e0c35
1// Copyright (c) 2010 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/full_update_generator.h"
6
7#include <string>
8#include <vector>
9
10#include <gtest/gtest.h>
11
12#include "update_engine/delta_performer.h"
13#include "update_engine/payload_generator/extent_utils.h"
14#include "update_engine/test_utils.h"
15
16using chromeos_update_engine::test_utils::FillWithData;
17using std::string;
18using std::vector;
19
20namespace chromeos_update_engine {
21
22class FullUpdateGeneratorTest : public ::testing::Test {
23 protected:
24  void SetUp() override {
25    config_.is_delta = false;
26    config_.minor_version = DeltaPerformer::kFullPayloadMinorVersion;
27    config_.hard_chunk_size = 128 * 1024;
28    config_.block_size = 4096;
29
30    EXPECT_TRUE(utils::MakeTempFile("FullUpdateTest_rootfs.XXXXXX",
31                                    &config_.target.rootfs.path,
32                                    nullptr));
33    EXPECT_TRUE(utils::MakeTempFile("FullUpdateTest_kernel.XXXXXX",
34                                    &config_.target.kernel.path,
35                                    nullptr));
36    EXPECT_TRUE(utils::MakeTempFile("FullUpdateTest_blobs.XXXXXX",
37                                    &out_blobs_path_,
38                                    &out_blobs_fd_));
39
40    blob_file_.reset(new BlobFileWriter(out_blobs_fd_, &out_blobs_length_));
41    rootfs_part_unlinker_.reset(
42        new ScopedPathUnlinker(config_.target.rootfs.path));
43    kernel_part_unlinker_.reset(
44        new ScopedPathUnlinker(config_.target.kernel.path));
45    out_blobs_unlinker_.reset(new ScopedPathUnlinker(out_blobs_path_));
46  }
47
48  PayloadGenerationConfig config_;
49
50  // Output file holding the payload blobs.
51  string out_blobs_path_;
52  int out_blobs_fd_{-1};
53  off_t out_blobs_length_{0};
54  ScopedFdCloser out_blobs_fd_closer_{&out_blobs_fd_};
55
56  std::unique_ptr<BlobFileWriter> blob_file_;
57  std::unique_ptr<ScopedPathUnlinker> rootfs_part_unlinker_;
58  std::unique_ptr<ScopedPathUnlinker> kernel_part_unlinker_;
59  std::unique_ptr<ScopedPathUnlinker> out_blobs_unlinker_;
60
61  // FullUpdateGenerator under test.
62  FullUpdateGenerator generator_;
63};
64
65TEST_F(FullUpdateGeneratorTest, RunTest) {
66  chromeos::Blob new_root(9 * 1024 * 1024);
67  chromeos::Blob new_kern(3 * 1024 * 1024);
68  FillWithData(&new_root);
69  FillWithData(&new_kern);
70
71  // Assume hashes take 2 MiB beyond the rootfs.
72  config_.rootfs_partition_size = new_root.size();
73  config_.target.rootfs.size = new_root.size() - 2 * 1024 * 1024;
74  config_.target.kernel.size = new_kern.size();
75
76  EXPECT_TRUE(test_utils::WriteFileVector(config_.target.rootfs.path,
77                                          new_root));
78  EXPECT_TRUE(test_utils::WriteFileVector(config_.target.kernel.path,
79                                          new_kern));
80
81  vector<AnnotatedOperation> rootfs_ops;
82  vector<AnnotatedOperation> kernel_ops;
83
84  EXPECT_TRUE(generator_.GenerateOperations(config_,
85                                            blob_file_.get(),
86                                            &rootfs_ops,
87                                            &kernel_ops));
88  int64_t target_rootfs_chunks =
89      config_.target.rootfs.size / config_.hard_chunk_size;
90  EXPECT_EQ(target_rootfs_chunks, rootfs_ops.size());
91  EXPECT_EQ(new_kern.size() / config_.hard_chunk_size, kernel_ops.size());
92  for (off_t i = 0; i < target_rootfs_chunks; ++i) {
93    EXPECT_EQ(1, rootfs_ops[i].op.dst_extents_size());
94    EXPECT_EQ(i * config_.hard_chunk_size / config_.block_size,
95              rootfs_ops[i].op.dst_extents(0).start_block()) << "i = " << i;
96    EXPECT_EQ(config_.hard_chunk_size / config_.block_size,
97              rootfs_ops[i].op.dst_extents(0).num_blocks());
98    if (rootfs_ops[i].op.type() != InstallOperation::REPLACE) {
99      EXPECT_EQ(InstallOperation::REPLACE_BZ, rootfs_ops[i].op.type());
100    }
101  }
102}
103
104// Test that if the chunk size is not a divisor of the image size, it handles
105// correctly the last chunk of each partition.
106TEST_F(FullUpdateGeneratorTest, ChunkSizeTooBig) {
107  config_.hard_chunk_size = 1024 * 1024;
108  config_.soft_chunk_size = config_.hard_chunk_size;
109  chromeos::Blob new_root(1536 * 1024);  // 1.5 MiB
110  chromeos::Blob new_kern(128 * 1024);
111  config_.rootfs_partition_size = new_root.size();
112  config_.target.rootfs.size = new_root.size();
113  config_.target.kernel.size = new_kern.size();
114
115  EXPECT_TRUE(test_utils::WriteFileVector(config_.target.rootfs.path,
116                                          new_root));
117  EXPECT_TRUE(test_utils::WriteFileVector(config_.target.kernel.path,
118                                          new_kern));
119
120  vector<AnnotatedOperation> rootfs_ops;
121  vector<AnnotatedOperation> kernel_ops;
122
123  EXPECT_TRUE(generator_.GenerateOperations(config_,
124                                            blob_file_.get(),
125                                            &rootfs_ops,
126                                            &kernel_ops));
127  // rootfs has one chunk and a half.
128  EXPECT_EQ(2, rootfs_ops.size());
129  EXPECT_EQ(config_.hard_chunk_size / config_.block_size,
130            BlocksInExtents(rootfs_ops[0].op.dst_extents()));
131  EXPECT_EQ((new_root.size() - config_.hard_chunk_size) / config_.block_size,
132            BlocksInExtents(rootfs_ops[1].op.dst_extents()));
133
134  // kernel has less than one chunk.
135  EXPECT_EQ(1, kernel_ops.size());
136  EXPECT_EQ(new_kern.size() / config_.block_size,
137            BlocksInExtents(kernel_ops[0].op.dst_extents()));
138}
139
140}  // namespace chromeos_update_engine
141