diff options
Diffstat (limited to 'src/test/rbd_mirror/image_replayer/test_mock_PrepareRemoteImageRequest.cc')
-rw-r--r-- | src/test/rbd_mirror/image_replayer/test_mock_PrepareRemoteImageRequest.cc | 811 |
1 files changed, 811 insertions, 0 deletions
diff --git a/src/test/rbd_mirror/image_replayer/test_mock_PrepareRemoteImageRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_PrepareRemoteImageRequest.cc new file mode 100644 index 000000000..e5b473c0f --- /dev/null +++ b/src/test/rbd_mirror/image_replayer/test_mock_PrepareRemoteImageRequest.cc @@ -0,0 +1,811 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/rbd_mirror/test_mock_fixture.h" +#include "cls/rbd/cls_rbd_types.h" +#include "librbd/journal/TypeTraits.h" +#include "librbd/mirror/GetInfoRequest.h" +#include "tools/rbd_mirror/Threads.h" +#include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h" +#include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h" +#include "tools/rbd_mirror/image_replayer/StateBuilder.h" +#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h" +#include "tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h" +#include "test/journal/mock/MockJournaler.h" +#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" +#include "test/librbd/mock/MockImageCtx.h" + +namespace librbd { + +namespace { + +struct MockTestImageCtx : public librbd::MockImageCtx { + MockTestImageCtx(librbd::ImageCtx &image_ctx) + : librbd::MockImageCtx(image_ctx) { + } +}; + +} // anonymous namespace + +namespace journal { + +template <> +struct TypeTraits<MockTestImageCtx> { + typedef ::journal::MockJournalerProxy Journaler; +}; + +} // namespace journal + +namespace mirror { + +template<> +struct GetInfoRequest<librbd::MockTestImageCtx> { + static GetInfoRequest* s_instance; + cls::rbd::MirrorImage *mirror_image; + PromotionState *promotion_state; + std::string *primary_mirror_uuid; + Context *on_finish = nullptr; + + static GetInfoRequest* create(librados::IoCtx& io_ctx, + librbd::asio::ContextWQ* context_wq, + const std::string& image_id, + cls::rbd::MirrorImage *mirror_image, + PromotionState *promotion_state, + std::string* primary_mirror_uuid, + Context *on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->mirror_image = mirror_image; + s_instance->promotion_state = promotion_state; + s_instance->primary_mirror_uuid = primary_mirror_uuid; + s_instance->on_finish = on_finish; + return s_instance; + } + + GetInfoRequest() { + ceph_assert(s_instance == nullptr); + s_instance = this; + } + ~GetInfoRequest() { + s_instance = nullptr; + } + + MOCK_METHOD0(send, void()); +}; + +GetInfoRequest<librbd::MockTestImageCtx>* GetInfoRequest<librbd::MockTestImageCtx>::s_instance = nullptr; + +} // namespace mirror +} // namespace librbd + +namespace rbd { +namespace mirror { + +template <> +struct Threads<librbd::MockTestImageCtx> { + ceph::mutex &timer_lock; + SafeTimer *timer; + librbd::asio::ContextWQ *work_queue; + + Threads(Threads<librbd::ImageCtx> *threads) + : timer_lock(threads->timer_lock), timer(threads->timer), + work_queue(threads->work_queue) { + } +}; + +namespace image_replayer { + +template <> +struct GetMirrorImageIdRequest<librbd::MockTestImageCtx> { + static GetMirrorImageIdRequest* s_instance; + std::string* image_id = nullptr; + Context* on_finish = nullptr; + + static GetMirrorImageIdRequest* create(librados::IoCtx& io_ctx, + const std::string& global_image_id, + std::string* image_id, + Context* on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->image_id = image_id; + s_instance->on_finish = on_finish; + return s_instance; + } + + GetMirrorImageIdRequest() { + s_instance = this; + } + + MOCK_METHOD0(send, void()); +}; + +template<> +struct StateBuilder<librbd::MockTestImageCtx> { + std::string local_image_id; + librbd::mirror::PromotionState local_promotion_state = + librbd::mirror::PROMOTION_STATE_NON_PRIMARY; + std::string remote_image_id; + std::string remote_mirror_uuid; + librbd::mirror::PromotionState remote_promotion_state; + + virtual ~StateBuilder() {} + + MOCK_CONST_METHOD0(get_mirror_image_mode, cls::rbd::MirrorImageMode()); +}; + +GetMirrorImageIdRequest<librbd::MockTestImageCtx>* GetMirrorImageIdRequest<librbd::MockTestImageCtx>::s_instance = nullptr; + +namespace journal { + +template<> +struct StateBuilder<librbd::MockTestImageCtx> + : public image_replayer::StateBuilder<librbd::MockTestImageCtx> { + static StateBuilder* s_instance; + + cls::rbd::MirrorImageMode mirror_image_mode = + cls::rbd::MIRROR_IMAGE_MODE_JOURNAL; + + ::journal::MockJournalerProxy* remote_journaler = nullptr; + cls::journal::ClientState remote_client_state; + librbd::journal::MirrorPeerClientMeta remote_client_meta; + + static StateBuilder* create(const std::string&) { + ceph_assert(s_instance != nullptr); + return s_instance; + } + + StateBuilder() { + s_instance = this; + } +}; + +StateBuilder<librbd::MockTestImageCtx>* StateBuilder<librbd::MockTestImageCtx>::s_instance = nullptr; + +} // namespace journal + +namespace snapshot { + +template<> +struct StateBuilder<librbd::MockTestImageCtx> + : public image_replayer::StateBuilder<librbd::MockTestImageCtx> { + static StateBuilder* s_instance; + + cls::rbd::MirrorImageMode mirror_image_mode = + cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT; + + std::string remote_mirror_peer_uuid; + + static StateBuilder* create(const std::string&) { + ceph_assert(s_instance != nullptr); + return s_instance; + } + + StateBuilder() { + s_instance = this; + } +}; + +StateBuilder<librbd::MockTestImageCtx>* StateBuilder<librbd::MockTestImageCtx>::s_instance = nullptr; + +} // namespace snapshot +} // namespace image_replayer +} // namespace mirror +} // namespace rbd + +// template definitions +#include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.cc" + +namespace rbd { +namespace mirror { +namespace image_replayer { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::WithArg; + +class TestMockImageReplayerPrepareRemoteImageRequest : public TestMockFixture { +public: + typedef Threads<librbd::MockTestImageCtx> MockThreads; + typedef PrepareRemoteImageRequest<librbd::MockTestImageCtx> MockPrepareRemoteImageRequest; + typedef GetMirrorImageIdRequest<librbd::MockTestImageCtx> MockGetMirrorImageIdRequest; + typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder; + typedef journal::StateBuilder<librbd::MockTestImageCtx> MockJournalStateBuilder; + typedef snapshot::StateBuilder<librbd::MockTestImageCtx> MockSnapshotStateBuilder; + typedef librbd::mirror::GetInfoRequest<librbd::MockTestImageCtx> MockGetMirrorInfoRequest; + + void expect_get_mirror_image_mode(MockStateBuilder& mock_state_builder, + cls::rbd::MirrorImageMode mirror_image_mode) { + EXPECT_CALL(mock_state_builder, get_mirror_image_mode()) + .WillOnce(Return(mirror_image_mode)); + } + + void expect_get_mirror_image_id(MockGetMirrorImageIdRequest& mock_get_mirror_image_id_request, + const std::string& image_id, int r) { + EXPECT_CALL(mock_get_mirror_image_id_request, send()) + .WillOnce(Invoke([&mock_get_mirror_image_id_request, image_id, r]() { + *mock_get_mirror_image_id_request.image_id = image_id; + mock_get_mirror_image_id_request.on_finish->complete(r); + })); + } + + void expect_get_mirror_info( + MockGetMirrorInfoRequest &mock_get_mirror_info_request, + const cls::rbd::MirrorImage &mirror_image, + librbd::mirror::PromotionState promotion_state, + const std::string& primary_mirror_uuid, int r) { + EXPECT_CALL(mock_get_mirror_info_request, send()) + .WillOnce(Invoke([this, &mock_get_mirror_info_request, mirror_image, + promotion_state, primary_mirror_uuid, r]() { + *mock_get_mirror_info_request.mirror_image = mirror_image; + *mock_get_mirror_info_request.promotion_state = promotion_state; + *mock_get_mirror_info_request.primary_mirror_uuid = + primary_mirror_uuid; + m_threads->work_queue->queue( + mock_get_mirror_info_request.on_finish, r); + })); + } + + void expect_journaler_get_client(::journal::MockJournaler &mock_journaler, + const std::string &client_id, + cls::journal::Client &client, int r) { + EXPECT_CALL(mock_journaler, get_client(StrEq(client_id), _, _)) + .WillOnce(DoAll(WithArg<1>(Invoke([client](cls::journal::Client *out_client) { + *out_client = client; + })), + WithArg<2>(Invoke([this, r](Context *on_finish) { + m_threads->work_queue->queue(on_finish, r); + })))); + } + + void expect_journaler_register_client(::journal::MockJournaler &mock_journaler, + const librbd::journal::ClientData &client_data, + int r) { + bufferlist bl; + encode(client_data, bl); + + EXPECT_CALL(mock_journaler, register_client(ContentsEqual(bl), _)) + .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) { + m_threads->work_queue->queue(on_finish, r); + }))); + } +}; + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, SuccessJournal) { + ::journal::MockJournaler mock_remote_journaler; + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", 0); + + EXPECT_CALL(mock_remote_journaler, construct()); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + librbd::journal::ClientData client_data{mirror_peer_client_meta}; + cls::journal::Client client; + client.state = cls::journal::CLIENT_STATE_DISCONNECTED; + encode(client_data, client.data); + expect_journaler_get_client(mock_remote_journaler, "local mirror uuid", + client, 0); + + MockJournalStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = nullptr; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(0, ctx.wait()); + ASSERT_TRUE(mock_state_builder != nullptr); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + mock_journal_state_builder.mirror_image_mode); + ASSERT_EQ(std::string("remote mirror uuid"), + mock_journal_state_builder.remote_mirror_uuid); + ASSERT_EQ(std::string("remote image id"), + mock_journal_state_builder.remote_image_id); + ASSERT_EQ(librbd::mirror::PROMOTION_STATE_PRIMARY, + mock_journal_state_builder.remote_promotion_state); + ASSERT_TRUE(mock_journal_state_builder.remote_journaler != nullptr); + ASSERT_EQ(cls::journal::CLIENT_STATE_DISCONNECTED, + mock_journal_state_builder.remote_client_state); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, SuccessSnapshot) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", 0); + + MockSnapshotStateBuilder mock_snapshot_state_builder; + MockStateBuilder* mock_state_builder = nullptr; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", + "remote mirror peer uuid"}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(0, ctx.wait()); + ASSERT_TRUE(mock_state_builder != nullptr); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + mock_snapshot_state_builder.mirror_image_mode); + ASSERT_EQ(std::string("remote mirror uuid"), + mock_snapshot_state_builder.remote_mirror_uuid); + ASSERT_EQ(std::string("remote mirror peer uuid"), + mock_snapshot_state_builder.remote_mirror_peer_uuid); + ASSERT_EQ(std::string("remote image id"), + mock_snapshot_state_builder.remote_image_id); + ASSERT_EQ(librbd::mirror::PROMOTION_STATE_PRIMARY, + mock_snapshot_state_builder.remote_promotion_state); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, SuccessNotRegistered) { + ::journal::MockJournaler mock_remote_journaler; + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", 0); + + MockJournalStateBuilder mock_journal_state_builder; + expect_get_mirror_image_mode(mock_journal_state_builder, + cls::rbd::MIRROR_IMAGE_MODE_JOURNAL); + + EXPECT_CALL(mock_remote_journaler, construct()); + + cls::journal::Client client; + expect_journaler_get_client(mock_remote_journaler, "local mirror uuid", + client, -ENOENT); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; + librbd::journal::ClientData client_data{mirror_peer_client_meta}; + expect_journaler_register_client(mock_remote_journaler, client_data, 0); + + mock_journal_state_builder.local_image_id = "local image id"; + MockStateBuilder* mock_state_builder = &mock_journal_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(0, ctx.wait()); + ASSERT_TRUE(mock_state_builder != nullptr); + ASSERT_EQ(std::string("remote image id"), + mock_journal_state_builder.remote_image_id); + ASSERT_EQ(librbd::mirror::PROMOTION_STATE_PRIMARY, + mock_journal_state_builder.remote_promotion_state); + ASSERT_TRUE(mock_journal_state_builder.remote_journaler != nullptr); + ASSERT_EQ(cls::journal::CLIENT_STATE_CONNECTED, + mock_journal_state_builder.remote_client_state); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, GetMirrorImageIdError) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "", -EINVAL); + + MockJournalStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = &mock_journal_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); + ASSERT_TRUE(mock_journal_state_builder.remote_journaler == nullptr); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, GetMirrorInfoError) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", -EINVAL); + + MockJournalStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = nullptr; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); + ASSERT_TRUE(mock_state_builder == nullptr); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, GetClientError) { + ::journal::MockJournaler mock_remote_journaler; + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", 0); + + EXPECT_CALL(mock_remote_journaler, construct()); + + cls::journal::Client client; + expect_journaler_get_client(mock_remote_journaler, "local mirror uuid", + client, -EINVAL); + + MockJournalStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = nullptr; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); + ASSERT_TRUE(mock_state_builder == nullptr); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, RegisterClientError) { + ::journal::MockJournaler mock_remote_journaler; + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", 0); + + MockJournalStateBuilder mock_journal_state_builder; + expect_get_mirror_image_mode(mock_journal_state_builder, + cls::rbd::MIRROR_IMAGE_MODE_JOURNAL); + + EXPECT_CALL(mock_remote_journaler, construct()); + + cls::journal::Client client; + expect_journaler_get_client(mock_remote_journaler, "local mirror uuid", + client, -ENOENT); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; + librbd::journal::ClientData client_data{mirror_peer_client_meta}; + expect_journaler_register_client(mock_remote_journaler, client_data, -EINVAL); + + mock_journal_state_builder.local_image_id = "local image id"; + MockStateBuilder* mock_state_builder = &mock_journal_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorImageIdDNEJournal) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "", -ENOENT); + + MockJournalStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = &mock_journal_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + mock_journal_state_builder.mirror_image_mode); + ASSERT_EQ("remote mirror uuid", + mock_journal_state_builder.remote_mirror_uuid); + ASSERT_EQ("", mock_journal_state_builder.remote_image_id); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorImageIdDNESnapshot) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "", -ENOENT); + + MockSnapshotStateBuilder mock_snapshot_state_builder; + MockStateBuilder* mock_state_builder = &mock_snapshot_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", + "remote mirror peer uuid"}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + mock_snapshot_state_builder.mirror_image_mode); + ASSERT_EQ("remote mirror uuid", + mock_snapshot_state_builder.remote_mirror_uuid); + ASSERT_EQ("remote mirror peer uuid", + mock_snapshot_state_builder.remote_mirror_peer_uuid); + ASSERT_EQ("", mock_snapshot_state_builder.remote_image_id); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorInfoDNEJournal) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", -ENOENT); + + MockJournalStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = &mock_journal_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + mock_journal_state_builder.mirror_image_mode); + ASSERT_EQ("remote mirror uuid", + mock_journal_state_builder.remote_mirror_uuid); + ASSERT_EQ("", mock_journal_state_builder.remote_image_id); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorInfoDNESnapshot) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", -ENOENT); + + MockSnapshotStateBuilder mock_snapshot_state_builder; + MockStateBuilder* mock_state_builder = &mock_snapshot_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", + "remote mirror peer uuid"}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + mock_snapshot_state_builder.mirror_image_mode); + ASSERT_EQ("remote mirror uuid", + mock_snapshot_state_builder.remote_mirror_uuid); + ASSERT_EQ("remote mirror peer uuid", + mock_snapshot_state_builder.remote_mirror_peer_uuid); + ASSERT_EQ("", mock_snapshot_state_builder.remote_image_id); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorInfoDisablingJournal) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_DISABLING}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", 0); + + MockJournalStateBuilder mock_journal_state_builder; + expect_get_mirror_image_mode(mock_journal_state_builder, + cls::rbd::MIRROR_IMAGE_MODE_JOURNAL); + MockStateBuilder* mock_state_builder = &mock_journal_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", ""}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, + mock_journal_state_builder.mirror_image_mode); + ASSERT_EQ("remote mirror uuid", + mock_journal_state_builder.remote_mirror_uuid); + ASSERT_EQ("", mock_journal_state_builder.remote_image_id); +} + +TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorInfoDisablingSnapshot) { + MockThreads mock_threads(m_threads); + + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, + "remote image id", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_DISABLING}, + librbd::mirror::PROMOTION_STATE_PRIMARY, + "remote mirror uuid", 0); + + MockSnapshotStateBuilder mock_snapshot_state_builder; + expect_get_mirror_image_mode(mock_snapshot_state_builder, + cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT); + MockStateBuilder* mock_state_builder = &mock_snapshot_state_builder; + C_SaferCond ctx; + auto req = MockPrepareRemoteImageRequest::create(&mock_threads, + m_local_io_ctx, + m_remote_io_ctx, + "global image id", + "local mirror uuid", + {"remote mirror uuid", + "remote mirror peer uuid"}, + nullptr, + &mock_state_builder, + &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); + ASSERT_EQ(cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + mock_snapshot_state_builder.mirror_image_mode); + ASSERT_EQ("remote mirror uuid", + mock_snapshot_state_builder.remote_mirror_uuid); + ASSERT_EQ("remote mirror peer uuid", + mock_snapshot_state_builder.remote_mirror_peer_uuid); + ASSERT_EQ("", mock_snapshot_state_builder.remote_image_id); +} + +} // namespace image_replayer +} // namespace mirror +} // namespace rbd |