xref: /aosp_15_r20/system/core/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include <memory>
18 #include <optional>
19 #include <string>
20 #include <unordered_map>
21 #include <unordered_set>
22 
23 #include <android-base/file.h>
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26 #include <libfiemap/image_manager.h>
27 #include <liblp/mock_property_fetcher.h>
28 #include <liblp/partition_opener.h>
29 #include <libsnapshot/snapshot.h>
30 #include <storage_literals/storage_literals.h>
31 #include <update_engine/update_metadata.pb.h>
32 
33 #include "utility.h"
34 
35 namespace android {
36 namespace snapshot {
37 
38 using aidl::android::hardware::boot::MergeStatus;
39 using android::fs_mgr::IPropertyFetcher;
40 using android::fs_mgr::MetadataBuilder;
41 using android::fs_mgr::testing::MockPropertyFetcher;
42 using chromeos_update_engine::DeltaArchiveManifest;
43 using chromeos_update_engine::PartitionUpdate;
44 using testing::_;
45 using testing::AssertionResult;
46 using testing::NiceMock;
47 
48 using namespace android::storage_literals;
49 using namespace std::string_literals;
50 
51 // These are not reset between each test because it's expensive to create
52 // these resources (starting+connecting to gsid, zero-filling images).
53 extern std::unique_ptr<SnapshotManager> sm;
54 extern class TestDeviceInfo* test_device;
55 extern std::string fake_super;
56 static constexpr uint64_t kSuperSize = 32_MiB + 4_KiB;
57 static constexpr uint64_t kGroupSize = 32_MiB;
58 
59 // Redirect requests for "super" to our fake super partition.
60 class TestPartitionOpener final : public android::fs_mgr::PartitionOpener {
61   public:
TestPartitionOpener(const std::string & fake_super_path)62     explicit TestPartitionOpener(const std::string& fake_super_path)
63         : fake_super_path_(fake_super_path) {}
64 
65     android::base::unique_fd Open(const std::string& partition_name, int flags) const override;
66     bool GetInfo(const std::string& partition_name,
67                  android::fs_mgr::BlockDeviceInfo* info) const override;
68     std::string GetDeviceString(const std::string& partition_name) const override;
69 
70   private:
71     std::string fake_super_path_;
72 };
73 
74 class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
75   public:
TestDeviceInfo()76     TestDeviceInfo() {}
TestDeviceInfo(const std::string & fake_super)77     explicit TestDeviceInfo(const std::string& fake_super) { set_fake_super(fake_super); }
TestDeviceInfo(const std::string & fake_super,const std::string & slot_suffix)78     TestDeviceInfo(const std::string& fake_super, const std::string& slot_suffix)
79         : TestDeviceInfo(fake_super) {
80         set_slot_suffix(slot_suffix);
81     }
GetMetadataDir()82     std::string GetMetadataDir() const override { return metadata_dir_; }
GetSlotSuffix()83     std::string GetSlotSuffix() const override { return slot_suffix_; }
GetOtherSlotSuffix()84     std::string GetOtherSlotSuffix() const override { return slot_suffix_ == "_a" ? "_b" : "_a"; }
GetSuperDevice(uint32_t slot)85     std::string GetSuperDevice([[maybe_unused]] uint32_t slot) const override { return "super"; }
GetPartitionOpener()86     const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const override {
87         return *opener_.get();
88     }
SetBootControlMergeStatus(MergeStatus status)89     bool SetBootControlMergeStatus(MergeStatus status) override {
90         merge_status_ = status;
91         return true;
92     }
IsOverlayfsSetup()93     bool IsOverlayfsSetup() const override { return false; }
IsRecovery()94     bool IsRecovery() const override { return recovery_; }
SetActiveBootSlot(unsigned int slot)95     bool SetActiveBootSlot([[maybe_unused]] unsigned int slot) override { return true; }
SetSlotAsUnbootable(unsigned int slot)96     bool SetSlotAsUnbootable(unsigned int slot) override {
97         unbootable_slots_.insert(slot);
98         return true;
99     }
IsTestDevice()100     bool IsTestDevice() const override { return true; }
IsFirstStageInit()101     bool IsFirstStageInit() const override { return first_stage_init_; }
OpenImageManager()102     std::unique_ptr<IImageManager> OpenImageManager() const override {
103         return IDeviceInfo::OpenImageManager("ota/test");
104     }
GetDeviceMapper()105     android::dm::IDeviceMapper& GetDeviceMapper() override {
106         if (dm_) {
107             return *dm_;
108         }
109         return android::dm::DeviceMapper::Instance();
110     }
111 
IsSlotUnbootable(uint32_t slot)112     bool IsSlotUnbootable(uint32_t slot) { return unbootable_slots_.count(slot) != 0; }
113 
set_slot_suffix(const std::string & suffix)114     void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
set_fake_super(const std::string & path)115     void set_fake_super(const std::string& path) {
116         opener_ = std::make_unique<TestPartitionOpener>(path);
117     }
set_recovery(bool value)118     void set_recovery(bool value) { recovery_ = value; }
set_first_stage_init(bool value)119     void set_first_stage_init(bool value) { first_stage_init_ = value; }
set_dm(android::dm::IDeviceMapper * dm)120     void set_dm(android::dm::IDeviceMapper* dm) { dm_ = dm; }
121 
merge_status()122     MergeStatus merge_status() const { return merge_status_; }
IsTempMetadata()123     bool IsTempMetadata() const override { return temp_metadata_; }
124 
125   private:
126     std::string slot_suffix_ = "_a";
127     std::unique_ptr<TestPartitionOpener> opener_;
128     MergeStatus merge_status_;
129     bool recovery_ = false;
130     bool first_stage_init_ = false;
131     std::unordered_set<uint32_t> unbootable_slots_;
132     android::dm::IDeviceMapper* dm_ = nullptr;
133     std::string metadata_dir_ = "/metadata/ota/test";
134     bool temp_metadata_ = false;
135 };
136 
137 class DeviceMapperWrapper : public android::dm::IDeviceMapper {
138     using DmDeviceState = android::dm::DmDeviceState;
139     using DmTable = android::dm::DmTable;
140 
141   public:
DeviceMapperWrapper()142     DeviceMapperWrapper() : impl_(android::dm::DeviceMapper::Instance()) {}
DeviceMapperWrapper(android::dm::IDeviceMapper & impl)143     explicit DeviceMapperWrapper(android::dm::IDeviceMapper& impl) : impl_(impl) {}
144 
CreateDevice(const std::string & name,const DmTable & table,std::string * path,const std::chrono::milliseconds & timeout_ms)145     virtual bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
146                               const std::chrono::milliseconds& timeout_ms) override {
147         return impl_.CreateDevice(name, table, path, timeout_ms);
148     }
GetState(const std::string & name)149     virtual DmDeviceState GetState(const std::string& name) const override {
150         return impl_.GetState(name);
151     }
LoadTable(const std::string & name,const DmTable & table)152     virtual bool LoadTable(const std::string& name, const DmTable& table) {
153         return impl_.LoadTable(name, table);
154     }
LoadTableAndActivate(const std::string & name,const DmTable & table)155     virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) {
156         return impl_.LoadTableAndActivate(name, table);
157     }
GetTableInfo(const std::string & name,std::vector<TargetInfo> * table)158     virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
159         return impl_.GetTableInfo(name, table);
160     }
GetTableStatus(const std::string & name,std::vector<TargetInfo> * table)161     virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
162         return impl_.GetTableStatus(name, table);
163     }
GetTableStatusIma(const std::string & name,std::vector<TargetInfo> * table)164     virtual bool GetTableStatusIma(const std::string& name, std::vector<TargetInfo>* table) {
165         return impl_.GetTableStatusIma(name, table);
166     }
GetDmDevicePathByName(const std::string & name,std::string * path)167     virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) {
168         return impl_.GetDmDevicePathByName(name, path);
169     }
GetDeviceString(const std::string & name,std::string * dev)170     virtual bool GetDeviceString(const std::string& name, std::string* dev) {
171         return impl_.GetDeviceString(name, dev);
172     }
DeleteDeviceIfExists(const std::string & name)173     virtual bool DeleteDeviceIfExists(const std::string& name) {
174         return impl_.DeleteDeviceIfExists(name);
175     }
176 
177   private:
178     android::dm::IDeviceMapper& impl_;
179 };
180 
181 class SnapshotTestPropertyFetcher : public android::fs_mgr::IPropertyFetcher {
182   public:
183     explicit SnapshotTestPropertyFetcher(const std::string& slot_suffix,
184                                          std::unordered_map<std::string, std::string>&& props = {});
185 
186     std::string GetProperty(const std::string& key, const std::string& defaultValue) override;
187     bool GetBoolProperty(const std::string& key, bool defaultValue) override;
188 
189     static void SetUp(const std::string& slot_suffix = "_a") { Reset(slot_suffix); }
TearDown()190     static void TearDown() { Reset("_a"); }
191 
192   private:
Reset(const std::string & slot_suffix)193     static void Reset(const std::string& slot_suffix) {
194         IPropertyFetcher::OverrideForTesting(
195                 std::make_unique<SnapshotTestPropertyFetcher>(slot_suffix));
196     }
197 
198   private:
199     std::unordered_map<std::string, std::string> properties_;
200 };
201 
202 // Helper for error-spam-free cleanup.
203 void DeleteBackingImage(android::fiemap::IImageManager* manager, const std::string& name);
204 
205 // Write some random data to the given device.
206 // If expect_size is not specified, will write until reaching end of the device.
207 // Expect space of |path| is multiple of 4K.
208 bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
209                      std::string* hash = nullptr);
210 std::string HashSnapshot(ICowWriter::FileDescriptor* writer);
211 
212 std::string ToHexString(const uint8_t* buf, size_t len);
213 
214 std::optional<std::string> GetHash(const std::string& path);
215 
216 // Add partitions and groups described by |manifest|.
217 AssertionResult FillFakeMetadata(MetadataBuilder* builder, const DeltaArchiveManifest& manifest,
218                                  const std::string& suffix);
219 
220 // In the update package metadata, set a partition with the given size.
221 void SetSize(PartitionUpdate* partition_update, uint64_t size);
222 
223 // Get partition size from update package metadata.
224 uint64_t GetSize(PartitionUpdate* partition_update);
225 
226 bool IsVirtualAbEnabled();
227 
228 #define SKIP_IF_NON_VIRTUAL_AB()                                                        \
229     do {                                                                                \
230         if (!IsVirtualAbEnabled()) GTEST_SKIP() << "Test for Virtual A/B devices only"; \
231     } while (0)
232 
233 #define RETURN_IF_NON_VIRTUAL_AB_MSG(msg) \
234     do {                                  \
235         if (!IsVirtualAbEnabled()) {      \
236             std::cerr << (msg);           \
237             return;                       \
238         }                                 \
239     } while (0)
240 
241 #define RETURN_IF_NON_VIRTUAL_AB() RETURN_IF_NON_VIRTUAL_AB_MSG("")
242 
243 #define SKIP_IF_VENDOR_ON_ANDROID_S()                                        \
244     do {                                                                     \
245         if (IsVendorFromAndroid12())                                         \
246             GTEST_SKIP() << "Skip test as Vendor partition is on Android S"; \
247     } while (0)
248 
249 #define RETURN_IF_VENDOR_ON_ANDROID_S_MSG(msg) \
250     do {                                       \
251         if (IsVendorFromAndroid12()) {         \
252             std::cerr << (msg);                \
253             return;                            \
254         }                                      \
255     } while (0)
256 
257 #define RETURN_IF_VENDOR_ON_ANDROID_S() RETURN_IF_VENDOR_ON_ANDROID_S_MSG("")
258 
259 }  // namespace snapshot
260 }  // namespace android
261