1 //
2 // Copyright (C) 2009 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "update_engine/payload_consumer/extent_writer.h"
18 
19 #include <fcntl.h>
20 
21 #include <algorithm>
22 #include <memory>
23 #include <string>
24 #include <vector>
25 
26 #include <brillo/secure_blob.h>
27 #include <gtest/gtest.h>
28 
29 #include "update_engine/common/test_utils.h"
30 #include "update_engine/common/utils.h"
31 #include "update_engine/payload_consumer/payload_constants.h"
32 #include "update_engine/payload_generator/extent_ranges.h"
33 
34 using chromeos_update_engine::test_utils::ExpectVectorsEq;
35 using std::min;
36 using std::string;
37 using std::vector;
38 
39 namespace chromeos_update_engine {
40 
41 static_assert(sizeof(off_t) == 8, "off_t not 64 bit");
42 
43 namespace {
44 const size_t kBlockSize = 4096;
45 }
46 
47 class ExtentWriterTest : public ::testing::Test {
48  protected:
49   void SetUp() override {
50     fd_.reset(new EintrSafeFileDescriptor);
51     ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600));
52   }
53   void TearDown() override { fd_->Close(); }
54 
55   // Writes data to an extent writer in 'chunk_size' chunks with
56   // the first chunk of size first_chunk_size. It calculates what the
57   // resultant file should look like and ensure that the extent writer
58   // wrote the file correctly.
59   void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
60 
61   FileDescriptorPtr fd_;
62   test_utils::ScopedTempFile temp_file_{"ExtentWriterTest-file.XXXXXX"};
63 };
64 
65 TEST_F(ExtentWriterTest, SimpleTest) {
66   vector<Extent> extents = {ExtentForRange(1, 1)};
67   const string bytes = "1234";
68   DirectExtentWriter direct_writer;
69   EXPECT_TRUE(
70       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
71   EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
72 
73   EXPECT_EQ(static_cast<off_t>(kBlockSize + bytes.size()),
74             utils::FileSize(temp_file_.path()));
75 
76   brillo::Blob result_file;
77   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
78 
79   brillo::Blob expected_file(kBlockSize);
80   expected_file.insert(
81       expected_file.end(), bytes.data(), bytes.data() + bytes.size());
82   ExpectVectorsEq(expected_file, result_file);
83 }
84 
85 TEST_F(ExtentWriterTest, ZeroLengthTest) {
86   vector<Extent> extents = {ExtentForRange(1, 1)};
87   DirectExtentWriter direct_writer;
88   EXPECT_TRUE(
89       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
90   EXPECT_TRUE(direct_writer.Write(nullptr, 0));
91 }
92 
93 TEST_F(ExtentWriterTest, OverflowExtentTest) {
94   WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
95 }
96 
97 TEST_F(ExtentWriterTest, UnalignedWriteTest) {
98   WriteAlignedExtents(7, 7);
99 }
100 
101 TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
102   WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
103 }
104 
105 void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
106                                            size_t first_chunk_size) {
107   vector<Extent> extents = {
108       ExtentForRange(1, 1), ExtentForRange(0, 1), ExtentForRange(2, 1)};
109   brillo::Blob data(kBlockSize * 3);
110   test_utils::FillWithData(&data);
111 
112   DirectExtentWriter direct_writer;
113   EXPECT_TRUE(
114       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
115 
116   size_t bytes_written = 0;
117   while (bytes_written < data.size()) {
118     size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
119     if (bytes_written == 0) {
120       bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
121     }
122     EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
123     bytes_written += bytes_to_write;
124   }
125 
126   EXPECT_EQ(static_cast<off_t>(data.size()),
127             utils::FileSize(temp_file_.path()));
128 
129   brillo::Blob result_file;
130   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
131 
132   brillo::Blob expected_file;
133   expected_file.insert(expected_file.end(),
134                        data.begin() + kBlockSize,
135                        data.begin() + kBlockSize * 2);
136   expected_file.insert(
137       expected_file.end(), data.begin(), data.begin() + kBlockSize);
138   expected_file.insert(
139       expected_file.end(), data.begin() + kBlockSize * 2, data.end());
140   ExpectVectorsEq(expected_file, result_file);
141 }
142 
143 TEST_F(ExtentWriterTest, SparseFileTest) {
144   vector<Extent> extents = {ExtentForRange(1, 1),
145                             ExtentForRange(kSparseHole, 2),
146                             ExtentForRange(0, 1)};
147   const int block_count = 4;
148   const int on_disk_count = 2;
149 
150   brillo::Blob data(17);
151   test_utils::FillWithData(&data);
152 
153   DirectExtentWriter direct_writer;
154   EXPECT_TRUE(
155       direct_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
156 
157   size_t bytes_written = 0;
158   while (bytes_written < (block_count * kBlockSize)) {
159     size_t bytes_to_write =
160         min(block_count * kBlockSize - bytes_written, data.size());
161     EXPECT_TRUE(direct_writer.Write(data.data(), bytes_to_write));
162     bytes_written += bytes_to_write;
163   }
164 
165   // check file size, then data inside
166   ASSERT_EQ(static_cast<off_t>(2 * kBlockSize),
167             utils::FileSize(temp_file_.path()));
168 
169   brillo::Blob resultant_data;
170   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &resultant_data));
171 
172   // Create expected data
173   brillo::Blob expected_data(on_disk_count * kBlockSize);
174   brillo::Blob big(block_count * kBlockSize);
175   for (brillo::Blob::size_type i = 0; i < big.size(); i++) {
176     big[i] = data[i % data.size()];
177   }
178   memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
179   memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
180   ExpectVectorsEq(expected_data, resultant_data);
181 }
182 
183 }  // namespace chromeos_update_engine
184