Merge "Add a test for bug 198265278."

This commit is contained in:
David Anderson 2021-10-08 19:29:16 +00:00 committed by Gerrit Code Review
commit a5df9e5db1
3 changed files with 113 additions and 30 deletions

View File

@ -408,6 +408,7 @@ class SnapshotManager final : public ISnapshotManager {
FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
FRIEND_TEST(SnapshotUpdateTest, QueryStatusError);
FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate);
friend class SnapshotTest;

View File

@ -100,6 +100,9 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
return IDeviceInfo::OpenImageManager("ota/test");
}
android::dm::IDeviceMapper& GetDeviceMapper() override {
if (dm_) {
return *dm_;
}
return android::dm::DeviceMapper::Instance();
}
@ -111,6 +114,8 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
}
void set_recovery(bool value) { recovery_ = value; }
void set_first_stage_init(bool value) { first_stage_init_ = value; }
void set_dm(android::dm::IDeviceMapper* dm) { dm_ = dm; }
MergeStatus merge_status() const { return merge_status_; }
private:
@ -120,6 +125,45 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
bool recovery_ = false;
bool first_stage_init_ = false;
std::unordered_set<uint32_t> unbootable_slots_;
android::dm::IDeviceMapper* dm_ = nullptr;
};
class DeviceMapperWrapper : public android::dm::IDeviceMapper {
using DmDeviceState = android::dm::DmDeviceState;
using DmTable = android::dm::DmTable;
public:
DeviceMapperWrapper() : impl_(android::dm::DeviceMapper::Instance()) {}
explicit DeviceMapperWrapper(android::dm::IDeviceMapper& impl) : impl_(impl) {}
virtual bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
const std::chrono::milliseconds& timeout_ms) override {
return impl_.CreateDevice(name, table, path, timeout_ms);
}
virtual DmDeviceState GetState(const std::string& name) const override {
return impl_.GetState(name);
}
virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) {
return impl_.LoadTableAndActivate(name, table);
}
virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
return impl_.GetTableInfo(name, table);
}
virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
return impl_.GetTableStatus(name, table);
}
virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) {
return impl_.GetDmDevicePathByName(name, path);
}
virtual bool GetDeviceString(const std::string& name, std::string* dev) {
return impl_.GetDeviceString(name, dev);
}
virtual bool DeleteDeviceIfExists(const std::string& name) {
return impl_.DeleteDeviceIfExists(name);
}
private:
android::dm::IDeviceMapper& impl_;
};
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {

View File

@ -56,6 +56,7 @@ namespace snapshot {
using android::base::unique_fd;
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
using android::dm::IDeviceMapper;
using android::fiemap::FiemapStatus;
using android::fiemap::IImageManager;
using android::fs_mgr::BlockDeviceInfo;
@ -911,6 +912,11 @@ class SnapshotUpdateTest : public SnapshotTest {
ASSERT_TRUE(hash.has_value());
hashes_[name] = *hash;
}
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
}
}
void TearDown() override {
RETURN_IF_NON_VIRTUAL_AB();
@ -925,6 +931,14 @@ class SnapshotUpdateTest : public SnapshotTest {
MountMetadata();
for (const auto& suffix : {"_a", "_b"}) {
test_device->set_slot_suffix(suffix);
// Cheat our way out of merge failed states.
if (sm->ProcessUpdateState() == UpdateState::MergeFailed) {
ASSERT_TRUE(AcquireLock());
ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
lock_ = {};
}
EXPECT_TRUE(sm->CancelUpdate()) << suffix;
}
EXPECT_TRUE(UnmapAll());
@ -1097,11 +1111,6 @@ class SnapshotUpdateTest : public SnapshotTest {
// Also test UnmapUpdateSnapshot unmaps everything.
// Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
}
// Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
// fit in super, but not |prd|.
constexpr uint64_t partition_size = 3788_KiB;
@ -1189,11 +1198,6 @@ TEST_F(SnapshotUpdateTest, DuplicateOps) {
GTEST_SKIP() << "Compression-only test";
}
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
}
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
@ -1239,11 +1243,6 @@ TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
GTEST_SKIP() << "Skipping Virtual A/B Compression test";
}
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
}
auto old_sys_size = GetSize(sys_);
auto old_prd_size = GetSize(prd_);
@ -1630,11 +1629,6 @@ TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
ASSERT_NE(nullptr, metadata);
ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
}
// Add operations for sys. The whole device is written.
AddOperation(sys_);
@ -2074,11 +2068,6 @@ TEST_F(SnapshotUpdateTest, LowSpace) {
}
TEST_F(SnapshotUpdateTest, AddPartition) {
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
}
group_->add_partition_names("dlkm");
auto dlkm = manifest_.add_partitions();
@ -2249,6 +2238,60 @@ TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
ASSERT_TRUE(sm->BeginUpdate());
}
TEST_F(SnapshotUpdateTest, QueryStatusError) {
// Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
// fit in super, but not |prd|.
constexpr uint64_t partition_size = 3788_KiB;
SetSize(sys_, partition_size);
AddOperationForPartitions({sys_});
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
ASSERT_TRUE(UnmapAll());
class DmStatusFailure final : public DeviceMapperWrapper {
public:
bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override {
if (!DeviceMapperWrapper::GetTableStatus(name, table)) {
return false;
}
if (name == "sys_b" && !table->empty()) {
auto& info = table->at(0);
if (DeviceMapper::GetTargetType(info.spec) == "snapshot-merge") {
info.data = "Merge failed";
}
}
return true;
}
};
DmStatusFailure wrapper;
// After reboot, init does first stage mount.
auto info = new TestDeviceInfo(fake_super, "_b");
info->set_dm(&wrapper);
auto init = NewManagerForFirstStageMount(info);
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Initiate the merge and wait for it to be completed.
ASSERT_TRUE(init->InitiateMerge());
ASSERT_EQ(UpdateState::MergeFailed, init->ProcessUpdateState());
// Simulate a reboot that tries the merge again, with the non-failing dm.
ASSERT_TRUE(UnmapAll());
init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
}
class FlashAfterUpdateTest : public SnapshotUpdateTest,
public WithParamInterface<std::tuple<uint32_t, bool>> {
public:
@ -2265,11 +2308,6 @@ class FlashAfterUpdateTest : public SnapshotUpdateTest,
};
TEST_P(FlashAfterUpdateTest, FlashSlotAfterUpdate) {
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
}
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));