1 //
2 // Copyright (C) 2023 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/block_extent_writer.h"
18
19 #include <fcntl.h>
20
21 #include <algorithm>
22 #include <memory>
23 #include <string>
24 #include <vector>
25
26 #include <gtest/gtest.h>
27 #include <gmock/gmock.h>
28
29 #include "update_engine/common/test_utils.h"
30 #include "update_engine/payload_generator/delta_diff_generator.h"
31 #include "update_engine/payload_generator/extent_utils.h"
32 #include "update_engine/common/utils.h"
33 #include "update_engine/payload_generator/extent_ranges.h"
34
35 using std::min;
36 using std::string;
37 using std::vector;
38 using testing::_;
39 using testing::Return;
40
41 namespace chromeos_update_engine {
42
43 class BlockExtentWriterTest : public ::testing::Test {
44 protected:
SetUp()45 void SetUp() override {}
TearDown()46 void TearDown() override {}
47 };
48
49 class MockBlockExtentWriter : public BlockExtentWriter {
50 public:
51 MOCK_METHOD(bool,
52 WriteExtent,
53 (const void*, const Extent&, size_t),
54 (override));
55 };
56
TEST_F(BlockExtentWriterTest,LongExtentTest)57 TEST_F(BlockExtentWriterTest, LongExtentTest) {
58 google::protobuf::RepeatedPtrField<Extent> extents;
59 *extents.Add() = ExtentForRange(0, 1);
60 *extents.Add() = ExtentForRange(2, 1);
61 *extents.Add() = ExtentForRange(4, 1);
62 // A single large extent which doesn't fit in 1 buffer
63 static constexpr auto BLOCKS_PER_BUFFER =
64 BlockExtentWriter::BUFFER_SIZE / kBlockSize;
65 *extents.Add() = ExtentForRange(10, BLOCKS_PER_BUFFER * 2);
66 MockBlockExtentWriter writer;
67 ASSERT_TRUE(writer.Init(extents, kBlockSize));
68 std::string buffer;
69 buffer.resize(BlockExtentWriter::BUFFER_SIZE * 2);
70 ON_CALL(writer, WriteExtent(_, _, _)).WillByDefault(Return(true));
71 EXPECT_CALL(writer,
72 WriteExtent(buffer.data(), ExtentForRange(0, 1), kBlockSize));
73 EXPECT_CALL(writer,
74 WriteExtent(static_cast<void*>(buffer.data() + kBlockSize),
75 ExtentForRange(2, 1),
76 kBlockSize));
77 EXPECT_CALL(writer,
78 WriteExtent(static_cast<void*>(buffer.data() + kBlockSize * 2),
79 ExtentForRange(4, 1),
80 kBlockSize));
81 // The last chunk should be split up into multiple chunks, each chunk is 1
82 // BUFFR_SIZE
83 EXPECT_CALL(writer,
84 WriteExtent(static_cast<void*>(buffer.data()),
85 ExtentForRange(10, BLOCKS_PER_BUFFER),
86 kBlockSize));
87 EXPECT_CALL(
88 writer,
89 WriteExtent(
90 static_cast<void*>(buffer.data() + BlockExtentWriter::BUFFER_SIZE),
91 ExtentForRange(10 + BLOCKS_PER_BUFFER, BLOCKS_PER_BUFFER),
92 kBlockSize));
93 ASSERT_TRUE(writer.Write(buffer.data(), kBlockSize * 3));
94 ASSERT_TRUE(writer.Write(buffer.data(), BlockExtentWriter::BUFFER_SIZE * 2));
95 }
96
TEST_F(BlockExtentWriterTest,LongExtentMultiCall)97 TEST_F(BlockExtentWriterTest, LongExtentMultiCall) {
98 google::protobuf::RepeatedPtrField<Extent> extents;
99 static constexpr auto BLOCKS_PER_BUFFER =
100 BlockExtentWriter::BUFFER_SIZE / kBlockSize;
101 *extents.Add() = ExtentForRange(10, BLOCKS_PER_BUFFER * 5);
102 MockBlockExtentWriter writer;
103 ASSERT_TRUE(writer.Init(extents, kBlockSize));
104 std::string buffer;
105 buffer.resize(BlockExtentWriter::BUFFER_SIZE * 2);
106 ON_CALL(writer, WriteExtent(_, _, _)).WillByDefault(Return(true));
107 // The last chunk should be split up into multiple chunks, each chunk is 1
108 // BUFFR_SIZE
109 EXPECT_CALL(writer,
110 WriteExtent(static_cast<void*>(buffer.data()),
111 ExtentForRange(10, BLOCKS_PER_BUFFER),
112 kBlockSize));
113 EXPECT_CALL(
114 writer,
115 WriteExtent(static_cast<void*>(buffer.data()),
116 ExtentForRange(10 + BLOCKS_PER_BUFFER, BLOCKS_PER_BUFFER),
117 kBlockSize));
118 EXPECT_CALL(
119 writer,
120 WriteExtent(static_cast<void*>(buffer.data()),
121 ExtentForRange(10 + BLOCKS_PER_BUFFER * 2, BLOCKS_PER_BUFFER),
122 kBlockSize));
123 ASSERT_TRUE(writer.Write(buffer.data(), BlockExtentWriter::BUFFER_SIZE));
124 ASSERT_TRUE(writer.Write(buffer.data(), BlockExtentWriter::BUFFER_SIZE));
125 ASSERT_TRUE(writer.Write(buffer.data(), BlockExtentWriter::BUFFER_SIZE));
126 }
127
FillArbitraryData(std::string * buffer)128 void FillArbitraryData(std::string* buffer) {
129 for (size_t i = 0; i < buffer->size(); i++) {
130 (*buffer)[i] = i;
131 }
132 }
133
TEST_F(BlockExtentWriterTest,SingleBufferMultiCall)134 TEST_F(BlockExtentWriterTest, SingleBufferMultiCall) {
135 google::protobuf::RepeatedPtrField<Extent> extents;
136 static constexpr auto BLOCKS_PER_BUFFER =
137 BlockExtentWriter::BUFFER_SIZE / kBlockSize;
138 *extents.Add() = ExtentForRange(10, BLOCKS_PER_BUFFER);
139 MockBlockExtentWriter writer;
140 ASSERT_TRUE(writer.Init(extents, kBlockSize));
141 std::string buffer;
142 buffer.resize(BlockExtentWriter::BUFFER_SIZE);
143 FillArbitraryData(&buffer);
144
145 ON_CALL(writer, WriteExtent(_, _, _)).WillByDefault(Return(true));
146 EXPECT_CALL(writer,
147 WriteExtent(_, ExtentForRange(10, BLOCKS_PER_BUFFER), kBlockSize))
148 .WillOnce([&buffer](const void* data, const Extent& extent, size_t) {
149 return memcmp(data, buffer.data(), buffer.size()) == 0;
150 });
151
152 ASSERT_TRUE(
153 writer.Write(buffer.data(), BlockExtentWriter::BUFFER_SIZE - kBlockSize));
154 ASSERT_TRUE(writer.Write(
155 buffer.data() + BlockExtentWriter::BUFFER_SIZE - kBlockSize, kBlockSize));
156 }
157
TEST_F(BlockExtentWriterTest,MultiBufferMultiCall)158 TEST_F(BlockExtentWriterTest, MultiBufferMultiCall) {
159 google::protobuf::RepeatedPtrField<Extent> extents;
160 static constexpr auto BLOCKS_PER_BUFFER =
161 BlockExtentWriter::BUFFER_SIZE / kBlockSize;
162 *extents.Add() = ExtentForRange(10, BLOCKS_PER_BUFFER + 1);
163 MockBlockExtentWriter writer;
164 ASSERT_TRUE(writer.Init(extents, kBlockSize));
165 std::string buffer;
166 buffer.resize(BlockExtentWriter::BUFFER_SIZE);
167 FillArbitraryData(&buffer);
168
169 ON_CALL(writer, WriteExtent(_, _, _)).WillByDefault(Return(true));
170 EXPECT_CALL(writer,
171 WriteExtent(_, ExtentForRange(10, BLOCKS_PER_BUFFER), kBlockSize))
172 .WillOnce([&buffer](const void* data, const Extent& extent, size_t) {
173 return memcmp(data, buffer.data(), extent.num_blocks() * kBlockSize) ==
174 0;
175 });
176 EXPECT_CALL(
177 writer,
178 WriteExtent(_, ExtentForRange(10 + BLOCKS_PER_BUFFER, 1), kBlockSize));
179
180 ASSERT_TRUE(writer.Write(buffer.data(), BlockExtentWriter::BUFFER_SIZE));
181 ASSERT_TRUE(writer.Write(buffer.data(), kBlockSize));
182 }
183
184 } // namespace chromeos_update_engine
185