blob: e98d2f4b81dc7b72b694e1d5637f33eea9dc8a33 [file] [log] [blame]
Yifan Hong537802d2018-08-15 13:15:42 -07001//
2// Copyright (C) 2018 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/boot_control_android.h"
18
19#include <set>
Yifan Hongd4db07e2018-10-18 17:46:27 -070020#include <vector>
Yifan Hong537802d2018-08-15 13:15:42 -070021
Yifan Hongd4db07e2018-10-18 17:46:27 -070022#include <base/logging.h>
23#include <base/strings/string_util.h>
David Andersond63cb3c2018-10-01 14:15:00 -070024#include <fs_mgr.h>
Yifan Hong537802d2018-08-15 13:15:42 -070025#include <gmock/gmock.h>
26#include <gtest/gtest.h>
27
28#include "update_engine/mock_boot_control_hal.h"
29#include "update_engine/mock_dynamic_partition_control.h"
30
Yifan Hong537802d2018-08-15 13:15:42 -070031using android::fs_mgr::MetadataBuilder;
32using android::hardware::Void;
33using testing::_;
34using testing::AnyNumber;
35using testing::Contains;
36using testing::Eq;
37using testing::Invoke;
38using testing::Key;
39using testing::MakeMatcher;
40using testing::Matcher;
41using testing::MatcherInterface;
42using testing::MatchResultListener;
43using testing::NiceMock;
Yifan Hongd4db07e2018-10-18 17:46:27 -070044using testing::Not;
Yifan Hong537802d2018-08-15 13:15:42 -070045using testing::Return;
46
47namespace chromeos_update_engine {
48
49constexpr const uint32_t kMaxNumSlots = 2;
50constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
51constexpr const char* kFakeDevicePath = "/fake/dev/path/";
52constexpr const char* kFakeMappedPath = "/fake/mapped/path/";
53constexpr const uint32_t kFakeMetadataSize = 65536;
Yifan Hongd4db07e2018-10-18 17:46:27 -070054constexpr const char* kDefaultGroup = "foo";
55
56// "vendor"
57struct PartitionName : std::string {
58 using std::string::string;
59};
60
61// "vendor_a"
62struct PartitionNameSuffix : std::string {
63 using std::string::string;
64};
Yifan Hong537802d2018-08-15 13:15:42 -070065
66// A map describing the size of each partition.
Yifan Hongd4db07e2018-10-18 17:46:27 -070067using PartitionSizes = std::map<PartitionName, uint64_t>;
68using PartitionSuffixSizes = std::map<PartitionNameSuffix, uint64_t>;
69
70using PartitionMetadata = BootControlInterface::PartitionMetadata;
Yifan Hong537802d2018-08-15 13:15:42 -070071
72// C++ standards do not allow uint64_t (aka unsigned long) to be the parameter
73// of user-defined literal operators.
Yifan Hongd4db07e2018-10-18 17:46:27 -070074constexpr unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT
Yifan Hong537802d2018-08-15 13:15:42 -070075 return x << 20;
76}
Yifan Hongd4db07e2018-10-18 17:46:27 -070077constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
Yifan Hong537802d2018-08-15 13:15:42 -070078 return x << 30;
79}
80
Yifan Hongd4db07e2018-10-18 17:46:27 -070081constexpr uint64_t kDefaultGroupSize = 5_GiB;
82// Super device size. 1 MiB for metadata.
83constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
84
Yifan Hong537802d2018-08-15 13:15:42 -070085template <typename U, typename V>
86std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
87 os << "{";
88 bool first = true;
89 for (const auto& pair : param) {
90 if (!first)
91 os << ", ";
92 os << pair.first << ":" << pair.second;
93 first = false;
94 }
95 return os << "}";
96}
97
Yifan Hongd4db07e2018-10-18 17:46:27 -070098template <typename T>
99std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) {
100 os << "[";
101 bool first = true;
102 for (const auto& e : param) {
103 if (!first)
104 os << ", ";
105 os << e;
106 first = false;
107 }
108 return os << "]";
109}
110
111std::ostream& operator<<(std::ostream& os,
112 const PartitionMetadata::Partition& p) {
113 return os << "{" << p.name << ", " << p.size << "}";
114}
115
116std::ostream& operator<<(std::ostream& os, const PartitionMetadata::Group& g) {
117 return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}";
118}
119
120std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) {
121 return os << m.groups;
122}
123
Yifan Hong537802d2018-08-15 13:15:42 -0700124inline std::string GetDevice(const std::string& name) {
125 return kFakeDevicePath + name;
126}
127inline std::string GetSuperDevice() {
David Andersond63cb3c2018-10-01 14:15:00 -0700128 return GetDevice(fs_mgr_get_super_partition_name());
Yifan Hong537802d2018-08-15 13:15:42 -0700129}
130
131struct TestParam {
132 uint32_t source;
133 uint32_t target;
134};
135std::ostream& operator<<(std::ostream& os, const TestParam& param) {
136 return os << "{source: " << param.source << ", target:" << param.target
137 << "}";
138}
139
Yifan Hongd4db07e2018-10-18 17:46:27 -0700140// To support legacy tests, auto-convert {name_a: size} map to
141// PartitionMetadata.
142PartitionMetadata toMetadata(const PartitionSuffixSizes& partition_sizes) {
143 PartitionMetadata metadata;
144 for (const char* suffix : kSlotSuffixes) {
145 metadata.groups.push_back(
146 {std::string(kDefaultGroup) + suffix, kDefaultGroupSize, {}});
147 }
148 for (const auto& pair : partition_sizes) {
149 for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
150 if (base::EndsWith(pair.first,
151 kSlotSuffixes[suffix_idx],
152 base::CompareCase::SENSITIVE)) {
153 metadata.groups[suffix_idx].partitions.push_back(
154 {pair.first, pair.second});
155 }
156 }
157 }
158 return metadata;
159}
160
161// To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
162PartitionMetadata toMetadata(const PartitionSizes& partition_sizes) {
163 PartitionMetadata metadata;
164 metadata.groups.push_back(
165 {std::string{kDefaultGroup}, kDefaultGroupSize, {}});
166 for (const auto& pair : partition_sizes) {
167 metadata.groups[0].partitions.push_back({pair.first, pair.second});
168 }
169 return metadata;
170}
171
172std::unique_ptr<MetadataBuilder> NewFakeMetadata(
173 const PartitionMetadata& metadata) {
174 auto builder =
175 MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
176 EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2);
Yifan Hong537802d2018-08-15 13:15:42 -0700177 EXPECT_NE(nullptr, builder);
178 if (builder == nullptr)
179 return nullptr;
Yifan Hongd4db07e2018-10-18 17:46:27 -0700180 for (const auto& group : metadata.groups) {
181 EXPECT_TRUE(builder->AddGroup(group.name, group.size));
182 for (const auto& partition : group.partitions) {
183 auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */);
184 EXPECT_TRUE(p && builder->ResizePartition(p, partition.size));
185 }
Yifan Hong537802d2018-08-15 13:15:42 -0700186 }
187 return builder;
188}
189
190class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
191 public:
Yifan Hongd4db07e2018-10-18 17:46:27 -0700192 explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
193 : partition_metadata_(toMetadata(partition_sizes)) {}
194 explicit MetadataMatcher(const PartitionMetadata& partition_metadata)
195 : partition_metadata_(partition_metadata) {}
196
Yifan Hong537802d2018-08-15 13:15:42 -0700197 bool MatchAndExplain(MetadataBuilder* metadata,
198 MatchResultListener* listener) const override {
199 bool success = true;
Yifan Hongd4db07e2018-10-18 17:46:27 -0700200 for (const auto& group : partition_metadata_.groups) {
201 for (const auto& partition : group.partitions) {
202 auto p = metadata->FindPartition(partition.name);
203 if (p == nullptr) {
204 if (!success)
205 *listener << "; ";
206 *listener << "No partition " << partition.name;
207 success = false;
208 continue;
209 }
210 if (p->size() != partition.size) {
211 if (!success)
212 *listener << "; ";
213 *listener << "Partition " << partition.name << " has size "
214 << p->size() << ", expected " << partition.size;
215 success = false;
216 }
217 if (p->group_name() != group.name) {
218 if (!success)
219 *listener << "; ";
220 *listener << "Partition " << partition.name << " has group "
221 << p->group_name() << ", expected " << group.name;
222 success = false;
223 }
Yifan Hong537802d2018-08-15 13:15:42 -0700224 }
225 }
226 return success;
227 }
228
229 void DescribeTo(std::ostream* os) const override {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700230 *os << "expect: " << partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700231 }
232
233 void DescribeNegationTo(std::ostream* os) const override {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700234 *os << "expect not: " << partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700235 }
236
237 private:
Yifan Hongd4db07e2018-10-18 17:46:27 -0700238 PartitionMetadata partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700239};
240
241inline Matcher<MetadataBuilder*> MetadataMatches(
Yifan Hongd4db07e2018-10-18 17:46:27 -0700242 const PartitionSuffixSizes& partition_sizes) {
Yifan Hong537802d2018-08-15 13:15:42 -0700243 return MakeMatcher(new MetadataMatcher(partition_sizes));
244}
245
Yifan Hongd4db07e2018-10-18 17:46:27 -0700246inline Matcher<MetadataBuilder*> MetadataMatches(
247 const PartitionMetadata& partition_metadata) {
248 return MakeMatcher(new MetadataMatcher(partition_metadata));
249}
250
251MATCHER_P(HasGroup, group, " has group " + group) {
252 auto groups = arg->ListGroups();
253 return std::find(groups.begin(), groups.end(), group) != groups.end();
254}
255
Yifan Hong537802d2018-08-15 13:15:42 -0700256class BootControlAndroidTest : public ::testing::Test {
257 protected:
258 void SetUp() override {
259 // Fake init bootctl_
260 bootctl_.module_ = new NiceMock<MockBootControlHal>();
261 bootctl_.dynamic_control_ =
262 std::make_unique<NiceMock<MockDynamicPartitionControl>>();
263
264 ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] {
265 return kMaxNumSlots;
266 }));
267 ON_CALL(module(), getSuffix(_, _))
268 .WillByDefault(Invoke([](auto slot, auto cb) {
269 EXPECT_LE(slot, kMaxNumSlots);
270 cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : "");
271 return Void();
272 }));
273
274 ON_CALL(dynamicControl(), IsDynamicPartitionsEnabled())
275 .WillByDefault(Return(true));
276 ON_CALL(dynamicControl(), GetDeviceDir(_))
277 .WillByDefault(Invoke([](auto path) {
278 *path = kFakeDevicePath;
279 return true;
280 }));
281 }
282
283 // Return the mocked HAL module.
284 NiceMock<MockBootControlHal>& module() {
285 return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
286 }
287
288 // Return the mocked DynamicPartitionControlInterface.
289 NiceMock<MockDynamicPartitionControl>& dynamicControl() {
290 return static_cast<NiceMock<MockDynamicPartitionControl>&>(
291 *bootctl_.dynamic_control_);
292 }
293
294 // Set the fake metadata to return when LoadMetadataBuilder is called on
295 // |slot|.
Yifan Hongd4db07e2018-10-18 17:46:27 -0700296 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
297 SetMetadata(slot, toMetadata(sizes));
298 }
299
300 void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) {
Yifan Hong537802d2018-08-15 13:15:42 -0700301 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), slot))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700302 .Times(AnyNumber())
303 .WillRepeatedly(Invoke(
304 [metadata](auto, auto) { return NewFakeMetadata(metadata); }));
Yifan Hong537802d2018-08-15 13:15:42 -0700305 }
306
307 // Expect that MapPartitionOnDeviceMapper is called on target() metadata slot
308 // with each partition in |partitions|.
Yifan Hongaf65ef12018-10-29 11:09:06 -0700309 void ExpectMap(const std::set<std::string>& partitions,
310 bool force_writable = true) {
Yifan Hong537802d2018-08-15 13:15:42 -0700311 // Error when MapPartitionOnDeviceMapper is called on unknown arguments.
Yifan Hongaf65ef12018-10-29 11:09:06 -0700312 ON_CALL(dynamicControl(), MapPartitionOnDeviceMapper(_, _, _, _, _))
Yifan Hong537802d2018-08-15 13:15:42 -0700313 .WillByDefault(Return(false));
314
315 for (const auto& partition : partitions) {
Yifan Hongaf65ef12018-10-29 11:09:06 -0700316 EXPECT_CALL(dynamicControl(),
317 MapPartitionOnDeviceMapper(
318 GetSuperDevice(), partition, target(), force_writable, _))
319 .WillOnce(Invoke([this](auto, auto partition, auto, auto, auto path) {
Yifan Hong537802d2018-08-15 13:15:42 -0700320 auto it = mapped_devices_.find(partition);
321 if (it != mapped_devices_.end()) {
322 *path = it->second;
323 return true;
324 }
325 mapped_devices_[partition] = *path = kFakeMappedPath + partition;
326 return true;
327 }));
328 }
329 }
330
331 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
332 // slot with each partition in |partitions|.
333 void ExpectUnmap(const std::set<std::string>& partitions) {
334 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
335 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
336 .WillByDefault(Return(false));
337
338 for (const auto& partition : partitions) {
339 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
340 .WillOnce(Invoke([this](auto partition, auto) {
341 mapped_devices_.erase(partition);
342 return true;
343 }));
344 }
345 }
346
347 void ExpectRemap(const std::set<std::string>& partitions) {
348 ExpectUnmap(partitions);
349 ExpectMap(partitions);
350 }
351
352 void ExpectDevicesAreMapped(const std::set<std::string>& partitions) {
353 ASSERT_EQ(partitions.size(), mapped_devices_.size());
354 for (const auto& partition : partitions) {
355 EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
356 << "Expect that " << partition << " is mapped, but it is not.";
357 }
358 }
359
Yifan Hongd4db07e2018-10-18 17:46:27 -0700360 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
Yifan Hong549eb362018-10-19 15:11:12 -0700361 ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
362 }
363
364 virtual void ExpectStoreMetadataMatch(
365 const Matcher<MetadataBuilder*>& matcher) {
366 EXPECT_CALL(dynamicControl(),
367 StoreMetadata(GetSuperDevice(), matcher, target()))
368 .WillOnce(Return(true));
369 }
370
Yifan Hong537802d2018-08-15 13:15:42 -0700371 uint32_t source() { return slots_.source; }
372
373 uint32_t target() { return slots_.target; }
374
375 // Return partition names with suffix of source().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700376 PartitionNameSuffix S(const std::string& name) {
377 return PartitionNameSuffix(name + std::string(kSlotSuffixes[source()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700378 }
379
380 // Return partition names with suffix of target().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700381 PartitionNameSuffix T(const std::string& name) {
382 return PartitionNameSuffix(name + std::string(kSlotSuffixes[target()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700383 }
384
385 // Set source and target slots to use before testing.
386 void SetSlots(const TestParam& slots) {
387 slots_ = slots;
388
389 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
390 return source();
391 }));
392 // Should not store metadata to source slot.
393 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, source()))
394 .Times(0);
Yifan Hongd4db07e2018-10-18 17:46:27 -0700395 // Should not load metadata from target slot.
396 EXPECT_CALL(dynamicControl(),
397 LoadMetadataBuilder(GetSuperDevice(), target()))
398 .Times(0);
399 }
400
401 bool InitPartitionMetadata(uint32_t slot, PartitionSizes partition_sizes) {
402 auto m = toMetadata(partition_sizes);
403 LOG(INFO) << m;
404 return bootctl_.InitPartitionMetadata(slot, m);
Yifan Hong537802d2018-08-15 13:15:42 -0700405 }
406
407 BootControlAndroid bootctl_; // BootControlAndroid under test.
408 TestParam slots_;
409 // mapped devices through MapPartitionOnDeviceMapper.
410 std::map<std::string, std::string> mapped_devices_;
411};
412
413class BootControlAndroidTestP
414 : public BootControlAndroidTest,
415 public ::testing::WithParamInterface<TestParam> {
416 public:
417 void SetUp() override {
418 BootControlAndroidTest::SetUp();
419 SetSlots(GetParam());
420 }
421};
422
Yifan Hong537802d2018-08-15 13:15:42 -0700423// Test resize case. Grow if target metadata contains a partition with a size
424// less than expected.
425TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700426 SetMetadata(source(),
427 {{S("system"), 2_GiB},
428 {S("vendor"), 1_GiB},
429 {T("system"), 2_GiB},
430 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700431 ExpectStoreMetadata({{S("system"), 2_GiB},
432 {S("vendor"), 1_GiB},
433 {T("system"), 3_GiB},
434 {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700435 ExpectRemap({T("system"), T("vendor")});
436
Yifan Hongd4db07e2018-10-18 17:46:27 -0700437 EXPECT_TRUE(
438 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700439 ExpectDevicesAreMapped({T("system"), T("vendor")});
440}
441
442// Test resize case. Shrink if target metadata contains a partition with a size
443// greater than expected.
444TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700445 SetMetadata(source(),
446 {{S("system"), 2_GiB},
447 {S("vendor"), 1_GiB},
448 {T("system"), 2_GiB},
449 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700450 ExpectStoreMetadata({{S("system"), 2_GiB},
451 {S("vendor"), 1_GiB},
452 {T("system"), 2_GiB},
453 {T("vendor"), 150_MiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700454 ExpectRemap({T("system"), T("vendor")});
455
Yifan Hongd4db07e2018-10-18 17:46:27 -0700456 EXPECT_TRUE(InitPartitionMetadata(target(),
457 {{"system", 2_GiB}, {"vendor", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700458 ExpectDevicesAreMapped({T("system"), T("vendor")});
459}
460
461// Test adding partitions on the first run.
462TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700463 SetMetadata(source(), PartitionSuffixSizes{});
Yifan Hong549eb362018-10-19 15:11:12 -0700464 ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700465 ExpectRemap({T("system"), T("vendor")});
466
Yifan Hongd4db07e2018-10-18 17:46:27 -0700467 EXPECT_TRUE(
468 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700469 ExpectDevicesAreMapped({T("system"), T("vendor")});
470}
471
472// Test subsequent add case.
473TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
474 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700475 ExpectStoreMetadata(
476 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700477 ExpectRemap({T("system"), T("vendor")});
478
Yifan Hongd4db07e2018-10-18 17:46:27 -0700479 EXPECT_TRUE(
480 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700481 ExpectDevicesAreMapped({T("system"), T("vendor")});
482}
483
484// Test delete one partition.
485TEST_P(BootControlAndroidTestP, DeletePartition) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700486 SetMetadata(source(),
487 {{S("system"), 2_GiB},
488 {S("vendor"), 1_GiB},
489 {T("system"), 2_GiB},
490 {T("vendor"), 1_GiB}});
491 // No T("vendor")
492 ExpectStoreMetadata(
493 {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
494 ExpectRemap({T("system")});
Yifan Hong537802d2018-08-15 13:15:42 -0700495
Yifan Hongd4db07e2018-10-18 17:46:27 -0700496 EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700497 ExpectDevicesAreMapped({T("system")});
498}
499
500// Test delete all partitions.
501TEST_P(BootControlAndroidTestP, DeleteAll) {
Yifan Hong537802d2018-08-15 13:15:42 -0700502 SetMetadata(source(),
503 {{S("system"), 2_GiB},
504 {S("vendor"), 1_GiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700505 {T("system"), 2_GiB},
506 {T("vendor"), 1_GiB}});
507 ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
508
509 EXPECT_TRUE(InitPartitionMetadata(target(), {}));
510 ExpectDevicesAreMapped({});
511}
512
513// Test corrupt source metadata case.
514TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
515 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), source()))
Yifan Hong537802d2018-08-15 13:15:42 -0700516 .WillOnce(Invoke([](auto, auto) { return nullptr; }));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700517 EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
518 << "Should not be able to continue with corrupt source metadata";
Yifan Hong537802d2018-08-15 13:15:42 -0700519}
520
521// Test that InitPartitionMetadata fail if there is not enough space on the
522// device.
523TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700524 SetMetadata(source(),
525 {{S("system"), 3_GiB},
526 {S("vendor"), 2_GiB},
527 {T("system"), 0},
528 {T("vendor"), 0}});
529 EXPECT_FALSE(
530 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
Yifan Hong537802d2018-08-15 13:15:42 -0700531 << "Should not be able to fit 11GiB data into 10GiB space";
532}
533
Yifan Hongd4db07e2018-10-18 17:46:27 -0700534TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
535 SetMetadata(source(),
536 {{S("system"), 1_GiB},
537 {S("vendor"), 1_GiB},
538 {T("system"), 0},
539 {T("vendor"), 0}});
540 EXPECT_FALSE(
541 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
542 << "Should not be able to grow over size of super / 2";
543}
544
545INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
Yifan Hong537802d2018-08-15 13:15:42 -0700546 BootControlAndroidTestP,
547 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
548
Yifan Hongd4db07e2018-10-18 17:46:27 -0700549const PartitionSuffixSizes update_sizes_0() {
550 // Initial state is 0 for "other" slot.
Yifan Hong537802d2018-08-15 13:15:42 -0700551 return {
552 {"grown_a", 2_GiB},
553 {"shrunk_a", 1_GiB},
554 {"same_a", 100_MiB},
555 {"deleted_a", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700556 // no added_a
557 {"grown_b", 200_MiB},
558 // simulate system_other
559 {"shrunk_b", 0},
560 {"same_b", 0},
561 {"deleted_b", 0},
562 // no added_b
563 };
564}
565
566const PartitionSuffixSizes update_sizes_1() {
567 return {
568 {"grown_a", 2_GiB},
569 {"shrunk_a", 1_GiB},
570 {"same_a", 100_MiB},
571 {"deleted_a", 150_MiB},
572 // no added_a
Yifan Hong537802d2018-08-15 13:15:42 -0700573 {"grown_b", 3_GiB},
574 {"shrunk_b", 150_MiB},
575 {"same_b", 100_MiB},
576 {"added_b", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700577 // no deleted_b
Yifan Hong537802d2018-08-15 13:15:42 -0700578 };
579}
580
Yifan Hongd4db07e2018-10-18 17:46:27 -0700581const PartitionSuffixSizes update_sizes_2() {
582 return {
583 {"grown_a", 4_GiB},
584 {"shrunk_a", 100_MiB},
585 {"same_a", 100_MiB},
586 {"deleted_a", 64_MiB},
587 // no added_a
588 {"grown_b", 3_GiB},
589 {"shrunk_b", 150_MiB},
590 {"same_b", 100_MiB},
591 {"added_b", 150_MiB},
592 // no deleted_b
593 };
Yifan Hong537802d2018-08-15 13:15:42 -0700594}
595
596// Test case for first update after the device is manufactured, in which
597// case the "other" slot is likely of size "0" (except system, which is
598// non-zero because of system_other partition)
599TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
600 SetSlots({0, 1});
601
602 SetMetadata(source(), update_sizes_0());
603 SetMetadata(target(), update_sizes_0());
Yifan Hong549eb362018-10-19 15:11:12 -0700604 ExpectStoreMetadata(update_sizes_1());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700605 ExpectRemap({"grown_b", "shrunk_b", "same_b", "added_b"});
Yifan Hong537802d2018-08-15 13:15:42 -0700606
Yifan Hongd4db07e2018-10-18 17:46:27 -0700607 EXPECT_TRUE(InitPartitionMetadata(target(),
608 {{"grown", 3_GiB},
609 {"shrunk", 150_MiB},
610 {"same", 100_MiB},
611 {"added", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700612 ExpectDevicesAreMapped({"grown_b", "shrunk_b", "same_b", "added_b"});
613}
614
615// After first update, test for the second update. In the second update, the
616// "added" partition is deleted and "deleted" partition is re-added.
617TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
618 SetSlots({1, 0});
619
620 SetMetadata(source(), update_sizes_1());
621 SetMetadata(target(), update_sizes_0());
622
Yifan Hong549eb362018-10-19 15:11:12 -0700623 ExpectStoreMetadata(update_sizes_2());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700624 ExpectRemap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
Yifan Hong537802d2018-08-15 13:15:42 -0700625
Yifan Hongd4db07e2018-10-18 17:46:27 -0700626 EXPECT_TRUE(InitPartitionMetadata(target(),
627 {{"grown", 4_GiB},
628 {"shrunk", 100_MiB},
629 {"same", 100_MiB},
630 {"deleted", 64_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700631 ExpectDevicesAreMapped({"grown_a", "shrunk_a", "same_a", "deleted_a"});
632}
633
634TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
635 SetSlots({1, 1});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700636 EXPECT_FALSE(InitPartitionMetadata(target(), {}))
Yifan Hong537802d2018-08-15 13:15:42 -0700637 << "Should not be able to apply to current slot.";
638}
639
Yifan Hongd4db07e2018-10-18 17:46:27 -0700640class BootControlAndroidGroupTestP : public BootControlAndroidTestP {
641 public:
642 void SetUp() override {
643 BootControlAndroidTestP::SetUp();
644 SetMetadata(
645 source(),
646 {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
647 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB),
648 SimpleGroup(T("android"), 3_GiB, T("system"), 0),
649 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}});
650 }
651
652 // Return a simple group with only one partition.
653 PartitionMetadata::Group SimpleGroup(const std::string& group,
654 uint64_t group_size,
655 const std::string& partition,
656 uint64_t partition_size) {
657 return {.name = group,
658 .size = group_size,
659 .partitions = {{.name = partition, .size = partition_size}}};
660 }
661
662 void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) {
663 ExpectStoreMetadataMatch(MetadataMatches(partition_metadata));
664 }
665
666 // Expect that target slot is stored with target groups.
667 void ExpectStoreMetadataMatch(
668 const Matcher<MetadataBuilder*>& matcher) override {
669 BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf(
670 MetadataMatches(PartitionMetadata{
671 .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
672 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}),
673 matcher));
674 }
675};
676
677// Allow to resize within group.
678TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
679 ExpectStoreMetadata(PartitionMetadata{
680 .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
681 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
682 ExpectRemap({T("system"), T("vendor")});
683
684 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
685 target(),
686 PartitionMetadata{
687 .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
688 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
689 ExpectDevicesAreMapped({T("system"), T("vendor")});
690}
691
692TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
693 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
694 target(),
695 PartitionMetadata{
696 .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
697 SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}))
698 << "Should not be able to grow over maximum size of group";
699}
700
701TEST_P(BootControlAndroidGroupTestP, GroupTooBig) {
702 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
703 target(),
704 PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
705 {.name = "oem", .size = 3_GiB}}}))
706 << "Should not be able to grow over size of super / 2";
707}
708
709TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
710 ExpectStoreMetadata(PartitionMetadata{
711 .groups = {
712 {.name = T("android"),
713 .size = 3_GiB,
714 .partitions = {{.name = T("system"), .size = 2_GiB},
715 {.name = T("product_services"), .size = 1_GiB}}}}});
716 ExpectRemap({T("system"), T("vendor"), T("product_services")});
717
718 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
719 target(),
720 PartitionMetadata{
721 .groups = {
722 {.name = "android",
723 .size = 3_GiB,
724 .partitions = {{.name = "system", .size = 2_GiB},
725 {.name = "product_services", .size = 1_GiB}}},
726 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
727 ExpectDevicesAreMapped({T("system"), T("vendor"), T("product_services")});
728}
729
730TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
731 ExpectStoreMetadata(PartitionMetadata{
732 .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
733 ExpectRemap({T("vendor")});
734
735 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
736 target(),
737 PartitionMetadata{
738 .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
739 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
740 ExpectDevicesAreMapped({T("vendor")});
741}
742
743TEST_P(BootControlAndroidGroupTestP, AddGroup) {
744 ExpectStoreMetadata(PartitionMetadata{
745 .groups = {
746 SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
747 ExpectRemap({T("system"), T("vendor"), T("new_partition")});
748
749 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
750 target(),
751 PartitionMetadata{
752 .groups = {
753 SimpleGroup("android", 2_GiB, "system", 2_GiB),
754 SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
755 SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}));
756 ExpectDevicesAreMapped({T("system"), T("vendor"), T("new_partition")});
757}
758
759TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
760 ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
761 ExpectRemap({T("system")});
762 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
763 target(),
764 PartitionMetadata{
765 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}));
766 ExpectDevicesAreMapped({T("system")});
767}
768
769TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
770 ExpectStoreMetadata(PartitionMetadata{
771 .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
772 SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
773 ExpectRemap({T("system"), T("vendor")});
774
775 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
776 target(),
777 PartitionMetadata{
778 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
779 SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}));
780 ExpectDevicesAreMapped({T("system"), T("vendor")});
781}
782
783INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
784 BootControlAndroidGroupTestP,
785 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
786
Yifan Hong537802d2018-08-15 13:15:42 -0700787} // namespace chromeos_update_engine