blob: f6519b68a914e354846cc37b43204dc4005b6799 [file] [log] [blame]
Andrew de los Reyes80061062010-02-04 14:25:00 -08001// Copyright (c) 2009 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
Alex Deymo161c4a12014-05-16 15:56:21 -07005#include "update_engine/extent_writer.h"
6
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -08007#include <fcntl.h>
Andrew de los Reyes80061062010-02-04 14:25:00 -08008#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070011
Andrew de los Reyes80061062010-02-04 14:25:00 -080012#include <algorithm>
13#include <string>
14#include <vector>
Alex Deymo161c4a12014-05-16 15:56:21 -070015
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080016#include <chromeos/secure_blob.h>
Andrew de los Reyes80061062010-02-04 14:25:00 -080017#include <gtest/gtest.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070018
19#include "update_engine/payload_constants.h"
Andrew de los Reyes80061062010-02-04 14:25:00 -080020#include "update_engine/test_utils.h"
21#include "update_engine/utils.h"
22
Alex Deymo10875d92014-11-10 21:52:57 -080023using chromeos_update_engine::test_utils::ExpectVectorsEq;
Andrew de los Reyes80061062010-02-04 14:25:00 -080024using std::min;
25using std::string;
26using std::vector;
27
28namespace chromeos_update_engine {
29
30COMPILE_ASSERT(sizeof(off_t) == 8, off_t_not_64_bit);
31
32namespace {
33const char kPathTemplate[] = "./ExtentWriterTest-file.XXXXXX";
34const size_t kBlockSize = 4096;
35}
36
37class ExtentWriterTest : public ::testing::Test {
38 protected:
Alex Deymo610277e2014-11-11 21:18:11 -080039 void SetUp() override {
Andrew de los Reyes80061062010-02-04 14:25:00 -080040 memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080041 fd_.reset(new EintrSafeFileDescriptor);
42 int fd = mkstemp(path_);
43 ASSERT_TRUE(fd_->Open(path_, O_RDWR, 0600));
44 close(fd);
Andrew de los Reyes80061062010-02-04 14:25:00 -080045 }
Alex Deymo610277e2014-11-11 21:18:11 -080046 void TearDown() override {
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080047 fd_->Close();
Andrew de los Reyes80061062010-02-04 14:25:00 -080048 unlink(path_);
49 }
Chris Masonef8d037f2014-02-19 01:53:00 +000050
Andrew de los Reyes80061062010-02-04 14:25:00 -080051 // Writes data to an extent writer in 'chunk_size' chunks with
52 // the first chunk of size first_chunk_size. It calculates what the
53 // resultant file should look like and ensure that the extent writer
54 // wrote the file correctly.
55 void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
56 void TestZeroPad(bool aligned_size);
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080057
58 FileDescriptorPtr fd_;
Andrew de los Reyes80061062010-02-04 14:25:00 -080059 char path_[sizeof(kPathTemplate)];
60};
61
62TEST_F(ExtentWriterTest, SimpleTest) {
63 vector<Extent> extents;
64 Extent extent;
65 extent.set_start_block(1);
66 extent.set_num_blocks(1);
67 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -070068
Andrew de los Reyes80061062010-02-04 14:25:00 -080069 const string bytes = "1234";
70
71 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080072 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Andrew de los Reyes80061062010-02-04 14:25:00 -080073 EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
74 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -070075
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080076 EXPECT_EQ(kBlockSize + bytes.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -070077
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080078 chromeos::Blob result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080079 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -070080
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080081 chromeos::Blob expected_file(kBlockSize);
Andrew de los Reyes80061062010-02-04 14:25:00 -080082 expected_file.insert(expected_file.end(),
83 bytes.data(), bytes.data() + bytes.size());
84 ExpectVectorsEq(expected_file, result_file);
85}
86
87TEST_F(ExtentWriterTest, ZeroLengthTest) {
88 vector<Extent> extents;
89 Extent extent;
90 extent.set_start_block(1);
91 extent.set_num_blocks(1);
92 extents.push_back(extent);
93
94 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080095 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Vakulenko88b591f2014-08-28 16:48:57 -070096 EXPECT_TRUE(direct_writer.Write(nullptr, 0));
Andrew de los Reyes80061062010-02-04 14:25:00 -080097 EXPECT_TRUE(direct_writer.End());
98}
99
100TEST_F(ExtentWriterTest, OverflowExtentTest) {
101 WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
102}
103
104TEST_F(ExtentWriterTest, UnalignedWriteTest) {
105 WriteAlignedExtents(7, 7);
106}
107
108TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
109 WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
110}
111
112void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
113 size_t first_chunk_size) {
114 vector<Extent> extents;
115 Extent extent;
116 extent.set_start_block(1);
117 extent.set_num_blocks(1);
118 extents.push_back(extent);
119 extent.set_start_block(0);
120 extent.set_num_blocks(1);
121 extents.push_back(extent);
122 extent.set_start_block(2);
123 extent.set_num_blocks(1);
124 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700125
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800126 chromeos::Blob data(kBlockSize * 3);
Alex Deymo10875d92014-11-10 21:52:57 -0800127 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700128
Andrew de los Reyes80061062010-02-04 14:25:00 -0800129 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800130 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700131
Andrew de los Reyes80061062010-02-04 14:25:00 -0800132 size_t bytes_written = 0;
133 while (bytes_written < data.size()) {
134 size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
135 if (bytes_written == 0) {
136 bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
137 }
138 EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
139 bytes_written += bytes_to_write;
140 }
141 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700142
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800143 EXPECT_EQ(data.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700144
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800145 chromeos::Blob result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800146 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700147
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800148 chromeos::Blob expected_file;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800149 expected_file.insert(expected_file.end(),
150 data.begin() + kBlockSize,
151 data.begin() + kBlockSize * 2);
152 expected_file.insert(expected_file.end(),
153 data.begin(), data.begin() + kBlockSize);
154 expected_file.insert(expected_file.end(),
155 data.begin() + kBlockSize * 2, data.end());
156 ExpectVectorsEq(expected_file, result_file);
157}
158
159TEST_F(ExtentWriterTest, ZeroPadNullTest) {
160 TestZeroPad(true);
161}
162
163TEST_F(ExtentWriterTest, ZeroPadFillTest) {
164 TestZeroPad(false);
165}
166
167void ExtentWriterTest::TestZeroPad(bool aligned_size) {
168 vector<Extent> extents;
169 Extent extent;
170 extent.set_start_block(1);
171 extent.set_num_blocks(1);
172 extents.push_back(extent);
173 extent.set_start_block(0);
174 extent.set_num_blocks(1);
175 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700176
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800177 chromeos::Blob data(kBlockSize * 2);
Alex Deymo10875d92014-11-10 21:52:57 -0800178 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700179
Andrew de los Reyes80061062010-02-04 14:25:00 -0800180 DirectExtentWriter direct_writer;
181 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
182
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800183 EXPECT_TRUE(zero_pad_writer.Init(fd_, extents, kBlockSize));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800184 size_t bytes_to_write = data.size();
185 const size_t missing_bytes = (aligned_size ? 0 : 9);
186 bytes_to_write -= missing_bytes;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800187 fd_->Seek(kBlockSize - missing_bytes, SEEK_SET);
188 EXPECT_EQ(3, fd_->Write("xxx", 3));
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800189 ASSERT_TRUE(zero_pad_writer.Write(data.data(), bytes_to_write));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800190 EXPECT_TRUE(zero_pad_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700191
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800192 EXPECT_EQ(data.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700193
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800194 chromeos::Blob result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800195 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700196
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800197 chromeos::Blob expected_file;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800198 expected_file.insert(expected_file.end(),
199 data.begin() + kBlockSize,
200 data.begin() + kBlockSize * 2);
201 expected_file.insert(expected_file.end(),
202 data.begin(), data.begin() + kBlockSize);
203 if (missing_bytes) {
204 memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
205 }
206
207 ExpectVectorsEq(expected_file, result_file);
208}
209
210TEST_F(ExtentWriterTest, SparseFileTest) {
211 vector<Extent> extents;
212 Extent extent;
213 extent.set_start_block(1);
214 extent.set_num_blocks(1);
215 extents.push_back(extent);
216 extent.set_start_block(kSparseHole);
217 extent.set_num_blocks(2);
218 extents.push_back(extent);
219 extent.set_start_block(0);
220 extent.set_num_blocks(1);
221 extents.push_back(extent);
222 const int block_count = 4;
223 const int on_disk_count = 2;
224
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800225 chromeos::Blob data(17);
Alex Deymo10875d92014-11-10 21:52:57 -0800226 test_utils::FillWithData(&data);
Andrew de los Reyes80061062010-02-04 14:25:00 -0800227
228 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800229 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700230
Andrew de los Reyes80061062010-02-04 14:25:00 -0800231 size_t bytes_written = 0;
232 while (bytes_written < (block_count * kBlockSize)) {
233 size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
234 data.size());
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800235 EXPECT_TRUE(direct_writer.Write(data.data(), bytes_to_write));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800236 bytes_written += bytes_to_write;
237 }
238 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700239
Andrew de los Reyes80061062010-02-04 14:25:00 -0800240 // check file size, then data inside
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800241 ASSERT_EQ(2 * kBlockSize, utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700242
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800243 chromeos::Blob resultant_data;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800244 EXPECT_TRUE(utils::ReadFile(path_, &resultant_data));
Alex Deymo161c4a12014-05-16 15:56:21 -0700245
Andrew de los Reyes80061062010-02-04 14:25:00 -0800246 // Create expected data
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800247 chromeos::Blob expected_data(on_disk_count * kBlockSize);
248 chromeos::Blob big(block_count * kBlockSize);
249 for (chromeos::Blob::size_type i = 0; i < big.size(); i++) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800250 big[i] = data[i % data.size()];
251 }
252 memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
253 memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
254 ExpectVectorsEq(expected_data, resultant_data);
255}
256
257} // namespace chromeos_update_engine