blob: 23757140ec340bf431ee90a2c26918ebc73c1eb4 [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));
Yifan Hong6e38b352018-11-19 14:12:37 -0800276 ON_CALL(dynamicControl(), IsDynamicPartitionsRetrofit())
277 .WillByDefault(Return(false));
Yifan Hong537802d2018-08-15 13:15:42 -0700278 ON_CALL(dynamicControl(), GetDeviceDir(_))
279 .WillByDefault(Invoke([](auto path) {
280 *path = kFakeDevicePath;
281 return true;
282 }));
283 }
284
285 // Return the mocked HAL module.
286 NiceMock<MockBootControlHal>& module() {
287 return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
288 }
289
290 // Return the mocked DynamicPartitionControlInterface.
291 NiceMock<MockDynamicPartitionControl>& dynamicControl() {
292 return static_cast<NiceMock<MockDynamicPartitionControl>&>(
293 *bootctl_.dynamic_control_);
294 }
295
296 // Set the fake metadata to return when LoadMetadataBuilder is called on
297 // |slot|.
Yifan Hongd4db07e2018-10-18 17:46:27 -0700298 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
299 SetMetadata(slot, toMetadata(sizes));
300 }
301
302 void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) {
Yifan Hong6e706b12018-11-09 16:50:51 -0800303 EXPECT_CALL(dynamicControl(),
304 LoadMetadataBuilder(GetSuperDevice(), slot, _))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700305 .Times(AnyNumber())
Yifan Hong6e706b12018-11-09 16:50:51 -0800306 .WillRepeatedly(Invoke([metadata](auto, auto, auto) {
307 return NewFakeMetadata(metadata);
308 }));
Yifan Hong537802d2018-08-15 13:15:42 -0700309 }
310
311 // Expect that MapPartitionOnDeviceMapper is called on target() metadata slot
312 // with each partition in |partitions|.
Yifan Hongaf65ef12018-10-29 11:09:06 -0700313 void ExpectMap(const std::set<std::string>& partitions,
314 bool force_writable = true) {
Yifan Hong537802d2018-08-15 13:15:42 -0700315 // Error when MapPartitionOnDeviceMapper is called on unknown arguments.
Yifan Hongaf65ef12018-10-29 11:09:06 -0700316 ON_CALL(dynamicControl(), MapPartitionOnDeviceMapper(_, _, _, _, _))
Yifan Hong537802d2018-08-15 13:15:42 -0700317 .WillByDefault(Return(false));
318
319 for (const auto& partition : partitions) {
Yifan Hongaf65ef12018-10-29 11:09:06 -0700320 EXPECT_CALL(dynamicControl(),
321 MapPartitionOnDeviceMapper(
322 GetSuperDevice(), partition, target(), force_writable, _))
323 .WillOnce(Invoke([this](auto, auto partition, auto, auto, auto path) {
Yifan Hong537802d2018-08-15 13:15:42 -0700324 auto it = mapped_devices_.find(partition);
325 if (it != mapped_devices_.end()) {
326 *path = it->second;
327 return true;
328 }
329 mapped_devices_[partition] = *path = kFakeMappedPath + partition;
330 return true;
331 }));
332 }
333 }
334
335 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
336 // slot with each partition in |partitions|.
337 void ExpectUnmap(const std::set<std::string>& partitions) {
338 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
339 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
340 .WillByDefault(Return(false));
341
342 for (const auto& partition : partitions) {
343 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
344 .WillOnce(Invoke([this](auto partition, auto) {
345 mapped_devices_.erase(partition);
346 return true;
347 }));
348 }
349 }
350
351 void ExpectRemap(const std::set<std::string>& partitions) {
352 ExpectUnmap(partitions);
353 ExpectMap(partitions);
354 }
355
356 void ExpectDevicesAreMapped(const std::set<std::string>& partitions) {
357 ASSERT_EQ(partitions.size(), mapped_devices_.size());
358 for (const auto& partition : partitions) {
359 EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
360 << "Expect that " << partition << " is mapped, but it is not.";
361 }
362 }
363
Yifan Hongd4db07e2018-10-18 17:46:27 -0700364 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
Yifan Hong549eb362018-10-19 15:11:12 -0700365 ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
366 }
367
368 virtual void ExpectStoreMetadataMatch(
369 const Matcher<MetadataBuilder*>& matcher) {
370 EXPECT_CALL(dynamicControl(),
371 StoreMetadata(GetSuperDevice(), matcher, target()))
372 .WillOnce(Return(true));
373 }
374
Yifan Hong537802d2018-08-15 13:15:42 -0700375 uint32_t source() { return slots_.source; }
376
377 uint32_t target() { return slots_.target; }
378
379 // Return partition names with suffix of source().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700380 PartitionNameSuffix S(const std::string& name) {
381 return PartitionNameSuffix(name + std::string(kSlotSuffixes[source()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700382 }
383
384 // Return partition names with suffix of target().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700385 PartitionNameSuffix T(const std::string& name) {
386 return PartitionNameSuffix(name + std::string(kSlotSuffixes[target()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700387 }
388
389 // Set source and target slots to use before testing.
390 void SetSlots(const TestParam& slots) {
391 slots_ = slots;
392
393 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
394 return source();
395 }));
396 // Should not store metadata to source slot.
397 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, source()))
398 .Times(0);
Yifan Hongd4db07e2018-10-18 17:46:27 -0700399 // Should not load metadata from target slot.
400 EXPECT_CALL(dynamicControl(),
Yifan Hong6e706b12018-11-09 16:50:51 -0800401 LoadMetadataBuilder(GetSuperDevice(), target(), _))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700402 .Times(0);
403 }
404
405 bool InitPartitionMetadata(uint32_t slot, PartitionSizes partition_sizes) {
406 auto m = toMetadata(partition_sizes);
407 LOG(INFO) << m;
408 return bootctl_.InitPartitionMetadata(slot, m);
Yifan Hong537802d2018-08-15 13:15:42 -0700409 }
410
411 BootControlAndroid bootctl_; // BootControlAndroid under test.
412 TestParam slots_;
413 // mapped devices through MapPartitionOnDeviceMapper.
414 std::map<std::string, std::string> mapped_devices_;
415};
416
417class BootControlAndroidTestP
418 : public BootControlAndroidTest,
419 public ::testing::WithParamInterface<TestParam> {
420 public:
421 void SetUp() override {
422 BootControlAndroidTest::SetUp();
423 SetSlots(GetParam());
424 }
425};
426
Yifan Hong537802d2018-08-15 13:15:42 -0700427// Test resize case. Grow if target metadata contains a partition with a size
428// less than expected.
429TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700430 SetMetadata(source(),
431 {{S("system"), 2_GiB},
432 {S("vendor"), 1_GiB},
433 {T("system"), 2_GiB},
434 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700435 ExpectStoreMetadata({{S("system"), 2_GiB},
436 {S("vendor"), 1_GiB},
437 {T("system"), 3_GiB},
438 {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700439 ExpectRemap({T("system"), T("vendor")});
440
Yifan Hongd4db07e2018-10-18 17:46:27 -0700441 EXPECT_TRUE(
442 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700443 ExpectDevicesAreMapped({T("system"), T("vendor")});
444}
445
446// Test resize case. Shrink if target metadata contains a partition with a size
447// greater than expected.
448TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700449 SetMetadata(source(),
450 {{S("system"), 2_GiB},
451 {S("vendor"), 1_GiB},
452 {T("system"), 2_GiB},
453 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700454 ExpectStoreMetadata({{S("system"), 2_GiB},
455 {S("vendor"), 1_GiB},
456 {T("system"), 2_GiB},
457 {T("vendor"), 150_MiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700458 ExpectRemap({T("system"), T("vendor")});
459
Yifan Hongd4db07e2018-10-18 17:46:27 -0700460 EXPECT_TRUE(InitPartitionMetadata(target(),
461 {{"system", 2_GiB}, {"vendor", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700462 ExpectDevicesAreMapped({T("system"), T("vendor")});
463}
464
465// Test adding partitions on the first run.
466TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700467 SetMetadata(source(), PartitionSuffixSizes{});
Yifan Hong549eb362018-10-19 15:11:12 -0700468 ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700469 ExpectRemap({T("system"), T("vendor")});
470
Yifan Hongd4db07e2018-10-18 17:46:27 -0700471 EXPECT_TRUE(
472 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700473 ExpectDevicesAreMapped({T("system"), T("vendor")});
474}
475
476// Test subsequent add case.
477TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
478 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700479 ExpectStoreMetadata(
480 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700481 ExpectRemap({T("system"), T("vendor")});
482
Yifan Hongd4db07e2018-10-18 17:46:27 -0700483 EXPECT_TRUE(
484 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700485 ExpectDevicesAreMapped({T("system"), T("vendor")});
486}
487
488// Test delete one partition.
489TEST_P(BootControlAndroidTestP, DeletePartition) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700490 SetMetadata(source(),
491 {{S("system"), 2_GiB},
492 {S("vendor"), 1_GiB},
493 {T("system"), 2_GiB},
494 {T("vendor"), 1_GiB}});
495 // No T("vendor")
496 ExpectStoreMetadata(
497 {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
498 ExpectRemap({T("system")});
Yifan Hong537802d2018-08-15 13:15:42 -0700499
Yifan Hongd4db07e2018-10-18 17:46:27 -0700500 EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700501 ExpectDevicesAreMapped({T("system")});
502}
503
504// Test delete all partitions.
505TEST_P(BootControlAndroidTestP, DeleteAll) {
Yifan Hong537802d2018-08-15 13:15:42 -0700506 SetMetadata(source(),
507 {{S("system"), 2_GiB},
508 {S("vendor"), 1_GiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700509 {T("system"), 2_GiB},
510 {T("vendor"), 1_GiB}});
511 ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
512
513 EXPECT_TRUE(InitPartitionMetadata(target(), {}));
514 ExpectDevicesAreMapped({});
515}
516
517// Test corrupt source metadata case.
518TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
Yifan Hong6e706b12018-11-09 16:50:51 -0800519 EXPECT_CALL(dynamicControl(),
520 LoadMetadataBuilder(GetSuperDevice(), source(), _))
521 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700522 EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
523 << "Should not be able to continue with corrupt source metadata";
Yifan Hong537802d2018-08-15 13:15:42 -0700524}
525
526// Test that InitPartitionMetadata fail if there is not enough space on the
527// device.
528TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700529 SetMetadata(source(),
530 {{S("system"), 3_GiB},
531 {S("vendor"), 2_GiB},
532 {T("system"), 0},
533 {T("vendor"), 0}});
534 EXPECT_FALSE(
535 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
Yifan Hong537802d2018-08-15 13:15:42 -0700536 << "Should not be able to fit 11GiB data into 10GiB space";
537}
538
Yifan Hongd4db07e2018-10-18 17:46:27 -0700539TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
540 SetMetadata(source(),
541 {{S("system"), 1_GiB},
542 {S("vendor"), 1_GiB},
543 {T("system"), 0},
544 {T("vendor"), 0}});
545 EXPECT_FALSE(
546 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
547 << "Should not be able to grow over size of super / 2";
548}
549
550INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
Yifan Hong537802d2018-08-15 13:15:42 -0700551 BootControlAndroidTestP,
552 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
553
Yifan Hongd4db07e2018-10-18 17:46:27 -0700554const PartitionSuffixSizes update_sizes_0() {
555 // Initial state is 0 for "other" slot.
Yifan Hong537802d2018-08-15 13:15:42 -0700556 return {
557 {"grown_a", 2_GiB},
558 {"shrunk_a", 1_GiB},
559 {"same_a", 100_MiB},
560 {"deleted_a", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700561 // no added_a
562 {"grown_b", 200_MiB},
563 // simulate system_other
564 {"shrunk_b", 0},
565 {"same_b", 0},
566 {"deleted_b", 0},
567 // no added_b
568 };
569}
570
571const PartitionSuffixSizes update_sizes_1() {
572 return {
573 {"grown_a", 2_GiB},
574 {"shrunk_a", 1_GiB},
575 {"same_a", 100_MiB},
576 {"deleted_a", 150_MiB},
577 // no added_a
Yifan Hong537802d2018-08-15 13:15:42 -0700578 {"grown_b", 3_GiB},
579 {"shrunk_b", 150_MiB},
580 {"same_b", 100_MiB},
581 {"added_b", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700582 // no deleted_b
Yifan Hong537802d2018-08-15 13:15:42 -0700583 };
584}
585
Yifan Hongd4db07e2018-10-18 17:46:27 -0700586const PartitionSuffixSizes update_sizes_2() {
587 return {
588 {"grown_a", 4_GiB},
589 {"shrunk_a", 100_MiB},
590 {"same_a", 100_MiB},
591 {"deleted_a", 64_MiB},
592 // no added_a
593 {"grown_b", 3_GiB},
594 {"shrunk_b", 150_MiB},
595 {"same_b", 100_MiB},
596 {"added_b", 150_MiB},
597 // no deleted_b
598 };
Yifan Hong537802d2018-08-15 13:15:42 -0700599}
600
601// Test case for first update after the device is manufactured, in which
602// case the "other" slot is likely of size "0" (except system, which is
603// non-zero because of system_other partition)
604TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
605 SetSlots({0, 1});
606
607 SetMetadata(source(), update_sizes_0());
608 SetMetadata(target(), update_sizes_0());
Yifan Hong549eb362018-10-19 15:11:12 -0700609 ExpectStoreMetadata(update_sizes_1());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700610 ExpectRemap({"grown_b", "shrunk_b", "same_b", "added_b"});
Yifan Hong537802d2018-08-15 13:15:42 -0700611
Yifan Hongd4db07e2018-10-18 17:46:27 -0700612 EXPECT_TRUE(InitPartitionMetadata(target(),
613 {{"grown", 3_GiB},
614 {"shrunk", 150_MiB},
615 {"same", 100_MiB},
616 {"added", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700617 ExpectDevicesAreMapped({"grown_b", "shrunk_b", "same_b", "added_b"});
618}
619
620// After first update, test for the second update. In the second update, the
621// "added" partition is deleted and "deleted" partition is re-added.
622TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
623 SetSlots({1, 0});
624
625 SetMetadata(source(), update_sizes_1());
626 SetMetadata(target(), update_sizes_0());
627
Yifan Hong549eb362018-10-19 15:11:12 -0700628 ExpectStoreMetadata(update_sizes_2());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700629 ExpectRemap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
Yifan Hong537802d2018-08-15 13:15:42 -0700630
Yifan Hongd4db07e2018-10-18 17:46:27 -0700631 EXPECT_TRUE(InitPartitionMetadata(target(),
632 {{"grown", 4_GiB},
633 {"shrunk", 100_MiB},
634 {"same", 100_MiB},
635 {"deleted", 64_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700636 ExpectDevicesAreMapped({"grown_a", "shrunk_a", "same_a", "deleted_a"});
637}
638
639TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
640 SetSlots({1, 1});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700641 EXPECT_FALSE(InitPartitionMetadata(target(), {}))
Yifan Hong537802d2018-08-15 13:15:42 -0700642 << "Should not be able to apply to current slot.";
643}
644
Yifan Hongd4db07e2018-10-18 17:46:27 -0700645class BootControlAndroidGroupTestP : public BootControlAndroidTestP {
646 public:
647 void SetUp() override {
648 BootControlAndroidTestP::SetUp();
649 SetMetadata(
650 source(),
651 {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
652 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB),
653 SimpleGroup(T("android"), 3_GiB, T("system"), 0),
654 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}});
655 }
656
657 // Return a simple group with only one partition.
658 PartitionMetadata::Group SimpleGroup(const std::string& group,
659 uint64_t group_size,
660 const std::string& partition,
661 uint64_t partition_size) {
662 return {.name = group,
663 .size = group_size,
664 .partitions = {{.name = partition, .size = partition_size}}};
665 }
666
667 void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) {
668 ExpectStoreMetadataMatch(MetadataMatches(partition_metadata));
669 }
670
671 // Expect that target slot is stored with target groups.
672 void ExpectStoreMetadataMatch(
673 const Matcher<MetadataBuilder*>& matcher) override {
674 BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf(
675 MetadataMatches(PartitionMetadata{
676 .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
677 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}),
678 matcher));
679 }
680};
681
682// Allow to resize within group.
683TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
684 ExpectStoreMetadata(PartitionMetadata{
685 .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
686 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
687 ExpectRemap({T("system"), T("vendor")});
688
689 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
690 target(),
691 PartitionMetadata{
692 .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
693 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
694 ExpectDevicesAreMapped({T("system"), T("vendor")});
695}
696
697TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
698 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
699 target(),
700 PartitionMetadata{
701 .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
702 SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}))
703 << "Should not be able to grow over maximum size of group";
704}
705
706TEST_P(BootControlAndroidGroupTestP, GroupTooBig) {
707 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
708 target(),
709 PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
710 {.name = "oem", .size = 3_GiB}}}))
711 << "Should not be able to grow over size of super / 2";
712}
713
714TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
715 ExpectStoreMetadata(PartitionMetadata{
716 .groups = {
717 {.name = T("android"),
718 .size = 3_GiB,
719 .partitions = {{.name = T("system"), .size = 2_GiB},
720 {.name = T("product_services"), .size = 1_GiB}}}}});
721 ExpectRemap({T("system"), T("vendor"), T("product_services")});
722
723 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
724 target(),
725 PartitionMetadata{
726 .groups = {
727 {.name = "android",
728 .size = 3_GiB,
729 .partitions = {{.name = "system", .size = 2_GiB},
730 {.name = "product_services", .size = 1_GiB}}},
731 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
732 ExpectDevicesAreMapped({T("system"), T("vendor"), T("product_services")});
733}
734
735TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
736 ExpectStoreMetadata(PartitionMetadata{
737 .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
738 ExpectRemap({T("vendor")});
739
740 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
741 target(),
742 PartitionMetadata{
743 .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
744 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
745 ExpectDevicesAreMapped({T("vendor")});
746}
747
748TEST_P(BootControlAndroidGroupTestP, AddGroup) {
749 ExpectStoreMetadata(PartitionMetadata{
750 .groups = {
751 SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
752 ExpectRemap({T("system"), T("vendor"), T("new_partition")});
753
754 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
755 target(),
756 PartitionMetadata{
757 .groups = {
758 SimpleGroup("android", 2_GiB, "system", 2_GiB),
759 SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
760 SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}));
761 ExpectDevicesAreMapped({T("system"), T("vendor"), T("new_partition")});
762}
763
764TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
765 ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
766 ExpectRemap({T("system")});
767 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
768 target(),
769 PartitionMetadata{
770 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}));
771 ExpectDevicesAreMapped({T("system")});
772}
773
774TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
775 ExpectStoreMetadata(PartitionMetadata{
776 .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
777 SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
778 ExpectRemap({T("system"), T("vendor")});
779
780 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
781 target(),
782 PartitionMetadata{
783 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
784 SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}));
785 ExpectDevicesAreMapped({T("system"), T("vendor")});
786}
787
788INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
789 BootControlAndroidGroupTestP,
790 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
791
Yifan Hong537802d2018-08-15 13:15:42 -0700792} // namespace chromeos_update_engine