diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 40dcc2a8e..2368f8f36 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -219,6 +219,7 @@ cc_test { "libsnapshot_cow_defaults", ], srcs: [ + "testing/dm_user_harness.cpp", "user-space-merge/snapuserd_test.cpp", ], shared_libs: [ diff --git a/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp new file mode 100644 index 000000000..7cadf250c --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2023 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 "dm_user_harness.h" + +#include + +#include +#include +#include +#include + +namespace android { +namespace snapshot { + +using namespace std::chrono_literals; +using android::base::unique_fd; + +DmUserDevice::DmUserDevice(std::unique_ptr&& dev) : dev_(std::move(dev)) {} + +const std::string& DmUserDevice::GetPath() { + return dev_->path(); +} + +bool DmUserDevice::Destroy() { + return dev_->Destroy(); +} + +DmUserTestHarness::DmUserTestHarness() { + block_server_factory_ = std::make_unique(); +} + +std::unique_ptr DmUserTestHarness::CreateUserDevice(const std::string& dev_name, + const std::string& misc_name, + uint64_t num_sectors) { + android::dm::DmTable dmuser_table; + dmuser_table.Emplace(0, num_sectors, misc_name); + auto dev = std::make_unique(dev_name, dmuser_table); + if (!dev->valid()) { + return nullptr; + } + + auto misc_device = "/dev/dm-user/" + misc_name; + if (!android::fs_mgr::WaitForFile(misc_device, 10s)) { + return nullptr; + } + + return std::make_unique(std::move(dev)); +} + +IBlockServerFactory* DmUserTestHarness::GetBlockServerFactory() { + return block_server_factory_.get(); +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h new file mode 100644 index 000000000..cf26bed03 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h @@ -0,0 +1,54 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include + +#include "harness.h" +#include "temp_device.h" + +namespace android { +namespace snapshot { + +using android::base::unique_fd; + +class DmUserBlockServerFactory; + +class DmUserDevice final : public IUserDevice { + public: + explicit DmUserDevice(std::unique_ptr&& dev); + const std::string& GetPath() override; + bool Destroy() override; + + private: + std::unique_ptr dev_; +}; + +class DmUserTestHarness final : public ITestHarness { + public: + DmUserTestHarness(); + + std::unique_ptr CreateUserDevice(const std::string& dev_name, + const std::string& misc_name, + uint64_t num_sectors) override; + IBlockServerFactory* GetBlockServerFactory() override; + bool HasUserDevice() override { return true; } + + private: + std::unique_ptr block_server_factory_; +}; + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/testing/harness.h b/fs_mgr/libsnapshot/snapuserd/testing/harness.h new file mode 100644 index 000000000..c0d528f8b --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/harness.h @@ -0,0 +1,47 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include + +#include + +#include +#include + +namespace android { +namespace snapshot { + +// Interface for a "block driver in userspace" device. +class IUserDevice { + public: + virtual ~IUserDevice() {} + virtual const std::string& GetPath() = 0; + virtual bool Destroy() = 0; +}; + +class ITestHarness { + public: + virtual ~ITestHarness() {} + virtual std::unique_ptr CreateUserDevice(const std::string& dev_name, + const std::string& misc_name, + uint64_t num_sectors) = 0; + virtual IBlockServerFactory* GetBlockServerFactory() = 0; + virtual bool HasUserDevice() = 0; +}; + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp index 157925d63..4ea1d5d08 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -41,6 +41,7 @@ #include #include "handler_manager.h" #include "snapuserd_core.h" +#include "testing/dm_user_harness.h" #include "testing/temp_device.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); @@ -75,10 +76,9 @@ class SnapuserdTest : public ::testing::Test { static const uint64_t kSectorSize = 512; protected: - void SetUp() override {} + void SetUp() override; void TearDown() override { Shutdown(); } - private: void SetupImpl(); void SimulateDaemonRestart(); @@ -94,10 +94,10 @@ class SnapuserdTest : public ::testing::Test { void InitCowDevice(); void SetDeviceControlName(); void InitDaemon(); - void CreateDmUserDevice(); + void CreateUserDevice(); unique_ptr base_loop_; - unique_ptr dmuser_dev_; + unique_ptr dmuser_dev_; std::string system_device_ctrl_name_; std::string system_device_name_; @@ -112,6 +112,7 @@ class SnapuserdTest : public ::testing::Test { size_t size_ = 100_MiB; int cow_num_sectors_; int total_base_size_; + std::unique_ptr harness_; }; static unique_fd CreateTempFile(const std::string& name, size_t size) { @@ -132,6 +133,10 @@ static unique_fd CreateTempFile(const std::string& name, size_t size) { return fd; } +void SnapuserdTest::SetUp() { + harness_ = std::make_unique(); +} + void SnapuserdTest::Shutdown() { ASSERT_TRUE(dmuser_dev_->Destroy()); @@ -173,7 +178,7 @@ bool SnapuserdTest::SetupCopyOverlap_2() { bool SnapuserdTest::SetupDaemon() { SetDeviceControlName(); - CreateDmUserDevice(); + CreateUserDevice(); InitCowDevice(); InitDaemon(); @@ -206,7 +211,7 @@ void SnapuserdTest::CreateBaseDevice() { } void SnapuserdTest::ReadSnapshotDeviceAndValidate() { - unique_fd fd(open(dmuser_dev_->path().c_str(), O_RDONLY)); + unique_fd fd(open(dmuser_dev_->GetPath().c_str(), O_RDONLY)); ASSERT_GE(fd, 0); std::unique_ptr snapuserd_buffer = std::make_unique(size_); @@ -535,9 +540,8 @@ void SnapuserdTest::InitCowDevice() { use_iouring = false; } - DmUserBlockServerFactory factory; - - auto opener = factory.CreateOpener(system_device_ctrl_name_); + auto factory = harness_->GetBlockServerFactory(); + auto opener = factory->CreateOpener(system_device_ctrl_name_); auto handler = handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_loop_->device(), base_loop_->device(), opener, 1, use_iouring, false); @@ -560,7 +564,7 @@ void SnapuserdTest::SetDeviceControlName() { system_device_ctrl_name_ = system_device_name_ + "-ctrl"; } -void SnapuserdTest::CreateDmUserDevice() { +void SnapuserdTest::CreateUserDevice() { unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC))); ASSERT_TRUE(fd > 0); @@ -569,17 +573,9 @@ void SnapuserdTest::CreateDmUserDevice() { cow_num_sectors_ = dev_sz >> 9; - DmTable dmuser_table; - ASSERT_TRUE(dmuser_table.AddTarget( - std::make_unique(0, cow_num_sectors_, system_device_ctrl_name_))); - ASSERT_TRUE(dmuser_table.valid()); - - dmuser_dev_ = std::make_unique(system_device_name_, dmuser_table); - ASSERT_TRUE(dmuser_dev_->valid()); - ASSERT_FALSE(dmuser_dev_->path().empty()); - - auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_; - ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s)); + dmuser_dev_ = harness_->CreateUserDevice(system_device_name_, system_device_ctrl_name_, + cow_num_sectors_); + ASSERT_NE(dmuser_dev_, nullptr); } void SnapuserdTest::InitDaemon() { @@ -603,7 +599,7 @@ void SnapuserdTest::SetupImpl() { SetDeviceControlName(); - CreateDmUserDevice(); + CreateUserDevice(); InitCowDevice(); InitDaemon(); @@ -632,7 +628,7 @@ void SnapuserdTest::SimulateDaemonRestart() { Shutdown(); std::this_thread::sleep_for(500ms); SetDeviceControlName(); - CreateDmUserDevice(); + CreateUserDevice(); InitCowDevice(); InitDaemon(); } @@ -695,6 +691,9 @@ void SnapuserdTest::MergeInterrupt() { } TEST_F(SnapuserdTest, Snapshot_IO_TEST) { + if (!harness_->HasUserDevice()) { + GTEST_SKIP() << "Skipping snapshot read; not supported"; + } ASSERT_TRUE(SetupDefault()); // I/O before merge ReadSnapshotDeviceAndValidate(); @@ -707,6 +706,9 @@ TEST_F(SnapuserdTest, Snapshot_IO_TEST) { } TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) { + if (!harness_->HasUserDevice()) { + GTEST_SKIP() << "Skipping snapshot read; not supported"; + } ASSERT_TRUE(SetupDefault()); // Issue I/O before merge begins std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); @@ -717,6 +719,9 @@ TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) { } TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) { + if (!harness_->HasUserDevice()) { + GTEST_SKIP() << "Skipping snapshot read; not supported"; + } ASSERT_TRUE(SetupDefault()); // Start the merge StartMerge();