blob: a35ba26e24e698e9b689a2e6fafa4781732b8812 [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
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8#include <algorithm>
9#include <string>
10#include <vector>
11#include <gtest/gtest.h>
12#include "update_engine/extent_writer.h"
13#include "update_engine/test_utils.h"
14#include "update_engine/utils.h"
15
16using std::min;
17using std::string;
18using std::vector;
19
20namespace chromeos_update_engine {
21
22COMPILE_ASSERT(sizeof(off_t) == 8, off_t_not_64_bit);
23
24namespace {
25const char kPathTemplate[] = "./ExtentWriterTest-file.XXXXXX";
26const size_t kBlockSize = 4096;
27}
28
29class ExtentWriterTest : public ::testing::Test {
30 protected:
31 virtual void SetUp() {
32 memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
33 fd_ = mkstemp(path_);
34 ASSERT_GE(fd_, 0);
35 }
36 virtual void TearDown() {
37 close(fd_);
38 unlink(path_);
39 }
40 int fd() { return fd_; }
41 const char* path() { return path_; }
42
43 // Writes data to an extent writer in 'chunk_size' chunks with
44 // the first chunk of size first_chunk_size. It calculates what the
45 // resultant file should look like and ensure that the extent writer
46 // wrote the file correctly.
47 void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
48 void TestZeroPad(bool aligned_size);
49 private:
50 int fd_;
51 char path_[sizeof(kPathTemplate)];
52};
53
54TEST_F(ExtentWriterTest, SimpleTest) {
55 vector<Extent> extents;
56 Extent extent;
57 extent.set_start_block(1);
58 extent.set_num_blocks(1);
59 extents.push_back(extent);
60
61 const string bytes = "1234";
62
63 DirectExtentWriter direct_writer;
64 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
65 EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
66 EXPECT_TRUE(direct_writer.End());
67
68 struct stat stbuf;
69 EXPECT_EQ(0, fstat(fd(), &stbuf));
70 EXPECT_EQ(kBlockSize + bytes.size(), stbuf.st_size);
71
72 vector<char> result_file;
73 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
74
75 vector<char> expected_file(kBlockSize);
76 expected_file.insert(expected_file.end(),
77 bytes.data(), bytes.data() + bytes.size());
78 ExpectVectorsEq(expected_file, result_file);
79}
80
81TEST_F(ExtentWriterTest, ZeroLengthTest) {
82 vector<Extent> extents;
83 Extent extent;
84 extent.set_start_block(1);
85 extent.set_num_blocks(1);
86 extents.push_back(extent);
87
88 DirectExtentWriter direct_writer;
89 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
90 EXPECT_TRUE(direct_writer.Write(NULL, 0));
91 EXPECT_TRUE(direct_writer.End());
92}
93
94TEST_F(ExtentWriterTest, OverflowExtentTest) {
95 WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
96}
97
98TEST_F(ExtentWriterTest, UnalignedWriteTest) {
99 WriteAlignedExtents(7, 7);
100}
101
102TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
103 WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
104}
105
106void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
107 size_t first_chunk_size) {
108 vector<Extent> extents;
109 Extent extent;
110 extent.set_start_block(1);
111 extent.set_num_blocks(1);
112 extents.push_back(extent);
113 extent.set_start_block(0);
114 extent.set_num_blocks(1);
115 extents.push_back(extent);
116 extent.set_start_block(2);
117 extent.set_num_blocks(1);
118 extents.push_back(extent);
119
120 vector<char> data(kBlockSize * 3);
121 FillWithData(&data);
122
123 DirectExtentWriter direct_writer;
124 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
125
126 size_t bytes_written = 0;
127 while (bytes_written < data.size()) {
128 size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
129 if (bytes_written == 0) {
130 bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
131 }
132 EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
133 bytes_written += bytes_to_write;
134 }
135 EXPECT_TRUE(direct_writer.End());
136
137 struct stat stbuf;
138 EXPECT_EQ(0, fstat(fd(), &stbuf));
139 EXPECT_EQ(data.size(), stbuf.st_size);
140
141 vector<char> result_file;
142 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
143
144 vector<char> expected_file;
145 expected_file.insert(expected_file.end(),
146 data.begin() + kBlockSize,
147 data.begin() + kBlockSize * 2);
148 expected_file.insert(expected_file.end(),
149 data.begin(), data.begin() + kBlockSize);
150 expected_file.insert(expected_file.end(),
151 data.begin() + kBlockSize * 2, data.end());
152 ExpectVectorsEq(expected_file, result_file);
153}
154
155TEST_F(ExtentWriterTest, ZeroPadNullTest) {
156 TestZeroPad(true);
157}
158
159TEST_F(ExtentWriterTest, ZeroPadFillTest) {
160 TestZeroPad(false);
161}
162
163void ExtentWriterTest::TestZeroPad(bool aligned_size) {
164 vector<Extent> extents;
165 Extent extent;
166 extent.set_start_block(1);
167 extent.set_num_blocks(1);
168 extents.push_back(extent);
169 extent.set_start_block(0);
170 extent.set_num_blocks(1);
171 extents.push_back(extent);
172
173 vector<char> data(kBlockSize * 2);
174 FillWithData(&data);
175
176 DirectExtentWriter direct_writer;
177 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
178
179 EXPECT_TRUE(zero_pad_writer.Init(fd(), extents, kBlockSize));
180 size_t bytes_to_write = data.size();
181 const size_t missing_bytes = (aligned_size ? 0 : 9);
182 bytes_to_write -= missing_bytes;
183 lseek64(fd(), kBlockSize - missing_bytes, SEEK_SET);
184 EXPECT_EQ(3, write(fd(), "xxx", 3));
185 ASSERT_TRUE(zero_pad_writer.Write(&data[0], bytes_to_write));
186 EXPECT_TRUE(zero_pad_writer.End());
187
188 struct stat stbuf;
189 EXPECT_EQ(0, fstat(fd(), &stbuf));
190 EXPECT_EQ(data.size(), stbuf.st_size);
191
192 vector<char> result_file;
193 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
194
195 vector<char> expected_file;
196 expected_file.insert(expected_file.end(),
197 data.begin() + kBlockSize,
198 data.begin() + kBlockSize * 2);
199 expected_file.insert(expected_file.end(),
200 data.begin(), data.begin() + kBlockSize);
201 if (missing_bytes) {
202 memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
203 }
204
205 ExpectVectorsEq(expected_file, result_file);
206}
207
208TEST_F(ExtentWriterTest, SparseFileTest) {
209 vector<Extent> extents;
210 Extent extent;
211 extent.set_start_block(1);
212 extent.set_num_blocks(1);
213 extents.push_back(extent);
214 extent.set_start_block(kSparseHole);
215 extent.set_num_blocks(2);
216 extents.push_back(extent);
217 extent.set_start_block(0);
218 extent.set_num_blocks(1);
219 extents.push_back(extent);
220 const int block_count = 4;
221 const int on_disk_count = 2;
222
223 vector<char> data(17);
224 FillWithData(&data);
225
226 DirectExtentWriter direct_writer;
227 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
228
229 size_t bytes_written = 0;
230 while (bytes_written < (block_count * kBlockSize)) {
231 size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
232 data.size());
233 EXPECT_TRUE(direct_writer.Write(&data[0], bytes_to_write));
234 bytes_written += bytes_to_write;
235 }
236 EXPECT_TRUE(direct_writer.End());
237
238 // check file size, then data inside
239 ASSERT_EQ(2 * kBlockSize, FileSize(path()));
240
241 vector<char> resultant_data;
242 EXPECT_TRUE(utils::ReadFile(path(), &resultant_data));
243
244 // Create expected data
245 vector<char> expected_data(on_disk_count * kBlockSize);
246 vector<char> big(block_count * kBlockSize);
247 for (vector<char>::size_type i = 0; i < big.size(); i++) {
248 big[i] = data[i % data.size()];
249 }
250 memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
251 memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
252 ExpectVectorsEq(expected_data, resultant_data);
253}
254
255} // namespace chromeos_update_engine