blob: c3118fd19e67791c03ce7a10dc88a65afe8a1d57 [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
Alex Deymo10875d92014-11-10 21:52:57 -080021using chromeos_update_engine::test_utils::ExpectVectorsEq;
Andrew de los Reyes80061062010-02-04 14:25:00 -080022using std::min;
23using std::string;
24using std::vector;
25
26namespace chromeos_update_engine {
27
28COMPILE_ASSERT(sizeof(off_t) == 8, off_t_not_64_bit);
29
30namespace {
31const char kPathTemplate[] = "./ExtentWriterTest-file.XXXXXX";
32const size_t kBlockSize = 4096;
33}
34
35class ExtentWriterTest : public ::testing::Test {
36 protected:
37 virtual void SetUp() {
38 memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
39 fd_ = mkstemp(path_);
40 ASSERT_GE(fd_, 0);
41 }
42 virtual void TearDown() {
43 close(fd_);
44 unlink(path_);
45 }
46 int fd() { return fd_; }
47 const char* path() { return path_; }
Chris Masonef8d037f2014-02-19 01:53:00 +000048
Andrew de los Reyes80061062010-02-04 14:25:00 -080049 // Writes data to an extent writer in 'chunk_size' chunks with
50 // the first chunk of size first_chunk_size. It calculates what the
51 // resultant file should look like and ensure that the extent writer
52 // wrote the file correctly.
53 void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
54 void TestZeroPad(bool aligned_size);
55 private:
56 int fd_;
57 char path_[sizeof(kPathTemplate)];
58};
59
60TEST_F(ExtentWriterTest, SimpleTest) {
61 vector<Extent> extents;
62 Extent extent;
63 extent.set_start_block(1);
64 extent.set_num_blocks(1);
65 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -070066
Andrew de los Reyes80061062010-02-04 14:25:00 -080067 const string bytes = "1234";
68
69 DirectExtentWriter direct_writer;
70 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
71 EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
72 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -070073
Gabe Blacka77939e2014-09-09 23:35:08 -070074 EXPECT_EQ(kBlockSize + bytes.size(), utils::FileSize(fd()));
Alex Deymo161c4a12014-05-16 15:56:21 -070075
Andrew de los Reyes80061062010-02-04 14:25:00 -080076 vector<char> result_file;
77 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -070078
Andrew de los Reyes80061062010-02-04 14:25:00 -080079 vector<char> expected_file(kBlockSize);
80 expected_file.insert(expected_file.end(),
81 bytes.data(), bytes.data() + bytes.size());
82 ExpectVectorsEq(expected_file, result_file);
83}
84
85TEST_F(ExtentWriterTest, ZeroLengthTest) {
86 vector<Extent> extents;
87 Extent extent;
88 extent.set_start_block(1);
89 extent.set_num_blocks(1);
90 extents.push_back(extent);
91
92 DirectExtentWriter direct_writer;
93 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
Alex Vakulenko88b591f2014-08-28 16:48:57 -070094 EXPECT_TRUE(direct_writer.Write(nullptr, 0));
Andrew de los Reyes80061062010-02-04 14:25:00 -080095 EXPECT_TRUE(direct_writer.End());
96}
97
98TEST_F(ExtentWriterTest, OverflowExtentTest) {
99 WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
100}
101
102TEST_F(ExtentWriterTest, UnalignedWriteTest) {
103 WriteAlignedExtents(7, 7);
104}
105
106TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
107 WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
108}
109
110void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
111 size_t first_chunk_size) {
112 vector<Extent> extents;
113 Extent extent;
114 extent.set_start_block(1);
115 extent.set_num_blocks(1);
116 extents.push_back(extent);
117 extent.set_start_block(0);
118 extent.set_num_blocks(1);
119 extents.push_back(extent);
120 extent.set_start_block(2);
121 extent.set_num_blocks(1);
122 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700123
Andrew de los Reyes80061062010-02-04 14:25:00 -0800124 vector<char> data(kBlockSize * 3);
Alex Deymo10875d92014-11-10 21:52:57 -0800125 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700126
Andrew de los Reyes80061062010-02-04 14:25:00 -0800127 DirectExtentWriter direct_writer;
128 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700129
Andrew de los Reyes80061062010-02-04 14:25:00 -0800130 size_t bytes_written = 0;
131 while (bytes_written < data.size()) {
132 size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
133 if (bytes_written == 0) {
134 bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
135 }
136 EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
137 bytes_written += bytes_to_write;
138 }
139 EXPECT_TRUE(direct_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700140
Gabe Blacka77939e2014-09-09 23:35:08 -0700141 EXPECT_EQ(data.size(), utils::FileSize(fd()));
Alex Deymo161c4a12014-05-16 15:56:21 -0700142
Andrew de los Reyes80061062010-02-04 14:25:00 -0800143 vector<char> result_file;
144 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700145
Andrew de los Reyes80061062010-02-04 14:25:00 -0800146 vector<char> expected_file;
147 expected_file.insert(expected_file.end(),
148 data.begin() + kBlockSize,
149 data.begin() + kBlockSize * 2);
150 expected_file.insert(expected_file.end(),
151 data.begin(), data.begin() + kBlockSize);
152 expected_file.insert(expected_file.end(),
153 data.begin() + kBlockSize * 2, data.end());
154 ExpectVectorsEq(expected_file, result_file);
155}
156
157TEST_F(ExtentWriterTest, ZeroPadNullTest) {
158 TestZeroPad(true);
159}
160
161TEST_F(ExtentWriterTest, ZeroPadFillTest) {
162 TestZeroPad(false);
163}
164
165void ExtentWriterTest::TestZeroPad(bool aligned_size) {
166 vector<Extent> extents;
167 Extent extent;
168 extent.set_start_block(1);
169 extent.set_num_blocks(1);
170 extents.push_back(extent);
171 extent.set_start_block(0);
172 extent.set_num_blocks(1);
173 extents.push_back(extent);
Alex Deymo161c4a12014-05-16 15:56:21 -0700174
Andrew de los Reyes80061062010-02-04 14:25:00 -0800175 vector<char> data(kBlockSize * 2);
Alex Deymo10875d92014-11-10 21:52:57 -0800176 test_utils::FillWithData(&data);
Alex Deymo161c4a12014-05-16 15:56:21 -0700177
Andrew de los Reyes80061062010-02-04 14:25:00 -0800178 DirectExtentWriter direct_writer;
179 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
180
181 EXPECT_TRUE(zero_pad_writer.Init(fd(), extents, kBlockSize));
182 size_t bytes_to_write = data.size();
183 const size_t missing_bytes = (aligned_size ? 0 : 9);
184 bytes_to_write -= missing_bytes;
185 lseek64(fd(), kBlockSize - missing_bytes, SEEK_SET);
186 EXPECT_EQ(3, write(fd(), "xxx", 3));
187 ASSERT_TRUE(zero_pad_writer.Write(&data[0], bytes_to_write));
188 EXPECT_TRUE(zero_pad_writer.End());
Alex Deymo161c4a12014-05-16 15:56:21 -0700189
Gabe Blacka77939e2014-09-09 23:35:08 -0700190 EXPECT_EQ(data.size(), utils::FileSize(fd()));
Alex Deymo161c4a12014-05-16 15:56:21 -0700191
Andrew de los Reyes80061062010-02-04 14:25:00 -0800192 vector<char> result_file;
193 EXPECT_TRUE(utils::ReadFile(path(), &result_file));
Alex Deymo161c4a12014-05-16 15:56:21 -0700194
Andrew de los Reyes80061062010-02-04 14:25:00 -0800195 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);
Alex Deymo10875d92014-11-10 21:52:57 -0800224 test_utils::FillWithData(&data);
Andrew de los Reyes80061062010-02-04 14:25:00 -0800225
226 DirectExtentWriter direct_writer;
227 EXPECT_TRUE(direct_writer.Init(fd(), extents, kBlockSize));
Alex Deymo161c4a12014-05-16 15:56:21 -0700228
Andrew de los Reyes80061062010-02-04 14:25:00 -0800229 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());
Alex Deymo161c4a12014-05-16 15:56:21 -0700237
Andrew de los Reyes80061062010-02-04 14:25:00 -0800238 // check file size, then data inside
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700239 ASSERT_EQ(2 * kBlockSize, utils::FileSize(path()));
Alex Deymo161c4a12014-05-16 15:56:21 -0700240
Andrew de los Reyes80061062010-02-04 14:25:00 -0800241 vector<char> resultant_data;
242 EXPECT_TRUE(utils::ReadFile(path(), &resultant_data));
Alex Deymo161c4a12014-05-16 15:56:21 -0700243
Andrew de los Reyes80061062010-02-04 14:25:00 -0800244 // 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