X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ceph%2Fsrc%2Ftest%2Frbd_mirror%2Ftest_mock_InstanceReplayer.cc;h=1903c55f2c9032b84c585614bf534155cea12c4c;hb=d2e6a577eb19928d58b31d1b6e096ca0f03c4052;hp=6e2d58c0aa0e234e60f2dbf8afebc3a429c16744;hpb=c07f9fc5a4f48397831383549fb0482b93480643;p=ceph.git diff --git a/ceph/src/test/rbd_mirror/test_mock_InstanceReplayer.cc b/ceph/src/test/rbd_mirror/test_mock_InstanceReplayer.cc index 6e2d58c0a..1903c55f2 100644 --- a/ceph/src/test/rbd_mirror/test_mock_InstanceReplayer.cc +++ b/ceph/src/test/rbd_mirror/test_mock_InstanceReplayer.cc @@ -3,6 +3,8 @@ #include "test/librbd/mock/MockImageCtx.h" #include "test/rbd_mirror/test_mock_fixture.h" +#include "test/rbd_mirror/mock/MockContextWQ.h" +#include "test/rbd_mirror/mock/MockSafeTimer.h" #include "tools/rbd_mirror/ImageDeleter.h" #include "tools/rbd_mirror/ImageReplayer.h" #include "tools/rbd_mirror/InstanceWatcher.h" @@ -30,22 +32,25 @@ namespace mirror { template <> struct Threads { + MockSafeTimer *timer; Mutex &timer_lock; - SafeTimer *timer; - ContextWQ *work_queue; + Cond timer_cond; + + MockContextWQ *work_queue; Threads(Threads *threads) - : timer_lock(threads->timer_lock), timer(threads->timer), - work_queue(threads->work_queue) { + : timer(new MockSafeTimer()), + timer_lock(threads->timer_lock), + work_queue(new MockContextWQ()) { + } + ~Threads() { + delete timer; + delete work_queue; } }; template <> struct ImageDeleter { - MOCK_METHOD4(schedule_image_delete, void(RadosRef, int64_t, - const std::string&, bool)); - MOCK_METHOD4(wait_for_scheduled_deletion, - void(int64_t, const std::string&, Context*, bool)); }; template<> @@ -91,19 +96,16 @@ struct ImageReplayer { MOCK_METHOD0(restart, void()); MOCK_METHOD0(flush, void()); MOCK_METHOD2(print_status, void(Formatter *, stringstream *)); - MOCK_METHOD3(add_remote_image, void(const std::string &, - const std::string &, - librados::IoCtx &)); - MOCK_METHOD3(remove_remote_image, void(const std::string &, - const std::string &, - bool)); - MOCK_METHOD0(remote_images_empty, bool()); + MOCK_METHOD2(add_peer, void(const std::string &, librados::IoCtx &)); MOCK_METHOD0(get_global_image_id, const std::string &()); MOCK_METHOD0(get_local_image_id, const std::string &()); MOCK_METHOD0(is_running, bool()); MOCK_METHOD0(is_stopped, bool()); MOCK_METHOD0(is_blacklisted, bool()); + MOCK_CONST_METHOD0(is_finished, bool()); + MOCK_METHOD1(set_finished, void(bool)); + MOCK_CONST_METHOD0(get_health_state, image_replayer::HealthState()); }; @@ -127,73 +129,79 @@ using ::testing::WithArg; class TestMockInstanceReplayer : public TestMockFixture { public: + typedef Threads MockThreads; typedef ImageDeleter MockImageDeleter; typedef ImageReplayer MockImageReplayer; typedef InstanceReplayer MockInstanceReplayer; typedef InstanceWatcher MockInstanceWatcher; typedef ServiceDaemon MockServiceDaemon; - typedef Threads MockThreads; - - void SetUp() override { - TestMockFixture::SetUp(); - m_mock_threads = new MockThreads(m_threads); + void expect_work_queue(MockThreads &mock_threads) { + EXPECT_CALL(*mock_threads.work_queue, queue(_, _)) + .WillOnce(Invoke([this](Context *ctx, int r) { + m_threads->work_queue->queue(ctx, r); + })); } - void TearDown() override { - delete m_mock_threads; - TestMockFixture::TearDown(); + void expect_add_event_after(MockThreads &mock_threads, + Context** timer_ctx = nullptr) { + EXPECT_CALL(*mock_threads.timer, add_event_after(_, _)) + .WillOnce(WithArg<1>( + Invoke([this, &mock_threads, timer_ctx](Context *ctx) { + assert(mock_threads.timer_lock.is_locked()); + if (timer_ctx != nullptr) { + *timer_ctx = ctx; + mock_threads.timer_cond.SignalOne(); + } else { + m_threads->work_queue->queue( + new FunctionContext([&mock_threads, ctx](int) { + Mutex::Locker timer_lock(mock_threads.timer_lock); + ctx->complete(0); + }), 0); + } + }))); } - void expect_wait_for_scheduled_deletion(MockImageDeleter& mock_image_deleter, - const std::string& global_image_id, - int r) { - EXPECT_CALL(mock_image_deleter, - wait_for_scheduled_deletion(_, global_image_id, _, false)) - .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { - m_threads->work_queue->queue(ctx, r); - }))); + void expect_cancel_event(MockThreads &mock_threads, bool canceled) { + EXPECT_CALL(*mock_threads.timer, cancel_event(_)) + .WillOnce(Return(canceled)); } - - MockThreads *m_mock_threads; }; TEST_F(TestMockInstanceReplayer, AcquireReleaseImage) { + MockThreads mock_threads(m_threads); MockServiceDaemon mock_service_daemon; MockImageDeleter mock_image_deleter; MockInstanceWatcher mock_instance_watcher; MockImageReplayer mock_image_replayer; MockInstanceReplayer instance_replayer( - m_mock_threads, &mock_service_daemon, &mock_image_deleter, + &mock_threads, &mock_service_daemon, &mock_image_deleter, rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)), "local_mirror_uuid", m_local_io_ctx.get_id()); - std::string global_image_id("global_image_id"); EXPECT_CALL(mock_image_replayer, get_global_image_id()) .WillRepeatedly(ReturnRef(global_image_id)); - EXPECT_CALL(mock_image_replayer, is_blacklisted()) - .WillRepeatedly(Return(false)); - - expect_wait_for_scheduled_deletion(mock_image_deleter, "global_image_id", 0); InSequence seq; - + expect_work_queue(mock_threads); + Context *timer_ctx = nullptr; + expect_add_event_after(mock_threads, &timer_ctx); instance_replayer.init(); - instance_replayer.add_peer("remote_mirror_uuid", m_remote_io_ctx); + instance_replayer.add_peer("peer_uuid", m_remote_io_ctx); // Acquire C_SaferCond on_acquire; - - EXPECT_CALL(mock_image_replayer, add_remote_image("remote_mirror_uuid", - "remote_image_id", _)); - EXPECT_CALL(mock_image_replayer, is_stopped()) - .WillOnce(Return(true)); + EXPECT_CALL(mock_image_replayer, add_peer("peer_uuid", _)); + EXPECT_CALL(mock_image_replayer, set_finished(false)); + EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true)); + EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false)); + EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(false)); EXPECT_CALL(mock_image_replayer, start(nullptr, false)); + expect_work_queue(mock_threads); instance_replayer.acquire_image(&mock_instance_watcher, global_image_id, - "remote_mirror_uuid", "remote_image_id", &on_acquire); ASSERT_EQ(0, on_acquire.wait()); @@ -201,31 +209,108 @@ TEST_F(TestMockInstanceReplayer, AcquireReleaseImage) { C_SaferCond on_release; - EXPECT_CALL(mock_image_replayer, - remove_remote_image("remote_mirror_uuid", "remote_image_id", - false)); - EXPECT_CALL(mock_image_replayer, remote_images_empty()) - .WillOnce(Return(true)); EXPECT_CALL(mock_image_replayer, is_stopped()) .WillOnce(Return(false)); EXPECT_CALL(mock_image_replayer, is_running()) .WillOnce(Return(false)); + expect_work_queue(mock_threads); + expect_add_event_after(mock_threads); + expect_work_queue(mock_threads); EXPECT_CALL(mock_image_replayer, is_stopped()) .WillOnce(Return(false)); EXPECT_CALL(mock_image_replayer, is_running()) .WillOnce(Return(true)); EXPECT_CALL(mock_image_replayer, stop(_, false)) .WillOnce(CompleteContext(0)); + expect_work_queue(mock_threads); EXPECT_CALL(mock_image_replayer, is_stopped()) .WillOnce(Return(true)); + expect_work_queue(mock_threads); EXPECT_CALL(mock_image_replayer, destroy()); - instance_replayer.release_image("global_image_id", "remote_mirror_uuid", - "remote_image_id", false, &on_release); + instance_replayer.release_image("global_image_id", &on_release); ASSERT_EQ(0, on_release.wait()); + expect_work_queue(mock_threads); + expect_cancel_event(mock_threads, true); + expect_work_queue(mock_threads); instance_replayer.shut_down(); + ASSERT_TRUE(timer_ctx != nullptr); + delete timer_ctx; } +TEST_F(TestMockInstanceReplayer, RemoveFinishedImage) { + MockThreads mock_threads(m_threads); + MockServiceDaemon mock_service_daemon; + MockImageDeleter mock_image_deleter; + MockInstanceWatcher mock_instance_watcher; + MockImageReplayer mock_image_replayer; + MockInstanceReplayer instance_replayer( + &mock_threads, &mock_service_daemon, &mock_image_deleter, + rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)), + "local_mirror_uuid", m_local_io_ctx.get_id()); + std::string global_image_id("global_image_id"); + + EXPECT_CALL(mock_image_replayer, get_global_image_id()) + .WillRepeatedly(ReturnRef(global_image_id)); + + InSequence seq; + expect_work_queue(mock_threads); + Context *timer_ctx1 = nullptr; + expect_add_event_after(mock_threads, &timer_ctx1); + instance_replayer.init(); + instance_replayer.add_peer("peer_uuid", m_remote_io_ctx); + + // Acquire + + C_SaferCond on_acquire; + EXPECT_CALL(mock_image_replayer, add_peer("peer_uuid", _)); + EXPECT_CALL(mock_image_replayer, set_finished(false)); + EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true)); + EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false)); + EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(false)); + EXPECT_CALL(mock_image_replayer, start(nullptr, false)); + expect_work_queue(mock_threads); + + instance_replayer.acquire_image(&mock_instance_watcher, global_image_id, + &on_acquire); + ASSERT_EQ(0, on_acquire.wait()); + + // periodic start timer + Context *timer_ctx2 = nullptr; + expect_add_event_after(mock_threads, &timer_ctx2); + + Context *start_image_replayers_ctx = nullptr; + EXPECT_CALL(*mock_threads.work_queue, queue(_, 0)) + .WillOnce(Invoke([&start_image_replayers_ctx](Context *ctx, int r) { + start_image_replayers_ctx = ctx; + })); + + ASSERT_TRUE(timer_ctx1 != nullptr); + { + Mutex::Locker timer_locker(mock_threads.timer_lock); + timer_ctx1->complete(0); + } + + // remove finished image replayer + EXPECT_CALL(mock_image_replayer, get_health_state()).WillOnce( + Return(image_replayer::HEALTH_STATE_OK)); + EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true)); + EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false)); + EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(true)); + EXPECT_CALL(mock_image_replayer, destroy()); + EXPECT_CALL(mock_service_daemon,add_or_update_attribute(_, _, _)).Times(3); + + ASSERT_TRUE(start_image_replayers_ctx != nullptr); + start_image_replayers_ctx->complete(0); + + // shut down + expect_work_queue(mock_threads); + expect_cancel_event(mock_threads, true); + expect_work_queue(mock_threads); + instance_replayer.shut_down(); + ASSERT_TRUE(timer_ctx2 != nullptr); + delete timer_ctx2; +} } // namespace mirror } // namespace rbd