xref: /aosp_15_r20/system/update_engine/payload_consumer/block_extent_writer_unittest.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
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