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   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{fd_};
69   EXPECT_TRUE(direct_writer.Init({extents.begin(), extents.end()}, kBlockSize));
70   EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
71 
72   EXPECT_EQ(static_cast<off_t>(kBlockSize + bytes.size()),
73             utils::FileSize(temp_file_.path()));
74 
75   brillo::Blob result_file;
76   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
77 
78   brillo::Blob expected_file(kBlockSize);
79   expected_file.insert(
80       expected_file.end(), bytes.data(), bytes.data() + bytes.size());
81   ExpectVectorsEq(expected_file, result_file);
82 }
83 
84 TEST_F(ExtentWriterTest, ZeroLengthTest) {
85   vector<Extent> extents = {ExtentForRange(1, 1)};
86   DirectExtentWriter direct_writer{fd_};
87   EXPECT_TRUE(direct_writer.Init({extents.begin(), extents.end()}, kBlockSize));
88   EXPECT_TRUE(direct_writer.Write(nullptr, 0));
89 }
90 
91 TEST_F(ExtentWriterTest, OverflowExtentTest) {
92   WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
93 }
94 
95 TEST_F(ExtentWriterTest, UnalignedWriteTest) {
96   WriteAlignedExtents(7, 7);
97 }
98 
99 TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
100   WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
101 }
102 
103 void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
104                                            size_t first_chunk_size) {
105   vector<Extent> extents = {
106       ExtentForRange(1, 1), ExtentForRange(0, 1), ExtentForRange(2, 1)};
107   brillo::Blob data(kBlockSize * 3);
108   test_utils::FillWithData(&data);
109 
110   DirectExtentWriter direct_writer{fd_};
111   EXPECT_TRUE(direct_writer.Init({extents.begin(), extents.end()}, kBlockSize));
112 
113   size_t bytes_written = 0;
114   while (bytes_written < data.size()) {
115     size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
116     if (bytes_written == 0) {
117       bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
118     }
119     EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
120     bytes_written += bytes_to_write;
121   }
122 
123   EXPECT_EQ(static_cast<off_t>(data.size()),
124             utils::FileSize(temp_file_.path()));
125 
126   brillo::Blob result_file;
127   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
128 
129   brillo::Blob expected_file;
130   expected_file.insert(expected_file.end(),
131                        data.begin() + kBlockSize,
132                        data.begin() + kBlockSize * 2);
133   expected_file.insert(
134       expected_file.end(), data.begin(), data.begin() + kBlockSize);
135   expected_file.insert(
136       expected_file.end(), data.begin() + kBlockSize * 2, data.end());
137   ExpectVectorsEq(expected_file, result_file);
138 }
139 
140 TEST_F(ExtentWriterTest, SparseFileTest) {
141   vector<Extent> extents = {ExtentForRange(1, 1),
142                             ExtentForRange(kSparseHole, 2),
143                             ExtentForRange(0, 1)};
144   const int block_count = 4;
145   const int on_disk_count = 2;
146 
147   brillo::Blob data(17);
148   test_utils::FillWithData(&data);
149 
150   DirectExtentWriter direct_writer{fd_};
151   EXPECT_TRUE(direct_writer.Init({extents.begin(), extents.end()}, kBlockSize));
152 
153   size_t bytes_written = 0;
154   while (bytes_written < (block_count * kBlockSize)) {
155     size_t bytes_to_write =
156         min(block_count * kBlockSize - bytes_written, data.size());
157     EXPECT_TRUE(direct_writer.Write(data.data(), bytes_to_write));
158     bytes_written += bytes_to_write;
159   }
160 
161   // check file size, then data inside
162   ASSERT_EQ(static_cast<off_t>(2 * kBlockSize),
163             utils::FileSize(temp_file_.path()));
164 
165   brillo::Blob resultant_data;
166   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &resultant_data));
167 
168   // Create expected data
169   brillo::Blob expected_data(on_disk_count * kBlockSize);
170   brillo::Blob big(block_count * kBlockSize);
171   for (brillo::Blob::size_type i = 0; i < big.size(); i++) {
172     big[i] = data[i % data.size()];
173   }
174   memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
175   memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
176   ExpectVectorsEq(expected_data, resultant_data);
177 }
178 
179 }  // namespace chromeos_update_engine
180