diff options
author | Amin Hassani <ahassani@chromium.org> | 2020-09-16 11:19:28 -0700 |
---|---|---|
committer | Amin Hassani <ahassani@chromium.org> | 2020-09-17 10:17:36 -0700 |
commit | e53b39b8b9c5c0871841bbbb86f23657c0b7f91b (patch) | |
tree | 12746e5e7e4716ba7fc94d3ed5c1a36c4d47d474 /boot_control_android_unittest.cc | |
parent | a02a1f1dc837f22226499d9856a949fb180d099a (diff) | |
parent | 9956320ffa4edb340d20bd7f3c852a9e87437bd3 (diff) |
update_engine: Merge remote-tracking branch 'cros/upstream' into cros/master
Done with:
git merge cros/upstream --commit -s recursive
- Added EC key support and its unittests.
- Resolved a conlict on error codes. Since Android versions are not
uploading any UMA metrics, I gave the priority to the Android version
Since they can't be changed.
- Changed the openssl functions to get1 version (from get0) version
because of a current issue with gale. Once the issue is resolved we
need to change them back.
- Some remaining styling issues fixed by clang-format
BUG=b:163153182
TEST=CQ passes
TEST=unittests
Change-Id: Ib95034422b92433ce26e28336bc4806b34910d38
Diffstat (limited to 'boot_control_android_unittest.cc')
-rw-r--r-- | boot_control_android_unittest.cc | 853 |
1 files changed, 0 insertions, 853 deletions
diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc deleted file mode 100644 index bb9903e2..00000000 --- a/boot_control_android_unittest.cc +++ /dev/null @@ -1,853 +0,0 @@ -// -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "update_engine/boot_control_android.h" - -#include <set> -#include <vector> - -#include <base/logging.h> -#include <base/strings/string_util.h> -#include <fs_mgr.h> -#include <gmock/gmock.h> -#include <gtest/gtest.h> -#include <libdm/dm.h> - -#include "update_engine/mock_boot_control_hal.h" -#include "update_engine/mock_dynamic_partition_control.h" - -using android::dm::DmDeviceState; -using android::fs_mgr::MetadataBuilder; -using android::hardware::Void; -using std::string; -using testing::_; -using testing::AnyNumber; -using testing::Contains; -using testing::Eq; -using testing::Invoke; -using testing::Key; -using testing::MakeMatcher; -using testing::Matcher; -using testing::MatcherInterface; -using testing::MatchResultListener; -using testing::NiceMock; -using testing::Not; -using testing::Return; - -namespace chromeos_update_engine { - -constexpr const uint32_t kMaxNumSlots = 2; -constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"}; -constexpr const char* kFakeDevicePath = "/fake/dev/path/"; -constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/"; -constexpr const uint32_t kFakeMetadataSize = 65536; -constexpr const char* kDefaultGroup = "foo"; - -// A map describing the size of each partition. -// "{name, size}" -using PartitionSizes = std::map<string, uint64_t>; - -// "{name_a, size}" -using PartitionSuffixSizes = std::map<string, uint64_t>; - -using PartitionMetadata = BootControlInterface::PartitionMetadata; - -// C++ standards do not allow uint64_t (aka unsigned long) to be the parameter -// of user-defined literal operators. -constexpr unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT - return x << 20; -} -constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT - return x << 30; -} - -constexpr uint64_t kDefaultGroupSize = 5_GiB; -// Super device size. 1 MiB for metadata. -constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB; - -template <typename U, typename V> -std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) { - os << "{"; - bool first = true; - for (const auto& pair : param) { - if (!first) - os << ", "; - os << pair.first << ":" << pair.second; - first = false; - } - return os << "}"; -} - -template <typename T> -std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) { - os << "["; - bool first = true; - for (const auto& e : param) { - if (!first) - os << ", "; - os << e; - first = false; - } - return os << "]"; -} - -std::ostream& operator<<(std::ostream& os, - const PartitionMetadata::Partition& p) { - return os << "{" << p.name << ", " << p.size << "}"; -} - -std::ostream& operator<<(std::ostream& os, const PartitionMetadata::Group& g) { - return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}"; -} - -std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) { - return os << m.groups; -} - -inline string GetDevice(const string& name) { - return kFakeDevicePath + name; -} - -inline string GetDmDevice(const string& name) { - return kFakeDmDevicePath + name; -} - -// TODO(elsk): fs_mgr_get_super_partition_name should be mocked. -inline string GetSuperDevice(uint32_t slot) { - return GetDevice(fs_mgr_get_super_partition_name(slot)); -} - -struct TestParam { - uint32_t source; - uint32_t target; -}; -std::ostream& operator<<(std::ostream& os, const TestParam& param) { - return os << "{source: " << param.source << ", target:" << param.target - << "}"; -} - -// To support legacy tests, auto-convert {name_a: size} map to -// PartitionMetadata. -PartitionMetadata partitionSuffixSizesToMetadata( - const PartitionSuffixSizes& partition_sizes) { - PartitionMetadata metadata; - for (const char* suffix : kSlotSuffixes) { - metadata.groups.push_back( - {string(kDefaultGroup) + suffix, kDefaultGroupSize, {}}); - } - for (const auto& pair : partition_sizes) { - for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) { - if (base::EndsWith(pair.first, - kSlotSuffixes[suffix_idx], - base::CompareCase::SENSITIVE)) { - metadata.groups[suffix_idx].partitions.push_back( - {pair.first, pair.second}); - } - } - } - return metadata; -} - -// To support legacy tests, auto-convert {name: size} map to PartitionMetadata. -PartitionMetadata partitionSizesToMetadata( - const PartitionSizes& partition_sizes) { - PartitionMetadata metadata; - metadata.groups.push_back({string{kDefaultGroup}, kDefaultGroupSize, {}}); - for (const auto& pair : partition_sizes) { - metadata.groups[0].partitions.push_back({pair.first, pair.second}); - } - return metadata; -} - -std::unique_ptr<MetadataBuilder> NewFakeMetadata( - const PartitionMetadata& metadata) { - auto builder = - MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots); - EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2); - EXPECT_NE(nullptr, builder); - if (builder == nullptr) - return nullptr; - for (const auto& group : metadata.groups) { - EXPECT_TRUE(builder->AddGroup(group.name, group.size)); - for (const auto& partition : group.partitions) { - auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */); - EXPECT_TRUE(p && builder->ResizePartition(p, partition.size)); - } - } - return builder; -} - -class MetadataMatcher : public MatcherInterface<MetadataBuilder*> { - public: - explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes) - : partition_metadata_(partitionSuffixSizesToMetadata(partition_sizes)) {} - explicit MetadataMatcher(const PartitionMetadata& partition_metadata) - : partition_metadata_(partition_metadata) {} - - bool MatchAndExplain(MetadataBuilder* metadata, - MatchResultListener* listener) const override { - bool success = true; - for (const auto& group : partition_metadata_.groups) { - for (const auto& partition : group.partitions) { - auto p = metadata->FindPartition(partition.name); - if (p == nullptr) { - if (!success) - *listener << "; "; - *listener << "No partition " << partition.name; - success = false; - continue; - } - if (p->size() != partition.size) { - if (!success) - *listener << "; "; - *listener << "Partition " << partition.name << " has size " - << p->size() << ", expected " << partition.size; - success = false; - } - if (p->group_name() != group.name) { - if (!success) - *listener << "; "; - *listener << "Partition " << partition.name << " has group " - << p->group_name() << ", expected " << group.name; - success = false; - } - } - } - return success; - } - - void DescribeTo(std::ostream* os) const override { - *os << "expect: " << partition_metadata_; - } - - void DescribeNegationTo(std::ostream* os) const override { - *os << "expect not: " << partition_metadata_; - } - - private: - PartitionMetadata partition_metadata_; -}; - -inline Matcher<MetadataBuilder*> MetadataMatches( - const PartitionSuffixSizes& partition_sizes) { - return MakeMatcher(new MetadataMatcher(partition_sizes)); -} - -inline Matcher<MetadataBuilder*> MetadataMatches( - const PartitionMetadata& partition_metadata) { - return MakeMatcher(new MetadataMatcher(partition_metadata)); -} - -MATCHER_P(HasGroup, group, " has group " + group) { - auto groups = arg->ListGroups(); - return std::find(groups.begin(), groups.end(), group) != groups.end(); -} - -class BootControlAndroidTest : public ::testing::Test { - protected: - void SetUp() override { - // Fake init bootctl_ - bootctl_.module_ = new NiceMock<MockBootControlHal>(); - bootctl_.dynamic_control_ = - std::make_unique<NiceMock<MockDynamicPartitionControl>>(); - - ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] { - return kMaxNumSlots; - })); - ON_CALL(module(), getSuffix(_, _)) - .WillByDefault(Invoke([](auto slot, auto cb) { - EXPECT_LE(slot, kMaxNumSlots); - cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : ""); - return Void(); - })); - - ON_CALL(dynamicControl(), IsDynamicPartitionsEnabled()) - .WillByDefault(Return(true)); - ON_CALL(dynamicControl(), IsDynamicPartitionsRetrofit()) - .WillByDefault(Return(false)); - ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true)); - ON_CALL(dynamicControl(), GetDeviceDir(_)) - .WillByDefault(Invoke([](auto path) { - *path = kFakeDevicePath; - return true; - })); - ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _)) - .WillByDefault(Invoke([](auto partition_name_suffix, auto device) { - *device = GetDmDevice(partition_name_suffix); - return true; - })); - } - - // Return the mocked HAL module. - NiceMock<MockBootControlHal>& module() { - return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_); - } - - // Return the mocked DynamicPartitionControlInterface. - NiceMock<MockDynamicPartitionControl>& dynamicControl() { - return static_cast<NiceMock<MockDynamicPartitionControl>&>( - *bootctl_.dynamic_control_); - } - - // Set the fake metadata to return when LoadMetadataBuilder is called on - // |slot|. - void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) { - SetMetadata(slot, partitionSuffixSizesToMetadata(sizes)); - } - - void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) { - EXPECT_CALL(dynamicControl(), - LoadMetadataBuilder(GetSuperDevice(slot), slot, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke([metadata](auto, auto, auto) { - return NewFakeMetadata(metadata); - })); - } - - // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata - // slot with each partition in |partitions|. - void ExpectUnmap(const std::set<string>& partitions) { - // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments. - ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _)) - .WillByDefault(Return(false)); - - for (const auto& partition : partitions) { - EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _)) - .WillOnce(Invoke([this](auto partition, auto) { - mapped_devices_.erase(partition); - return true; - })); - } - } - - void ExpectDevicesAreMapped(const std::set<string>& partitions) { - ASSERT_EQ(partitions.size(), mapped_devices_.size()); - for (const auto& partition : partitions) { - EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition)))) - << "Expect that " << partition << " is mapped, but it is not."; - } - } - - void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) { - ExpectStoreMetadataMatch(MetadataMatches(partition_sizes)); - } - - virtual void ExpectStoreMetadataMatch( - const Matcher<MetadataBuilder*>& matcher) { - EXPECT_CALL(dynamicControl(), - StoreMetadata(GetSuperDevice(target()), matcher, target())) - .WillOnce(Return(true)); - } - - uint32_t source() { return slots_.source; } - - uint32_t target() { return slots_.target; } - - // Return partition names with suffix of source(). - string S(const string& name) { return name + kSlotSuffixes[source()]; } - - // Return partition names with suffix of target(). - string T(const string& name) { return name + kSlotSuffixes[target()]; } - - // Set source and target slots to use before testing. - void SetSlots(const TestParam& slots) { - slots_ = slots; - - ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] { - return source(); - })); - // Should not store metadata to source slot. - EXPECT_CALL(dynamicControl(), - StoreMetadata(GetSuperDevice(source()), _, source())) - .Times(0); - // Should not load metadata from target slot. - EXPECT_CALL(dynamicControl(), - LoadMetadataBuilder(GetSuperDevice(target()), target(), _)) - .Times(0); - } - - bool InitPartitionMetadata(uint32_t slot, - PartitionSizes partition_sizes, - bool update_metadata = true) { - auto m = partitionSizesToMetadata(partition_sizes); - LOG(INFO) << m; - return bootctl_.InitPartitionMetadata(slot, m, update_metadata); - } - - BootControlAndroid bootctl_; // BootControlAndroid under test. - TestParam slots_; - // mapped devices through MapPartitionOnDeviceMapper. - std::map<string, string> mapped_devices_; -}; - -class BootControlAndroidTestP - : public BootControlAndroidTest, - public ::testing::WithParamInterface<TestParam> { - public: - void SetUp() override { - BootControlAndroidTest::SetUp(); - SetSlots(GetParam()); - } -}; - -// Test resize case. Grow if target metadata contains a partition with a size -// less than expected. -TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) { - SetMetadata(source(), - {{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 1_GiB}}); - ExpectStoreMetadata({{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 3_GiB}, - {T("vendor"), 1_GiB}}); - ExpectUnmap({T("system"), T("vendor")}); - - EXPECT_TRUE( - InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}})); -} - -// Test resize case. Shrink if target metadata contains a partition with a size -// greater than expected. -TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) { - SetMetadata(source(), - {{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 1_GiB}}); - ExpectStoreMetadata({{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 150_MiB}}); - ExpectUnmap({T("system"), T("vendor")}); - - EXPECT_TRUE(InitPartitionMetadata(target(), - {{"system", 2_GiB}, {"vendor", 150_MiB}})); -} - -// Test adding partitions on the first run. -TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) { - SetMetadata(source(), PartitionSuffixSizes{}); - ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}}); - ExpectUnmap({T("system"), T("vendor")}); - - EXPECT_TRUE( - InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}})); -} - -// Test subsequent add case. -TEST_P(BootControlAndroidTestP, AddAdditionalPartition) { - SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}}); - ExpectStoreMetadata( - {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}}); - ExpectUnmap({T("system"), T("vendor")}); - - EXPECT_TRUE( - InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}})); -} - -// Test delete one partition. -TEST_P(BootControlAndroidTestP, DeletePartition) { - SetMetadata(source(), - {{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 1_GiB}}); - // No T("vendor") - ExpectStoreMetadata( - {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}}); - ExpectUnmap({T("system")}); - - EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}})); -} - -// Test delete all partitions. -TEST_P(BootControlAndroidTestP, DeleteAll) { - SetMetadata(source(), - {{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 1_GiB}}); - ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}); - - EXPECT_TRUE(InitPartitionMetadata(target(), {})); -} - -// Test corrupt source metadata case. -TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) { - EXPECT_CALL(dynamicControl(), - LoadMetadataBuilder(GetSuperDevice(source()), source(), _)) - .WillOnce(Invoke([](auto, auto, auto) { return nullptr; })); - ExpectUnmap({T("system")}); - - EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}})) - << "Should not be able to continue with corrupt source metadata"; -} - -// Test that InitPartitionMetadata fail if there is not enough space on the -// device. -TEST_P(BootControlAndroidTestP, NotEnoughSpace) { - SetMetadata(source(), - {{S("system"), 3_GiB}, - {S("vendor"), 2_GiB}, - {T("system"), 0}, - {T("vendor"), 0}}); - EXPECT_FALSE( - InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}})) - << "Should not be able to fit 11GiB data into 10GiB space"; -} - -TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) { - SetMetadata(source(), - {{S("system"), 1_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 0}, - {T("vendor"), 0}}); - EXPECT_FALSE( - InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}})) - << "Should not be able to grow over size of super / 2"; -} - -// Test applying retrofit update on a build with dynamic partitions enabled. -TEST_P(BootControlAndroidTestP, - ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) { - SetMetadata(source(), - {{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 1_GiB}}); - // Should not try to unmap any target partition. - EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _)).Times(0); - // Should not store metadata to target slot. - EXPECT_CALL(dynamicControl(), - StoreMetadata(GetSuperDevice(target()), _, target())) - .Times(0); - - // Not calling through BootControlAndroidTest::InitPartitionMetadata(), since - // we don't want any default group in the PartitionMetadata. - EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}, true)); - - // Should use dynamic source partitions. - EXPECT_CALL(dynamicControl(), GetState(S("system"))) - .Times(1) - .WillOnce(Return(DmDeviceState::ACTIVE)); - string system_device; - EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device)); - EXPECT_EQ(GetDmDevice(S("system")), system_device); - - // Should use static target partitions without querying dynamic control. - EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0); - EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device)); - EXPECT_EQ(GetDevice(T("system")), system_device); - - // Static partition "bar". - EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0); - std::string bar_device; - EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device)); - EXPECT_EQ(GetDevice(S("bar")), bar_device); - - EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0); - EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device)); - EXPECT_EQ(GetDevice(T("bar")), bar_device); -} - -TEST_P(BootControlAndroidTestP, GetPartitionDeviceWhenResumingUpdate) { - // Both of the two slots contain valid partition metadata, since this is - // resuming an update. - SetMetadata(source(), - {{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 1_GiB}}); - SetMetadata(target(), - {{S("system"), 2_GiB}, - {S("vendor"), 1_GiB}, - {T("system"), 2_GiB}, - {T("vendor"), 1_GiB}}); - EXPECT_CALL(dynamicControl(), - StoreMetadata(GetSuperDevice(target()), _, target())) - .Times(0); - EXPECT_TRUE(InitPartitionMetadata( - target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}, false)); - - // Dynamic partition "system". - EXPECT_CALL(dynamicControl(), GetState(S("system"))) - .Times(1) - .WillOnce(Return(DmDeviceState::ACTIVE)); - string system_device; - EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device)); - EXPECT_EQ(GetDmDevice(S("system")), system_device); - - EXPECT_CALL(dynamicControl(), GetState(T("system"))) - .Times(1) - .WillOnce(Return(DmDeviceState::ACTIVE)); - EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device)); - EXPECT_EQ(GetDmDevice(T("system")), system_device); - - // Static partition "bar". - EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0); - std::string bar_device; - EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device)); - EXPECT_EQ(GetDevice(S("bar")), bar_device); - - EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0); - EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device)); - EXPECT_EQ(GetDevice(T("bar")), bar_device); -} - -INSTANTIATE_TEST_CASE_P(BootControlAndroidTest, - BootControlAndroidTestP, - testing::Values(TestParam{0, 1}, TestParam{1, 0})); - -const PartitionSuffixSizes update_sizes_0() { - // Initial state is 0 for "other" slot. - return { - {"grown_a", 2_GiB}, - {"shrunk_a", 1_GiB}, - {"same_a", 100_MiB}, - {"deleted_a", 150_MiB}, - // no added_a - {"grown_b", 200_MiB}, - // simulate system_other - {"shrunk_b", 0}, - {"same_b", 0}, - {"deleted_b", 0}, - // no added_b - }; -} - -const PartitionSuffixSizes update_sizes_1() { - return { - {"grown_a", 2_GiB}, - {"shrunk_a", 1_GiB}, - {"same_a", 100_MiB}, - {"deleted_a", 150_MiB}, - // no added_a - {"grown_b", 3_GiB}, - {"shrunk_b", 150_MiB}, - {"same_b", 100_MiB}, - {"added_b", 150_MiB}, - // no deleted_b - }; -} - -const PartitionSuffixSizes update_sizes_2() { - return { - {"grown_a", 4_GiB}, - {"shrunk_a", 100_MiB}, - {"same_a", 100_MiB}, - {"deleted_a", 64_MiB}, - // no added_a - {"grown_b", 3_GiB}, - {"shrunk_b", 150_MiB}, - {"same_b", 100_MiB}, - {"added_b", 150_MiB}, - // no deleted_b - }; -} - -// Test case for first update after the device is manufactured, in which -// case the "other" slot is likely of size "0" (except system, which is -// non-zero because of system_other partition) -TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) { - SetSlots({0, 1}); - - SetMetadata(source(), update_sizes_0()); - SetMetadata(target(), update_sizes_0()); - ExpectStoreMetadata(update_sizes_1()); - ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"}); - - EXPECT_TRUE(InitPartitionMetadata(target(), - {{"grown", 3_GiB}, - {"shrunk", 150_MiB}, - {"same", 100_MiB}, - {"added", 150_MiB}})); -} - -// After first update, test for the second update. In the second update, the -// "added" partition is deleted and "deleted" partition is re-added. -TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) { - SetSlots({1, 0}); - - SetMetadata(source(), update_sizes_1()); - SetMetadata(target(), update_sizes_0()); - - ExpectStoreMetadata(update_sizes_2()); - ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"}); - - EXPECT_TRUE(InitPartitionMetadata(target(), - {{"grown", 4_GiB}, - {"shrunk", 100_MiB}, - {"same", 100_MiB}, - {"deleted", 64_MiB}})); -} - -TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) { - SetSlots({1, 1}); - EXPECT_FALSE(InitPartitionMetadata(target(), {})) - << "Should not be able to apply to current slot."; -} - -class BootControlAndroidGroupTestP : public BootControlAndroidTestP { - public: - void SetUp() override { - BootControlAndroidTestP::SetUp(); - SetMetadata( - source(), - {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB), - SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB), - SimpleGroup(T("android"), 3_GiB, T("system"), 0), - SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}}); - } - - // Return a simple group with only one partition. - PartitionMetadata::Group SimpleGroup(const string& group, - uint64_t group_size, - const string& partition, - uint64_t partition_size) { - return {.name = group, - .size = group_size, - .partitions = {{.name = partition, .size = partition_size}}}; - } - - void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) { - ExpectStoreMetadataMatch(MetadataMatches(partition_metadata)); - } - - // Expect that target slot is stored with target groups. - void ExpectStoreMetadataMatch( - const Matcher<MetadataBuilder*>& matcher) override { - BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf( - MetadataMatches(PartitionMetadata{ - .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB), - SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}), - matcher)); - } -}; - -// Allow to resize within group. -TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) { - ExpectStoreMetadata(PartitionMetadata{ - .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB), - SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}}); - ExpectUnmap({T("system"), T("vendor")}); - - EXPECT_TRUE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{ - .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB), - SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}, - true)); -} - -TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) { - EXPECT_FALSE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{ - .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB), - SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}, - true)) - << "Should not be able to grow over maximum size of group"; -} - -TEST_P(BootControlAndroidGroupTestP, GroupTooBig) { - EXPECT_FALSE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB}, - {.name = "oem", .size = 3_GiB}}}, - true)) - << "Should not be able to grow over size of super / 2"; -} - -TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) { - ExpectStoreMetadata(PartitionMetadata{ - .groups = { - {.name = T("android"), - .size = 3_GiB, - .partitions = {{.name = T("system"), .size = 2_GiB}, - {.name = T("product_services"), .size = 1_GiB}}}}}); - ExpectUnmap({T("system"), T("vendor"), T("product_services")}); - - EXPECT_TRUE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{ - .groups = {{.name = "android", - .size = 3_GiB, - .partitions = {{.name = "system", .size = 2_GiB}, - {.name = "product_services", - .size = 1_GiB}}}, - SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}, - true)); -} - -TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) { - ExpectStoreMetadata(PartitionMetadata{ - .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}}); - ExpectUnmap({T("vendor")}); - - EXPECT_TRUE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{ - .groups = {{.name = "android", .size = 3_GiB, .partitions = {}}, - SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}, - true)); -} - -TEST_P(BootControlAndroidGroupTestP, AddGroup) { - ExpectStoreMetadata(PartitionMetadata{ - .groups = { - SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}}); - ExpectUnmap({T("system"), T("vendor"), T("new_partition")}); - - EXPECT_TRUE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{ - .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB), - SimpleGroup("oem", 1_GiB, "vendor", 1_GiB), - SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}, - true)); -} - -TEST_P(BootControlAndroidGroupTestP, RemoveGroup) { - ExpectStoreMetadataMatch(Not(HasGroup(T("oem")))); - ExpectUnmap({T("system")}); - EXPECT_TRUE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{ - .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}, - true)); -} - -TEST_P(BootControlAndroidGroupTestP, ResizeGroup) { - ExpectStoreMetadata(PartitionMetadata{ - .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB), - SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}}); - ExpectUnmap({T("system"), T("vendor")}); - - EXPECT_TRUE(bootctl_.InitPartitionMetadata( - target(), - PartitionMetadata{ - .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB), - SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}, - true)); -} - -INSTANTIATE_TEST_CASE_P(BootControlAndroidTest, - BootControlAndroidGroupTestP, - testing::Values(TestParam{0, 1}, TestParam{1, 0})); - -} // namespace chromeos_update_engine |