blob: 574d30e8e0d458d1650c51bc77862c4c97810dae [file] [log] [blame]
Yifan Hongc049f932019-07-23 15:06:05 -07001//
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#ifndef UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_
18#define UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_
19
20#include <stdint.h>
21
22#include <iostream>
23#include <map>
24#include <memory>
25#include <string>
26#include <vector>
27
28#include <base/strings/string_util.h>
29#include <fs_mgr.h>
30#include <gmock/gmock.h>
31#include <gtest/gtest.h>
32#include <liblp/builder.h>
33
34#include "update_engine/common/boot_control_interface.h"
35
36namespace chromeos_update_engine {
37
38using android::fs_mgr::MetadataBuilder;
39using testing::_;
40using testing::MakeMatcher;
41using testing::Matcher;
42using testing::MatcherInterface;
43using testing::MatchResultListener;
44
45constexpr const uint32_t kMaxNumSlots = 2;
46constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
47constexpr const char* kFakeDevicePath = "/fake/dev/path/";
48constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/";
49constexpr const uint32_t kFakeMetadataSize = 65536;
50constexpr const char* kDefaultGroup = "foo";
Yifan Hong700d7c12019-07-23 20:49:16 -070051constexpr const char* kFakeSuper = "fake_super";
Yifan Hongc049f932019-07-23 15:06:05 -070052
53// A map describing the size of each partition.
54// "{name, size}"
55using PartitionSizes = std::map<std::string, uint64_t>;
56
57// "{name_a, size}"
58using PartitionSuffixSizes = std::map<std::string, uint64_t>;
59
60using PartitionMetadata = BootControlInterface::PartitionMetadata;
61
62// C++ standards do not allow uint64_t (aka unsigned long) to be the parameter
63// of user-defined literal operators.
64// clang-format off
65inline constexpr unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT
66 return x << 20;
67}
68inline constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
69 return x << 30;
70}
71// clang-format on
72
73constexpr uint64_t kDefaultGroupSize = 5_GiB;
74// Super device size. 1 MiB for metadata.
75constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
76
77template <typename U, typename V>
78inline std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
79 os << "{";
80 bool first = true;
81 for (const auto& pair : param) {
82 if (!first)
83 os << ", ";
84 os << pair.first << ":" << pair.second;
85 first = false;
86 }
87 return os << "}";
88}
89
90template <typename T>
91inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) {
92 os << "[";
93 bool first = true;
94 for (const auto& e : param) {
95 if (!first)
96 os << ", ";
97 os << e;
98 first = false;
99 }
100 return os << "]";
101}
102
103inline std::ostream& operator<<(std::ostream& os,
104 const PartitionMetadata::Partition& p) {
105 return os << "{" << p.name << ", " << p.size << "}";
106}
107
108inline std::ostream& operator<<(std::ostream& os,
109 const PartitionMetadata::Group& g) {
110 return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}";
111}
112
113inline std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) {
114 return os << m.groups;
115}
116
117inline std::string GetDevice(const std::string& name) {
118 return kFakeDevicePath + name;
119}
120
121inline std::string GetDmDevice(const std::string& name) {
122 return kFakeDmDevicePath + name;
123}
124
Yifan Hongc049f932019-07-23 15:06:05 -0700125// To support legacy tests, auto-convert {name_a: size} map to
126// PartitionMetadata.
127inline PartitionMetadata PartitionSuffixSizesToMetadata(
128 const PartitionSuffixSizes& partition_sizes) {
129 PartitionMetadata metadata;
130 for (const char* suffix : kSlotSuffixes) {
131 metadata.groups.push_back(
132 {std::string(kDefaultGroup) + suffix, kDefaultGroupSize, {}});
133 }
134 for (const auto& pair : partition_sizes) {
135 for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
136 if (base::EndsWith(pair.first,
137 kSlotSuffixes[suffix_idx],
138 base::CompareCase::SENSITIVE)) {
139 metadata.groups[suffix_idx].partitions.push_back(
140 {pair.first, pair.second});
141 }
142 }
143 }
144 return metadata;
145}
146
147// To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
148inline PartitionMetadata PartitionSizesToMetadata(
149 const PartitionSizes& partition_sizes) {
150 PartitionMetadata metadata;
151 metadata.groups.push_back(
152 {std::string{kDefaultGroup}, kDefaultGroupSize, {}});
153 for (const auto& pair : partition_sizes) {
154 metadata.groups[0].partitions.push_back({pair.first, pair.second});
155 }
156 return metadata;
157}
158
159inline std::unique_ptr<MetadataBuilder> NewFakeMetadata(
160 const PartitionMetadata& metadata) {
161 auto builder =
162 MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
163 EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2);
164 EXPECT_NE(nullptr, builder);
165 if (builder == nullptr)
166 return nullptr;
167 for (const auto& group : metadata.groups) {
168 EXPECT_TRUE(builder->AddGroup(group.name, group.size));
169 for (const auto& partition : group.partitions) {
170 auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */);
171 EXPECT_TRUE(p && builder->ResizePartition(p, partition.size));
172 }
173 }
174 return builder;
175}
176
177class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
178 public:
179 explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
180 : partition_metadata_(PartitionSuffixSizesToMetadata(partition_sizes)) {}
181 explicit MetadataMatcher(const PartitionMetadata& partition_metadata)
182 : partition_metadata_(partition_metadata) {}
183
184 bool MatchAndExplain(MetadataBuilder* metadata,
185 MatchResultListener* listener) const override {
186 bool success = true;
187 for (const auto& group : partition_metadata_.groups) {
188 for (const auto& partition : group.partitions) {
189 auto p = metadata->FindPartition(partition.name);
190 if (p == nullptr) {
191 if (!success)
192 *listener << "; ";
193 *listener << "No partition " << partition.name;
194 success = false;
195 continue;
196 }
197 if (p->size() != partition.size) {
198 if (!success)
199 *listener << "; ";
200 *listener << "Partition " << partition.name << " has size "
201 << p->size() << ", expected " << partition.size;
202 success = false;
203 }
204 if (p->group_name() != group.name) {
205 if (!success)
206 *listener << "; ";
207 *listener << "Partition " << partition.name << " has group "
208 << p->group_name() << ", expected " << group.name;
209 success = false;
210 }
211 }
212 }
213 return success;
214 }
215
216 void DescribeTo(std::ostream* os) const override {
217 *os << "expect: " << partition_metadata_;
218 }
219
220 void DescribeNegationTo(std::ostream* os) const override {
221 *os << "expect not: " << partition_metadata_;
222 }
223
224 private:
225 PartitionMetadata partition_metadata_;
226};
227
228inline Matcher<MetadataBuilder*> MetadataMatches(
229 const PartitionSuffixSizes& partition_sizes) {
230 return MakeMatcher(new MetadataMatcher(partition_sizes));
231}
232
233inline Matcher<MetadataBuilder*> MetadataMatches(
234 const PartitionMetadata& partition_metadata) {
235 return MakeMatcher(new MetadataMatcher(partition_metadata));
236}
237
238MATCHER_P(HasGroup, group, " has group " + group) {
239 auto groups = arg->ListGroups();
240 return std::find(groups.begin(), groups.end(), group) != groups.end();
241}
242
243struct TestParam {
244 uint32_t source;
245 uint32_t target;
246};
247inline std::ostream& operator<<(std::ostream& os, const TestParam& param) {
248 return os << "{source: " << param.source << ", target:" << param.target
249 << "}";
250}
251
252} // namespace chromeos_update_engine
253
254#endif // UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_