Add a test for bug 198265278.
This test uses dependency injection to cause a failure in QuerySnapshotStatus. We expect ProcessUpdateState to return MergeFailed. The test also checks that if the merge is attempted again, it can succeed. Some duplicated code has also been factored out into the test harness. Bug: 198265278 Test: vts_libsnapshot_test gtest Change-Id: I6ccb434afa0e5ebf6781b2cec5277e3b7c210b77
This commit is contained in:
parent
be17619ccc
commit
2374bd48ed
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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_));
|
||||
|
|
Loading…
Reference in New Issue