1 //
2 // Copyright (C) 2017 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_reader.h"
18 
19 #include <fcntl.h>
20 
21 #include <algorithm>
22 #include <string>
23 #include <vector>
24 
25 #include <brillo/secure_blob.h>
26 #include <gtest/gtest.h>
27 
28 #include "update_engine/common/test_utils.h"
29 #include "update_engine/common/utils.h"
30 #include "update_engine/payload_consumer/file_descriptor.h"
31 #include "update_engine/payload_consumer/payload_constants.h"
32 #include "update_engine/payload_generator/extent_ranges.h"
33 #include "update_engine/payload_generator/extent_utils.h"
34 
35 using chromeos_update_engine::test_utils::ExpectVectorsEq;
36 using std::min;
37 using std::string;
38 using std::vector;
39 
40 namespace chromeos_update_engine {
41 
42 namespace {
43 const size_t kBlockSize = 8;
44 const size_t kRandomIterations = 1000;
45 }  // namespace
46 
47 class ExtentReaderTest : public ::testing::Test {
48  protected:
SetUp()49   void SetUp() override {
50     sample_.resize(4096 * 10);
51     srand(time(nullptr));
52     unsigned int rand_seed;
53     for (size_t i = 0; i < sample_.size(); i++) {
54       sample_[i] = rand_r(&rand_seed) % 256;
55     }
56     ASSERT_TRUE(utils::WriteFile(
57         temp_file_.path().c_str(), sample_.data(), sample_.size()));
58 
59     fd_.reset(new EintrSafeFileDescriptor());
60     ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDONLY, 0600));
61   }
TearDown()62   void TearDown() override { fd_->Close(); }
63 
ReadExtents(vector<Extent> extents,brillo::Blob * blob)64   void ReadExtents(vector<Extent> extents, brillo::Blob* blob) {
65     blob->clear();
66     for (const auto& extent : extents) {
67       blob->insert(
68           blob->end(),
69           &sample_[extent.start_block() * kBlockSize],
70           &sample_[(extent.start_block() + extent.num_blocks()) * kBlockSize]);
71     }
72   }
73 
74   FileDescriptorPtr fd_;
75   ScopedTempFile temp_file_{"ExtentReaderTest-file.XXXXXX"};
76   brillo::Blob sample_;
77 };
78 
TEST_F(ExtentReaderTest,SimpleTest)79 TEST_F(ExtentReaderTest, SimpleTest) {
80   vector<Extent> extents = {ExtentForRange(1, 1)};
81   DirectExtentReader reader;
82   EXPECT_TRUE(reader.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
83   EXPECT_TRUE(reader.Seek(0));
84   brillo::Blob blob1(utils::BlocksInExtents(extents) * kBlockSize);
85   EXPECT_TRUE(reader.Read(blob1.data(), blob1.size()));
86   brillo::Blob blob2;
87   ReadExtents(extents, &blob2);
88   ExpectVectorsEq(blob1, blob2);
89 }
90 
TEST_F(ExtentReaderTest,ZeroExtentLengthTest)91 TEST_F(ExtentReaderTest, ZeroExtentLengthTest) {
92   vector<Extent> extents = {ExtentForRange(1, 0)};
93   DirectExtentReader reader;
94   EXPECT_TRUE(reader.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
95   EXPECT_TRUE(reader.Seek(0));
96   brillo::Blob blob(1);
97   EXPECT_TRUE(reader.Read(blob.data(), 0));
98   EXPECT_FALSE(reader.Read(blob.data(), 1));
99 }
100 
TEST_F(ExtentReaderTest,NoExtentTest)101 TEST_F(ExtentReaderTest, NoExtentTest) {
102   DirectExtentReader reader;
103   EXPECT_TRUE(reader.Init(fd_, {}, kBlockSize));
104   EXPECT_TRUE(reader.Seek(0));
105   brillo::Blob blob(1);
106   EXPECT_TRUE(reader.Read(blob.data(), 0));
107   EXPECT_FALSE(reader.Read(blob.data(), 1));
108 }
109 
TEST_F(ExtentReaderTest,OverflowExtentTest)110 TEST_F(ExtentReaderTest, OverflowExtentTest) {
111   vector<Extent> extents = {ExtentForRange(1, 1)};
112   DirectExtentReader reader;
113   EXPECT_TRUE(reader.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
114   EXPECT_TRUE(reader.Seek(0));
115   brillo::Blob blob(utils::BlocksInExtents(extents) * kBlockSize + 1);
116   EXPECT_FALSE(reader.Read(blob.data(), blob.size()));
117 }
118 
TEST_F(ExtentReaderTest,SeekOverflow1Test)119 TEST_F(ExtentReaderTest, SeekOverflow1Test) {
120   vector<Extent> extents = {ExtentForRange(1, 0)};
121   DirectExtentReader reader;
122   EXPECT_TRUE(reader.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
123   EXPECT_TRUE(reader.Seek(0));
124   EXPECT_FALSE(reader.Seek(1));
125 }
126 
TEST_F(ExtentReaderTest,SeekOverflow2Test)127 TEST_F(ExtentReaderTest, SeekOverflow2Test) {
128   DirectExtentReader reader;
129   reader.Init(fd_, {}, kBlockSize);
130   EXPECT_TRUE(reader.Seek(0));
131   EXPECT_FALSE(reader.Seek(1));
132 }
133 
TEST_F(ExtentReaderTest,SeekOverflow3Test)134 TEST_F(ExtentReaderTest, SeekOverflow3Test) {
135   vector<Extent> extents = {ExtentForRange(1, 1)};
136   DirectExtentReader reader;
137   EXPECT_TRUE(reader.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
138   // Seek to the end of the extents should be fine as long as nothing is read.
139   EXPECT_TRUE(reader.Seek(kBlockSize));
140   EXPECT_FALSE(reader.Seek(kBlockSize + 1));
141 }
142 
TEST_F(ExtentReaderTest,RandomReadTest)143 TEST_F(ExtentReaderTest, RandomReadTest) {
144   vector<Extent> extents = {ExtentForRange(0, 0),
145                             ExtentForRange(1, 1),
146                             ExtentForRange(3, 0),
147                             ExtentForRange(4, 2),
148                             ExtentForRange(7, 1)};
149   DirectExtentReader reader;
150   EXPECT_TRUE(reader.Init(fd_, {extents.begin(), extents.end()}, kBlockSize));
151 
152   brillo::Blob result;
153   ReadExtents(extents, &result);
154 
155   brillo::Blob blob(utils::BlocksInExtents(extents) * kBlockSize);
156   srand(time(nullptr));
157   uint32_t rand_seed;
158   for (size_t idx = 0; idx < kRandomIterations; idx++) {
159     // zero to full size available.
160     size_t start = rand_r(&rand_seed) % blob.size();
161     size_t size = rand_r(&rand_seed) % (blob.size() - start);
162     EXPECT_TRUE(reader.Seek(start));
163     EXPECT_TRUE(reader.Read(blob.data(), size));
164     for (size_t i = 0; i < size; i++) {
165       ASSERT_EQ(blob[i], result[start + i]);
166     }
167   }
168 }
169 
170 }  // namespace chromeos_update_engine
171