1 //
2 // Copyright (C) 2019 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 "snapshot_metadata_updater.h"
18
19 #include <memory>
20 #include <string>
21
22 #include <android-base/properties.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <liblp/builder.h>
26 #include <storage_literals/storage_literals.h>
27
28 #include <libsnapshot/test_helpers.h>
29
30 using namespace android::storage_literals;
31 using android::fs_mgr::LpMetadata;
32 using android::fs_mgr::MetadataBuilder;
33 using android::fs_mgr::SlotSuffixForSlotNumber;
34 using chromeos_update_engine::DeltaArchiveManifest;
35 using chromeos_update_engine::DynamicPartitionGroup;
36 using chromeos_update_engine::PartitionUpdate;
37 using testing::AssertionFailure;
38 using testing::AssertionResult;
39 using testing::AssertionSuccess;
40
41 namespace android {
42 namespace snapshot {
43
44 class SnapshotMetadataUpdaterTest : public ::testing::TestWithParam<uint32_t> {
45 public:
46 SnapshotMetadataUpdaterTest() = default;
47
SetUp()48 void SetUp() override {
49 SKIP_IF_NON_VIRTUAL_AB();
50
51 target_slot_ = GetParam();
52 target_suffix_ = SlotSuffixForSlotNumber(target_slot_);
53 SnapshotTestPropertyFetcher::SetUp(SlotSuffixForSlotNumber(1 - target_slot_));
54 builder_ = MetadataBuilder::New(4_GiB + 1_MiB, 4_KiB, 2);
55
56 group_ = manifest_.mutable_dynamic_partition_metadata()->add_groups();
57 group_->set_name("group");
58 group_->set_size(4_GiB);
59 group_->add_partition_names("system");
60 group_->add_partition_names("vendor");
61 system_ = manifest_.add_partitions();
62 system_->set_partition_name("system");
63 SetSize(system_, 2_GiB);
64 vendor_ = manifest_.add_partitions();
65 vendor_->set_partition_name("vendor");
66 SetSize(vendor_, 1_GiB);
67
68 ASSERT_TRUE(FillFakeMetadata(builder_.get(), manifest_, target_suffix_));
69 }
70
TearDown()71 void TearDown() override {
72 RETURN_IF_NON_VIRTUAL_AB();
73
74 SnapshotTestPropertyFetcher::TearDown();
75 }
76
77 // Append suffix to name.
T(std::string_view name)78 std::string T(std::string_view name) { return std::string(name) + target_suffix_; }
79
UpdateAndExport()80 AssertionResult UpdateAndExport() {
81 SnapshotMetadataUpdater updater(builder_.get(), target_slot_, manifest_);
82 if (!updater.Update()) {
83 return AssertionFailure() << "Update failed.";
84 }
85
86 exported_ = builder_->Export();
87 if (exported_ == nullptr) {
88 return AssertionFailure() << "Export failed.";
89 }
90 return AssertionSuccess();
91 }
92
93 // Check that in |builder_|, partition |name| + |target_suffix_| has the given |size|.
CheckSize(std::string_view name,uint64_t size)94 AssertionResult CheckSize(std::string_view name, uint64_t size) {
95 auto p = builder_->FindPartition(T(name));
96 if (p == nullptr) {
97 return AssertionFailure() << "Cannot find partition " << T(name);
98 }
99 if (p->size() != size) {
100 return AssertionFailure() << "Partition " << T(name) << " should be " << size
101 << " bytes, but is " << p->size() << " bytes.";
102 }
103 return AssertionSuccess() << "Partition" << T(name) << " is " << size << " bytes.";
104 }
105
106 // Check that in |builder_|, group |name| + |target_suffix_| has the given |size|.
CheckGroupSize(std::string_view name,uint64_t size)107 AssertionResult CheckGroupSize(std::string_view name, uint64_t size) {
108 auto g = builder_->FindGroup(T(name));
109 if (g == nullptr) {
110 return AssertionFailure() << "Cannot find group " << T(name);
111 }
112 if (g->maximum_size() != size) {
113 return AssertionFailure() << "Group " << T(name) << " should be " << size
114 << " bytes, but is " << g->maximum_size() << " bytes.";
115 }
116 return AssertionSuccess() << "Group" << T(name) << " is " << size << " bytes.";
117 }
118
119 // Check that in |builder_|, partition |partition_name| + |target_suffix_| is in group
120 // |group_name| + |target_suffix_|;
CheckGroupName(std::string_view partition_name,std::string_view group_name)121 AssertionResult CheckGroupName(std::string_view partition_name, std::string_view group_name) {
122 auto p = builder_->FindPartition(T(partition_name));
123 if (p == nullptr) {
124 return AssertionFailure() << "Cannot find partition " << T(partition_name);
125 }
126 if (p->group_name() != T(group_name)) {
127 return AssertionFailure() << "Partition " << T(partition_name) << " should be in "
128 << T(group_name) << ", but is in " << p->group_name() << ".";
129 }
130 return AssertionSuccess() << "Partition" << T(partition_name) << " is in " << T(group_name)
131 << ".";
132 }
133
134 std::unique_ptr<MetadataBuilder> builder_;
135 uint32_t target_slot_;
136 std::string target_suffix_;
137 DeltaArchiveManifest manifest_;
138 std::unique_ptr<LpMetadata> exported_;
139 DynamicPartitionGroup* group_ = nullptr;
140 PartitionUpdate* system_ = nullptr;
141 PartitionUpdate* vendor_ = nullptr;
142 };
143
TEST_P(SnapshotMetadataUpdaterTest,NoChange)144 TEST_P(SnapshotMetadataUpdaterTest, NoChange) {
145 EXPECT_TRUE(UpdateAndExport());
146
147 EXPECT_TRUE(CheckGroupSize("group", 4_GiB));
148 EXPECT_TRUE(CheckSize("system", 2_GiB));
149 EXPECT_TRUE(CheckGroupName("system", "group"));
150 EXPECT_TRUE(CheckSize("vendor", 1_GiB));
151 EXPECT_TRUE(CheckGroupName("vendor", "group"));
152 }
153
TEST_P(SnapshotMetadataUpdaterTest,GrowWithinBounds)154 TEST_P(SnapshotMetadataUpdaterTest, GrowWithinBounds) {
155 SetSize(system_, 2_GiB + 512_MiB);
156 SetSize(vendor_, 1_GiB + 512_MiB);
157
158 ASSERT_TRUE(UpdateAndExport());
159
160 EXPECT_TRUE(CheckSize("system", 2_GiB + 512_MiB));
161 EXPECT_TRUE(CheckSize("vendor", 1_GiB + 512_MiB));
162 }
163
TEST_P(SnapshotMetadataUpdaterTest,GrowOverSuper)164 TEST_P(SnapshotMetadataUpdaterTest, GrowOverSuper) {
165 SetSize(system_, 3_GiB);
166 SetSize(vendor_, 1_GiB + 512_MiB);
167
168 EXPECT_FALSE(UpdateAndExport());
169 }
170
TEST_P(SnapshotMetadataUpdaterTest,GrowOverGroup)171 TEST_P(SnapshotMetadataUpdaterTest, GrowOverGroup) {
172 SetSize(system_, 3_GiB);
173 SetSize(vendor_, 1_GiB + 4_KiB);
174
175 EXPECT_FALSE(UpdateAndExport());
176 }
177
TEST_P(SnapshotMetadataUpdaterTest,Add)178 TEST_P(SnapshotMetadataUpdaterTest, Add) {
179 group_->add_partition_names("product");
180 auto product = manifest_.add_partitions();
181 product->set_partition_name("product");
182 SetSize(product, 1_GiB);
183
184 EXPECT_TRUE(UpdateAndExport());
185
186 EXPECT_TRUE(CheckSize("system", 2_GiB));
187 EXPECT_TRUE(CheckSize("vendor", 1_GiB));
188 EXPECT_TRUE(CheckSize("product", 1_GiB));
189 }
190
TEST_P(SnapshotMetadataUpdaterTest,AddTooBig)191 TEST_P(SnapshotMetadataUpdaterTest, AddTooBig) {
192 group_->add_partition_names("product");
193 auto product = manifest_.add_partitions();
194 product->set_partition_name("product");
195 SetSize(product, 1_GiB + 4_KiB);
196
197 EXPECT_FALSE(UpdateAndExport());
198 }
199
TEST_P(SnapshotMetadataUpdaterTest,ShrinkAll)200 TEST_P(SnapshotMetadataUpdaterTest, ShrinkAll) {
201 SetSize(system_, 1_GiB);
202 SetSize(vendor_, 512_MiB);
203
204 ASSERT_TRUE(UpdateAndExport());
205
206 EXPECT_TRUE(CheckSize("system", 1_GiB));
207 EXPECT_TRUE(CheckSize("vendor", 512_MiB));
208 }
209
TEST_P(SnapshotMetadataUpdaterTest,ShrinkAndGrow)210 TEST_P(SnapshotMetadataUpdaterTest, ShrinkAndGrow) {
211 SetSize(system_, 3_GiB + 512_MiB);
212 SetSize(vendor_, 512_MiB);
213
214 ASSERT_TRUE(UpdateAndExport());
215
216 EXPECT_TRUE(CheckSize("system", 3_GiB + 512_MiB));
217 EXPECT_TRUE(CheckSize("vendor", 512_MiB));
218 }
219
TEST_P(SnapshotMetadataUpdaterTest,ShrinkAndAdd)220 TEST_P(SnapshotMetadataUpdaterTest, ShrinkAndAdd) {
221 SetSize(system_, 2_GiB);
222 SetSize(vendor_, 512_MiB);
223 group_->add_partition_names("product");
224 auto product = manifest_.add_partitions();
225 product->set_partition_name("product");
226 SetSize(product, 1_GiB + 512_MiB);
227
228 ASSERT_TRUE(UpdateAndExport());
229
230 EXPECT_TRUE(CheckSize("system", 2_GiB));
231 EXPECT_TRUE(CheckSize("vendor", 512_MiB));
232 EXPECT_TRUE(CheckSize("product", 1_GiB + 512_MiB));
233 }
234
TEST_P(SnapshotMetadataUpdaterTest,Delete)235 TEST_P(SnapshotMetadataUpdaterTest, Delete) {
236 group_->mutable_partition_names()->RemoveLast();
237 // No need to delete it from manifest.partitions as SnapshotMetadataUpdater
238 // should ignore them (treat them as static partitions).
239
240 EXPECT_TRUE(UpdateAndExport());
241
242 EXPECT_TRUE(CheckSize("system", 2_GiB));
243 EXPECT_EQ(nullptr, builder_->FindPartition(T("vendor")));
244 }
245
TEST_P(SnapshotMetadataUpdaterTest,DeleteAndGrow)246 TEST_P(SnapshotMetadataUpdaterTest, DeleteAndGrow) {
247 group_->mutable_partition_names()->RemoveLast();
248 SetSize(system_, 4_GiB);
249
250 EXPECT_TRUE(UpdateAndExport());
251
252 EXPECT_TRUE(CheckSize("system", 4_GiB));
253 }
254
TEST_P(SnapshotMetadataUpdaterTest,DeleteAndAdd)255 TEST_P(SnapshotMetadataUpdaterTest, DeleteAndAdd) {
256 group_->mutable_partition_names()->RemoveLast();
257 group_->add_partition_names("product");
258 auto product = manifest_.add_partitions();
259 product->set_partition_name("product");
260 SetSize(product, 2_GiB);
261
262 EXPECT_TRUE(UpdateAndExport());
263
264 EXPECT_TRUE(CheckSize("system", 2_GiB));
265 EXPECT_EQ(nullptr, builder_->FindPartition(T("vendor")));
266 EXPECT_TRUE(CheckSize("product", 2_GiB));
267 }
268
TEST_P(SnapshotMetadataUpdaterTest,GrowGroup)269 TEST_P(SnapshotMetadataUpdaterTest, GrowGroup) {
270 group_->set_size(4_GiB + 512_KiB);
271 SetSize(system_, 2_GiB + 256_KiB);
272 SetSize(vendor_, 2_GiB + 256_KiB);
273
274 EXPECT_TRUE(UpdateAndExport());
275
276 EXPECT_TRUE(CheckSize("system", 2_GiB + 256_KiB));
277 EXPECT_TRUE(CheckSize("vendor", 2_GiB + 256_KiB));
278 }
279
TEST_P(SnapshotMetadataUpdaterTest,ShrinkGroup)280 TEST_P(SnapshotMetadataUpdaterTest, ShrinkGroup) {
281 group_->set_size(1_GiB);
282 SetSize(system_, 512_MiB);
283 SetSize(vendor_, 512_MiB);
284
285 EXPECT_TRUE(UpdateAndExport());
286
287 EXPECT_TRUE(CheckSize("system", 512_MiB));
288 EXPECT_TRUE(CheckSize("vendor", 512_MiB));
289 }
290
TEST_P(SnapshotMetadataUpdaterTest,MoveToNewGroup)291 TEST_P(SnapshotMetadataUpdaterTest, MoveToNewGroup) {
292 group_->mutable_partition_names()->RemoveLast();
293 group_->set_size(2_GiB);
294
295 auto another_group = manifest_.mutable_dynamic_partition_metadata()->add_groups();
296 another_group->set_name("another_group");
297 another_group->set_size(2_GiB);
298 another_group->add_partition_names("vendor");
299 SetSize(vendor_, 2_GiB);
300
301 EXPECT_TRUE(UpdateAndExport());
302
303 EXPECT_TRUE(CheckGroupSize("group", 2_GiB));
304 EXPECT_TRUE(CheckGroupSize("another_group", 2_GiB));
305 EXPECT_TRUE(CheckSize("system", 2_GiB));
306 EXPECT_TRUE(CheckGroupName("system", "group"));
307 EXPECT_TRUE(CheckSize("vendor", 2_GiB));
308 EXPECT_TRUE(CheckGroupName("vendor", "another_group"));
309 }
310
TEST_P(SnapshotMetadataUpdaterTest,DeleteAndAddGroup)311 TEST_P(SnapshotMetadataUpdaterTest, DeleteAndAddGroup) {
312 manifest_.mutable_dynamic_partition_metadata()->mutable_groups()->RemoveLast();
313 group_ = nullptr;
314
315 auto another_group = manifest_.mutable_dynamic_partition_metadata()->add_groups();
316 another_group->set_name("another_group");
317 another_group->set_size(4_GiB);
318 another_group->add_partition_names("system");
319 another_group->add_partition_names("vendor");
320 another_group->add_partition_names("product");
321 auto product = manifest_.add_partitions();
322 product->set_partition_name("product");
323 SetSize(product, 1_GiB);
324
325 EXPECT_TRUE(UpdateAndExport());
326
327 EXPECT_EQ(nullptr, builder_->FindGroup(T("group")));
328 EXPECT_TRUE(CheckGroupSize("another_group", 4_GiB));
329 EXPECT_TRUE(CheckSize("system", 2_GiB));
330 EXPECT_TRUE(CheckGroupName("system", "another_group"));
331 EXPECT_TRUE(CheckSize("vendor", 1_GiB));
332 EXPECT_TRUE(CheckGroupName("vendor", "another_group"));
333 EXPECT_TRUE(CheckSize("product", 1_GiB));
334 EXPECT_TRUE(CheckGroupName("product", "another_group"));
335 }
336
337 INSTANTIATE_TEST_SUITE_P(Snapshot, SnapshotMetadataUpdaterTest, testing::Values(0, 1));
338
339 } // namespace snapshot
340 } // namespace android
341