blob: a1b254d34c4e544a573737c6db56e6733ee0c54d [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
Gabe Blacka77939e2014-09-09 23:35:08 -070073 EXPECT_EQ(kBlockSize + bytes.size(), utils::FileSize(fd()));
Alex Deymo161c4a12014-05-16 15:56:21 -070074
Andrew de los Reyes80061062010-02-04 14:25:00 -080075 vector<char> result_file;
76 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -070077
Andrew de los Reyes80061062010-02-04 14:25:00 -080078 vector<char> expected_file(kBlockSize);
79 expected_file.insert(expected_file.end(),
80 bytes.data(), bytes.data() + bytes.size());
81 ExpectVectorsEq(expected_file, result_file);
82}
83
84TEST_F(ExtentWriterTest, ZeroLengthTest) {
85 vector<Extent> extents;
86 Extent extent;
87 extent.set_start_block(1);
88 extent.set_num_blocks(1);
89 extents.push_back(extent);
90
91 DirectExtentWriter direct_writer;
92 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
Alex Vakulenko88b591f2014-08-28 16:48:57 -070093 EXPECT_TRUE(direct_writer.Write(nullptr, 0));
Andrew de los Reyes80061062010-02-04 14:25:00 -080094 EXPECT_TRUE(direct_writer.End());
95}
96
97TEST_F(ExtentWriterTest, OverflowExtentTest) {
98 WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
99}
100
101TEST_F(ExtentWriterTest, UnalignedWriteTest) {
102 WriteAlignedExtents(7, 7);
103}
104
105TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
106 WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
107}
108
109void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
110 size_t first_chunk_size) {
111 vector<Extent> extents;
112 Extent extent;
113 extent.set_start_block(1);
114 extent.set_num_blocks(1);
115 extents.push_back(extent);
116 extent.set_start_block(0);
117 extent.set_num_blocks(1);
118 extents.push_back(extent);
119 extent.set_start_block(2);
120 extent.set_num_blocks(1);
121 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700122
Andrew de los Reyes80061062010-02-04 14:25:00 -0800123 vector<char> data(kBlockSize * 3);
124 FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700125
Andrew de los Reyes80061062010-02-04 14:25:00 -0800126 DirectExtentWriter direct_writer;
127 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700128
Andrew de los Reyes80061062010-02-04 14:25:00 -0800129 size_t bytes_written = 0;
130 while (bytes_written < data.size()) {
131 size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
132 if (bytes_written == 0) {
133 bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
134 }
135 EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
136 bytes_written += bytes_to_write;
137 }
138 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700139
Gabe Blacka77939e2014-09-09 23:35:08 -0700140 EXPECT_EQ(data.size(), utils::FileSize(fd()));
Alex Deymo161c4a12014-05-16 15:56:21 -0700141
Andrew de los Reyes80061062010-02-04 14:25:00 -0800142 vector<char> result_file;
143 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700144
Andrew de los Reyes80061062010-02-04 14:25:00 -0800145 vector<char> expected_file;
146 expected_file.insert(expected_file.end(),
147 data.begin() + kBlockSize,
148 data.begin() + kBlockSize * 2);
149 expected_file.insert(expected_file.end(),
150 data.begin(), data.begin() + kBlockSize);
151 expected_file.insert(expected_file.end(),
152 data.begin() + kBlockSize * 2, data.end());
153 ExpectVectorsEq(expected_file, result_file);
154}
155
156TEST_F(ExtentWriterTest, ZeroPadNullTest) {
157 TestZeroPad(true);
158}
159
160TEST_F(ExtentWriterTest, ZeroPadFillTest) {
161 TestZeroPad(false);
162}
163
164void ExtentWriterTest::TestZeroPad(bool aligned_size) {
165 vector<Extent> extents;
166 Extent extent;
167 extent.set_start_block(1);
168 extent.set_num_blocks(1);
169 extents.push_back(extent);
170 extent.set_start_block(0);
171 extent.set_num_blocks(1);
172 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700173
Andrew de los Reyes80061062010-02-04 14:25:00 -0800174 vector<char> data(kBlockSize * 2);
175 FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700176
Andrew de los Reyes80061062010-02-04 14:25:00 -0800177 DirectExtentWriter direct_writer;
178 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
179
180 EXPECT_TRUE(zero_pad_writer.Init(fd(), extents, kBlockSize));
181 size_t bytes_to_write = data.size();
182 const size_t missing_bytes = (aligned_size ? 0 : 9);
183 bytes_to_write -= missing_bytes;
184 lseek64(fd(), kBlockSize - missing_bytes, SEEK_SET);
185 EXPECT_EQ(3, write(fd(), "xxx", 3));
186 ASSERT_TRUE(zero_pad_writer.Write(&data[0], bytes_to_write));
187 EXPECT_TRUE(zero_pad_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700188
Gabe Blacka77939e2014-09-09 23:35:08 -0700189 EXPECT_EQ(data.size(), utils::FileSize(fd()));
Alex Deymo161c4a12014-05-16 15:56:21 -0700190
Andrew de los Reyes80061062010-02-04 14:25:00 -0800191 vector<char> result_file;
192 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700193
Andrew de los Reyes80061062010-02-04 14:25:00 -0800194 vector<char> expected_file;
195 expected_file.insert(expected_file.end(),
196 data.begin() + kBlockSize,
197 data.begin() + kBlockSize * 2);
198 expected_file.insert(expected_file.end(),
199 data.begin(), data.begin() + kBlockSize);
200 if (missing_bytes) {
201 memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
202 }
203
204 ExpectVectorsEq(expected_file, result_file);
205}
206
207TEST_F(ExtentWriterTest, SparseFileTest) {
208 vector<Extent> extents;
209 Extent extent;
210 extent.set_start_block(1);
211 extent.set_num_blocks(1);
212 extents.push_back(extent);
213 extent.set_start_block(kSparseHole);
214 extent.set_num_blocks(2);
215 extents.push_back(extent);
216 extent.set_start_block(0);
217 extent.set_num_blocks(1);
218 extents.push_back(extent);
219 const int block_count = 4;
220 const int on_disk_count = 2;
221
222 vector<char> data(17);
223 FillWithData(&data);
224
225 DirectExtentWriter direct_writer;
226 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700227
Andrew de los Reyes80061062010-02-04 14:25:00 -0800228 size_t bytes_written = 0;
229 while (bytes_written < (block_count * kBlockSize)) {
230 size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
231 data.size());
232 EXPECT_TRUE(direct_writer.Write(&data[0], bytes_to_write));
233 bytes_written += bytes_to_write;
234 }
235 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700236
Andrew de los Reyes80061062010-02-04 14:25:00 -0800237 // check file size, then data inside
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700238 ASSERT_EQ(2 * kBlockSize, utils::FileSize(path()));
Alex Deymo161c4a12014-05-16 15:56:21 -0700239
Andrew de los Reyes80061062010-02-04 14:25:00 -0800240 vector<char> resultant_data;
241 EXPECT_TRUE(utils::ReadFile(path(), &resultant_data));
Alex Deymo161c4a12014-05-16 15:56:21 -0700242
Andrew de los Reyes80061062010-02-04 14:25:00 -0800243 // Create expected data
244 vector<char> expected_data(on_disk_count * kBlockSize);
245 vector<char> big(block_count * kBlockSize);
246 for (vector<char>::size_type i = 0; i < big.size(); i++) {
247 big[i] = data[i % data.size()];
248 }
249 memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
250 memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
251 ExpectVectorsEq(expected_data, resultant_data);
252}
253
254} // namespace chromeos_update_engine