blob: fcd57dd55ff21920e5d6af62651072c955906309 [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
Andrew de los Reyes80061062010-02-04 14:25:00 -08007#include <sys/stat.h>
8#include <sys/types.h>
9#include <unistd.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070010
Andrew de los Reyes80061062010-02-04 14:25:00 -080011#include <algorithm>
12#include <string>
13#include <vector>
Alex Deymo161c4a12014-05-16 15:56:21 -070014
Andrew de los Reyes80061062010-02-04 14:25:00 -080015#include <gtest/gtest.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070016
17#include "update_engine/payload_constants.h"
Andrew de los Reyes80061062010-02-04 14:25:00 -080018#include "update_engine/test_utils.h"
19#include "update_engine/utils.h"
20
21using std::min;
22using std::string;
23using std::vector;
24
25namespace chromeos_update_engine {
26
27COMPILE_ASSERT(sizeof(off_t) == 8, off_t_not_64_bit);
28
29namespace {
30const char kPathTemplate[] = "./ExtentWriterTest-file.XXXXXX";
31const size_t kBlockSize = 4096;
32}
33
34class ExtentWriterTest : public ::testing::Test {
35 protected:
36 virtual void SetUp() {
37 memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
38 fd_ = mkstemp(path_);
39 ASSERT_GE(fd_, 0);
40 }
41 virtual void TearDown() {
42 close(fd_);
43 unlink(path_);
44 }
45 int fd() { return fd_; }
46 const char* path() { return path_; }
Chris Masonef8d037f2014-02-19 01:53:00 +000047
Andrew de los Reyes80061062010-02-04 14:25:00 -080048 // Writes data to an extent writer in 'chunk_size' chunks with
49 // the first chunk of size first_chunk_size. It calculates what the
50 // resultant file should look like and ensure that the extent writer
51 // wrote the file correctly.
52 void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
53 void TestZeroPad(bool aligned_size);
54 private:
55 int fd_;
56 char path_[sizeof(kPathTemplate)];
57};
58
59TEST_F(ExtentWriterTest, SimpleTest) {
60 vector<Extent> extents;
61 Extent extent;
62 extent.set_start_block(1);
63 extent.set_num_blocks(1);
64 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -070065
Andrew de los Reyes80061062010-02-04 14:25:00 -080066 const string bytes = "1234";
67
68 DirectExtentWriter direct_writer;
69 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
70 EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
71 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -070072
Andrew de los Reyes80061062010-02-04 14:25:00 -080073 struct stat stbuf;
74 EXPECT_EQ(0, fstat(fd(), &stbuf));
75 EXPECT_EQ(kBlockSize + bytes.size(), stbuf.st_size);
Alex Deymo161c4a12014-05-16 15:56:21 -070076
Andrew de los Reyes80061062010-02-04 14:25:00 -080077 vector<char> result_file;
78 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;
94 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
95 EXPECT_TRUE(direct_writer.Write(NULL, 0));
96 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);
126 FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700127
Andrew de los Reyes80061062010-02-04 14:25:00 -0800128 DirectExtentWriter direct_writer;
129 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
Andrew de los Reyes80061062010-02-04 14:25:00 -0800142 struct stat stbuf;
143 EXPECT_EQ(0, fstat(fd(), &stbuf));
144 EXPECT_EQ(data.size(), stbuf.st_size);
Alex Deymo161c4a12014-05-16 15:56:21 -0700145
Andrew de los Reyes80061062010-02-04 14:25:00 -0800146 vector<char> result_file;
147 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700148
Andrew de los Reyes80061062010-02-04 14:25:00 -0800149 vector<char> expected_file;
150 expected_file.insert(expected_file.end(),
151 data.begin() + kBlockSize,
152 data.begin() + kBlockSize * 2);
153 expected_file.insert(expected_file.end(),
154 data.begin(), data.begin() + kBlockSize);
155 expected_file.insert(expected_file.end(),
156 data.begin() + kBlockSize * 2, data.end());
157 ExpectVectorsEq(expected_file, result_file);
158}
159
160TEST_F(ExtentWriterTest, ZeroPadNullTest) {
161 TestZeroPad(true);
162}
163
164TEST_F(ExtentWriterTest, ZeroPadFillTest) {
165 TestZeroPad(false);
166}
167
168void ExtentWriterTest::TestZeroPad(bool aligned_size) {
169 vector<Extent> extents;
170 Extent extent;
171 extent.set_start_block(1);
172 extent.set_num_blocks(1);
173 extents.push_back(extent);
174 extent.set_start_block(0);
175 extent.set_num_blocks(1);
176 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700177
Andrew de los Reyes80061062010-02-04 14:25:00 -0800178 vector<char> data(kBlockSize * 2);
179 FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700180
Andrew de los Reyes80061062010-02-04 14:25:00 -0800181 DirectExtentWriter direct_writer;
182 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
183
184 EXPECT_TRUE(zero_pad_writer.Init(fd(), extents, kBlockSize));
185 size_t bytes_to_write = data.size();
186 const size_t missing_bytes = (aligned_size ? 0 : 9);
187 bytes_to_write -= missing_bytes;
188 lseek64(fd(), kBlockSize - missing_bytes, SEEK_SET);
189 EXPECT_EQ(3, write(fd(), "xxx", 3));
190 ASSERT_TRUE(zero_pad_writer.Write(&data[0], bytes_to_write));
191 EXPECT_TRUE(zero_pad_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700192
Andrew de los Reyes80061062010-02-04 14:25:00 -0800193 struct stat stbuf;
194 EXPECT_EQ(0, fstat(fd(), &stbuf));
195 EXPECT_EQ(data.size(), stbuf.st_size);
Alex Deymo161c4a12014-05-16 15:56:21 -0700196
Andrew de los Reyes80061062010-02-04 14:25:00 -0800197 vector<char> result_file;
198 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700199
Andrew de los Reyes80061062010-02-04 14:25:00 -0800200 vector<char> expected_file;
201 expected_file.insert(expected_file.end(),
202 data.begin() + kBlockSize,
203 data.begin() + kBlockSize * 2);
204 expected_file.insert(expected_file.end(),
205 data.begin(), data.begin() + kBlockSize);
206 if (missing_bytes) {
207 memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
208 }
209
210 ExpectVectorsEq(expected_file, result_file);
211}
212
213TEST_F(ExtentWriterTest, SparseFileTest) {
214 vector<Extent> extents;
215 Extent extent;
216 extent.set_start_block(1);
217 extent.set_num_blocks(1);
218 extents.push_back(extent);
219 extent.set_start_block(kSparseHole);
220 extent.set_num_blocks(2);
221 extents.push_back(extent);
222 extent.set_start_block(0);
223 extent.set_num_blocks(1);
224 extents.push_back(extent);
225 const int block_count = 4;
226 const int on_disk_count = 2;
227
228 vector<char> data(17);
229 FillWithData(&data);
230
231 DirectExtentWriter direct_writer;
232 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700233
Andrew de los Reyes80061062010-02-04 14:25:00 -0800234 size_t bytes_written = 0;
235 while (bytes_written < (block_count * kBlockSize)) {
236 size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
237 data.size());
238 EXPECT_TRUE(direct_writer.Write(&data[0], bytes_to_write));
239 bytes_written += bytes_to_write;
240 }
241 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700242
Andrew de los Reyes80061062010-02-04 14:25:00 -0800243 // check file size, then data inside
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700244 ASSERT_EQ(2 * kBlockSize, utils::FileSize(path()));
Alex Deymo161c4a12014-05-16 15:56:21 -0700245
Andrew de los Reyes80061062010-02-04 14:25:00 -0800246 vector<char> resultant_data;
247 EXPECT_TRUE(utils::ReadFile(path(), &resultant_data));
Alex Deymo161c4a12014-05-16 15:56:21 -0700248
Andrew de los Reyes80061062010-02-04 14:25:00 -0800249 // Create expected data
250 vector<char> expected_data(on_disk_count * kBlockSize);
251 vector<char> big(block_count * kBlockSize);
252 for (vector<char>::size_type i = 0; i < big.size(); i++) {
253 big[i] = data[i % data.size()];
254 }
255 memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
256 memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
257 ExpectVectorsEq(expected_data, resultant_data);
258}
259
260} // namespace chromeos_update_engine