blob: 0a9020c8defb8925b0dc6fa381c17ea5885e37bc [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
Andrew de los Reyes80061062010-02-04 14:25:00 -080016#include <gtest/gtest.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070017
18#include "update_engine/payload_constants.h"
Andrew de los Reyes80061062010-02-04 14:25:00 -080019#include "update_engine/test_utils.h"
20#include "update_engine/utils.h"
21
Alex Deymo10875d92014-11-10 21:52:57 -080022using chromeos_update_engine::test_utils::ExpectVectorsEq;
Andrew de los Reyes80061062010-02-04 14:25:00 -080023using std::min;
24using std::string;
25using std::vector;
26
27namespace chromeos_update_engine {
28
29COMPILE_ASSERT(sizeof(off_t) == 8, off_t_not_64_bit);
30
31namespace {
32const char kPathTemplate[] = "./ExtentWriterTest-file.XXXXXX";
33const size_t kBlockSize = 4096;
34}
35
36class ExtentWriterTest : public ::testing::Test {
37 protected:
Alex Deymo610277e2014-11-11 21:18:11 -080038 void SetUp() override {
Andrew de los Reyes80061062010-02-04 14:25:00 -080039 memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080040 fd_.reset(new EintrSafeFileDescriptor);
41 int fd = mkstemp(path_);
42 ASSERT_TRUE(fd_->Open(path_, O_RDWR, 0600));
43 close(fd);
Andrew de los Reyes80061062010-02-04 14:25:00 -080044 }
Alex Deymo610277e2014-11-11 21:18:11 -080045 void TearDown() override {
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080046 fd_->Close();
Andrew de los Reyes80061062010-02-04 14:25:00 -080047 unlink(path_);
48 }
Chris Masonef8d037f2014-02-19 01:53:00 +000049
Andrew de los Reyes80061062010-02-04 14:25:00 -080050 // Writes data to an extent writer in 'chunk_size' chunks with
51 // the first chunk of size first_chunk_size. It calculates what the
52 // resultant file should look like and ensure that the extent writer
53 // wrote the file correctly.
54 void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
55 void TestZeroPad(bool aligned_size);
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080056
57 FileDescriptorPtr fd_;
Andrew de los Reyes80061062010-02-04 14:25:00 -080058 char path_[sizeof(kPathTemplate)];
59};
60
61TEST_F(ExtentWriterTest, SimpleTest) {
62 vector<Extent> extents;
63 Extent extent;
64 extent.set_start_block(1);
65 extent.set_num_blocks(1);
66 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -070067
Andrew de los Reyes80061062010-02-04 14:25:00 -080068 const string bytes = "1234";
69
70 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080071 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Andrew de los Reyes80061062010-02-04 14:25:00 -080072 EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
73 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -070074
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080075 EXPECT_EQ(kBlockSize + bytes.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -070076
Andrew de los Reyes80061062010-02-04 14:25:00 -080077 vector<char> result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080078 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -070079
Andrew de los Reyes80061062010-02-04 14:25:00 -080080 vector<char> expected_file(kBlockSize);
81 expected_file.insert(expected_file.end(),
82 bytes.data(), bytes.data() + bytes.size());
83 ExpectVectorsEq(expected_file, result_file);
84}
85
86TEST_F(ExtentWriterTest, ZeroLengthTest) {
87 vector<Extent> extents;
88 Extent extent;
89 extent.set_start_block(1);
90 extent.set_num_blocks(1);
91 extents.push_back(extent);
92
93 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -080094 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Vakulenko88b591f2014-08-28 16:48:57 -070095 EXPECT_TRUE(direct_writer.Write(nullptr, 0));
Andrew de los Reyes80061062010-02-04 14:25:00 -080096 EXPECT_TRUE(direct_writer.End());
97}
98
99TEST_F(ExtentWriterTest, OverflowExtentTest) {
100 WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
101}
102
103TEST_F(ExtentWriterTest, UnalignedWriteTest) {
104 WriteAlignedExtents(7, 7);
105}
106
107TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
108 WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
109}
110
111void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
112 size_t first_chunk_size) {
113 vector<Extent> extents;
114 Extent extent;
115 extent.set_start_block(1);
116 extent.set_num_blocks(1);
117 extents.push_back(extent);
118 extent.set_start_block(0);
119 extent.set_num_blocks(1);
120 extents.push_back(extent);
121 extent.set_start_block(2);
122 extent.set_num_blocks(1);
123 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700124
Andrew de los Reyes80061062010-02-04 14:25:00 -0800125 vector<char> data(kBlockSize * 3);
Alex Deymo10875d92014-11-10 21:52:57 -0800126 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700127
Andrew de los Reyes80061062010-02-04 14:25:00 -0800128 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800129 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700130
Andrew de los Reyes80061062010-02-04 14:25:00 -0800131 size_t bytes_written = 0;
132 while (bytes_written < data.size()) {
133 size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
134 if (bytes_written == 0) {
135 bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
136 }
137 EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
138 bytes_written += bytes_to_write;
139 }
140 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700141
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800142 EXPECT_EQ(data.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700143
Andrew de los Reyes80061062010-02-04 14:25:00 -0800144 vector<char> result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800145 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700146
Andrew de los Reyes80061062010-02-04 14:25:00 -0800147 vector<char> expected_file;
148 expected_file.insert(expected_file.end(),
149 data.begin() + kBlockSize,
150 data.begin() + kBlockSize * 2);
151 expected_file.insert(expected_file.end(),
152 data.begin(), data.begin() + kBlockSize);
153 expected_file.insert(expected_file.end(),
154 data.begin() + kBlockSize * 2, data.end());
155 ExpectVectorsEq(expected_file, result_file);
156}
157
158TEST_F(ExtentWriterTest, ZeroPadNullTest) {
159 TestZeroPad(true);
160}
161
162TEST_F(ExtentWriterTest, ZeroPadFillTest) {
163 TestZeroPad(false);
164}
165
166void ExtentWriterTest::TestZeroPad(bool aligned_size) {
167 vector<Extent> extents;
168 Extent extent;
169 extent.set_start_block(1);
170 extent.set_num_blocks(1);
171 extents.push_back(extent);
172 extent.set_start_block(0);
173 extent.set_num_blocks(1);
174 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700175
Andrew de los Reyes80061062010-02-04 14:25:00 -0800176 vector<char> data(kBlockSize * 2);
Alex Deymo10875d92014-11-10 21:52:57 -0800177 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700178
Andrew de los Reyes80061062010-02-04 14:25:00 -0800179 DirectExtentWriter direct_writer;
180 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
181
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800182 EXPECT_TRUE(zero_pad_writer.Init(fd_, extents, kBlockSize));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800183 size_t bytes_to_write = data.size();
184 const size_t missing_bytes = (aligned_size ? 0 : 9);
185 bytes_to_write -= missing_bytes;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800186 fd_->Seek(kBlockSize - missing_bytes, SEEK_SET);
187 EXPECT_EQ(3, fd_->Write("xxx", 3));
Andrew de los Reyes80061062010-02-04 14:25:00 -0800188 ASSERT_TRUE(zero_pad_writer.Write(&data[0], bytes_to_write));
189 EXPECT_TRUE(zero_pad_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700190
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800191 EXPECT_EQ(data.size(), utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700192
Andrew de los Reyes80061062010-02-04 14:25:00 -0800193 vector<char> result_file;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800194 EXPECT_TRUE(utils::ReadFile(path_, &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700195
Andrew de los Reyes80061062010-02-04 14:25:00 -0800196 vector<char> expected_file;
197 expected_file.insert(expected_file.end(),
198 data.begin() + kBlockSize,
199 data.begin() + kBlockSize * 2);
200 expected_file.insert(expected_file.end(),
201 data.begin(), data.begin() + kBlockSize);
202 if (missing_bytes) {
203 memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
204 }
205
206 ExpectVectorsEq(expected_file, result_file);
207}
208
209TEST_F(ExtentWriterTest, SparseFileTest) {
210 vector<Extent> extents;
211 Extent extent;
212 extent.set_start_block(1);
213 extent.set_num_blocks(1);
214 extents.push_back(extent);
215 extent.set_start_block(kSparseHole);
216 extent.set_num_blocks(2);
217 extents.push_back(extent);
218 extent.set_start_block(0);
219 extent.set_num_blocks(1);
220 extents.push_back(extent);
221 const int block_count = 4;
222 const int on_disk_count = 2;
223
224 vector<char> data(17);
Alex Deymo10875d92014-11-10 21:52:57 -0800225 test_utils::FillWithData(&data);
Andrew de los Reyes80061062010-02-04 14:25:00 -0800226
227 DirectExtentWriter direct_writer;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800228 EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700229
Andrew de los Reyes80061062010-02-04 14:25:00 -0800230 size_t bytes_written = 0;
231 while (bytes_written < (block_count * kBlockSize)) {
232 size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
233 data.size());
234 EXPECT_TRUE(direct_writer.Write(&data[0], bytes_to_write));
235 bytes_written += bytes_to_write;
236 }
237 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700238
Andrew de los Reyes80061062010-02-04 14:25:00 -0800239 // check file size, then data inside
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800240 ASSERT_EQ(2 * kBlockSize, utils::FileSize(path_));
Alex Deymo161c4a12014-05-16 15:56:21 -0700241
Andrew de los Reyes80061062010-02-04 14:25:00 -0800242 vector<char> resultant_data;
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -0800243 EXPECT_TRUE(utils::ReadFile(path_, &resultant_data));
Alex Deymo161c4a12014-05-16 15:56:21 -0700244
Andrew de los Reyes80061062010-02-04 14:25:00 -0800245 // Create expected data
246 vector<char> expected_data(on_disk_count * kBlockSize);
247 vector<char> big(block_count * kBlockSize);
248 for (vector<char>::size_type i = 0; i < big.size(); i++) {
249 big[i] = data[i % data.size()];
250 }
251 memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
252 memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
253 ExpectVectorsEq(expected_data, resultant_data);
254}
255
256} // namespace chromeos_update_engine