#include "test/rbd_mirror/test_mock_fixture.h"
#include "librbd/deep_copy/ImageCopyRequest.h"
#include "librbd/deep_copy/SnapshotCopyRequest.h"
+#include "librbd/mirror/ImageStateUpdateRequest.h"
#include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h"
#include "librbd/mirror/snapshot/GetImageStateRequest.h"
#include "librbd/mirror/snapshot/ImageMeta.h"
} // namespace deep_copy
namespace mirror {
+
+template <>
+struct ImageStateUpdateRequest<MockTestImageCtx> {
+ static ImageStateUpdateRequest* s_instance;
+ static ImageStateUpdateRequest* create(
+ librados::IoCtx& io_ctx,
+ const std::string& image_id,
+ cls::rbd::MirrorImageState mirror_image_state,
+ const cls::rbd::MirrorImage& mirror_image,
+ Context* on_finish) {
+ ceph_assert(s_instance != nullptr);
+ EXPECT_EQ(cls::rbd::MIRROR_IMAGE_STATE_ENABLED,
+ mirror_image_state);
+ EXPECT_EQ(cls::rbd::MirrorImage{}, mirror_image);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ Context* on_finish = nullptr;
+ ImageStateUpdateRequest() {
+ s_instance = this;
+ }
+
+ MOCK_METHOD0(send, void());
+};
+
+ImageStateUpdateRequest<MockTestImageCtx>* ImageStateUpdateRequest<MockTestImageCtx>::s_instance = nullptr;
+
namespace snapshot {
template <>
typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest;
typedef librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
typedef librbd::deep_copy::SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
+ typedef librbd::mirror::ImageStateUpdateRequest<librbd::MockTestImageCtx> MockImageStateUpdateRequest;
typedef librbd::mirror::snapshot::CreateNonPrimaryRequest<librbd::MockTestImageCtx> MockCreateNonPrimaryRequest;
typedef librbd::mirror::snapshot::GetImageStateRequest<librbd::MockTestImageCtx> MockGetImageStateRequest;
typedef librbd::mirror::snapshot::ImageMeta<librbd::MockTestImageCtx> MockImageMeta;
}));
}
+ void expect_update_mirror_image_state(MockImageStateUpdateRequest& mock_image_state_update_request,
+ int r) {
+ EXPECT_CALL(mock_image_state_update_request, send())
+ .WillOnce(Invoke([this, &req=mock_image_state_update_request, r]() {
+ m_threads->work_queue->queue(req.on_finish, r);
+ }));
+ }
+
void expect_notify_sync_request(MockInstanceWatcher& mock_instance_watcher,
const std::string& image_id, int r) {
EXPECT_CALL(mock_instance_watcher, notify_sync_request(image_id, _))
expect_create_non_primary_request(mock_create_non_primary_request,
false, "remote mirror uuid", 1,
{{1, CEPH_NOSNAP}}, 11, 0);
+ MockImageStateUpdateRequest mock_image_state_update_request;
+ expect_update_mirror_image_state(mock_image_state_update_request, 0);
expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
MockImageCopyRequest mock_image_copy_request;
expect_image_copy(mock_image_copy_request, 0, 1, 0, {},
expect_create_non_primary_request(mock_create_non_primary_request,
true, "remote mirror uuid", 1,
{{1, CEPH_NOSNAP}}, 11, 0);
+ MockImageStateUpdateRequest mock_image_state_update_request;
+ expect_update_mirror_image_state(mock_image_state_update_request, 0);
expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
MockImageCopyRequest mock_image_copy_request;
expect_image_copy(mock_image_copy_request, 0, 1, 0, {},
mock_remote_image_ctx));
}
+TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateMirrorImageStateError) {
+ librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx};
+ librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx};
+
+ MockThreads mock_threads(m_threads);
+ expect_work_queue_repeatedly(mock_threads);
+
+ MockReplayerListener mock_replayer_listener;
+ expect_notification(mock_threads, mock_replayer_listener);
+
+ InSequence seq;
+
+ MockInstanceWatcher mock_instance_watcher;
+ MockImageMeta mock_image_meta;
+ MockStateBuilder mock_state_builder(mock_local_image_ctx,
+ mock_remote_image_ctx,
+ mock_image_meta);
+ MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher,
+ "local mirror uuid", &m_pool_meta_cache,
+ &mock_state_builder, &mock_replayer_listener};
+ m_pool_meta_cache.set_remote_pool_meta(
+ m_remote_io_ctx.get_id(),
+ {"remote mirror uuid", "remote mirror peer uuid"});
+
+ librbd::UpdateWatchCtx* update_watch_ctx = nullptr;
+ ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads,
+ mock_local_image_ctx,
+ mock_remote_image_ctx,
+ mock_replayer_listener,
+ mock_image_meta,
+ &update_watch_ctx));
+
+ // inject snapshot
+ mock_remote_image_ctx.snap_info = {
+ {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{
+ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "",
+ CEPH_NOSNAP, true, 0, {}},
+ 0, {}, 0, 0, {}}}};
+
+ // sync snap1
+ expect_load_image_meta(mock_image_meta, false, 0);
+ expect_is_refresh_required(mock_local_image_ctx, false);
+ expect_is_refresh_required(mock_remote_image_ctx, false);
+ MockSnapshotCopyRequest mock_snapshot_copy_request;
+ expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}},
+ 0);
+ MockGetImageStateRequest mock_get_image_state_request;
+ expect_get_image_state(mock_get_image_state_request, 1, 0);
+ MockCreateNonPrimaryRequest mock_create_non_primary_request;
+ expect_create_non_primary_request(mock_create_non_primary_request,
+ false, "remote mirror uuid", 1,
+ {{1, CEPH_NOSNAP}}, 11, 0);
+ MockImageStateUpdateRequest mock_image_state_update_request;
+ expect_update_mirror_image_state(mock_image_state_update_request, -EIO);
+
+ // wake-up replayer
+ update_watch_ctx->handle_notify();
+
+ // wait for sync to complete and expect replay complete
+ ASSERT_EQ(0, wait_for_notification(1));
+ ASSERT_FALSE(mock_replayer.is_replaying());
+ ASSERT_EQ(-EIO, mock_replayer.get_error_code());
+
+ ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads,
+ mock_local_image_ctx,
+ mock_remote_image_ctx));
+}
+
TEST_F(TestMockImageReplayerSnapshotReplayer, RequestSyncError) {
librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx};
librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx};
expect_create_non_primary_request(mock_create_non_primary_request,
false, "remote mirror uuid", 1,
{{1, CEPH_NOSNAP}}, 11, 0);
+ MockImageStateUpdateRequest mock_image_state_update_request;
+ expect_update_mirror_image_state(mock_image_state_update_request, 0);
expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
-ECANCELED);
ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads,
mock_local_image_ctx,
mock_remote_image_ctx));
-
}
TEST_F(TestMockImageReplayerSnapshotReplayer, CopyImageError) {
expect_create_non_primary_request(mock_create_non_primary_request,
false, "remote mirror uuid", 1,
{{1, CEPH_NOSNAP}}, 11, 0);
+ MockImageStateUpdateRequest mock_image_state_update_request;
+ expect_update_mirror_image_state(mock_image_state_update_request, 0);
expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
MockImageCopyRequest mock_image_copy_request;
expect_image_copy(mock_image_copy_request, 0, 1, 0, {},
expect_create_non_primary_request(mock_create_non_primary_request,
false, "remote mirror uuid", 1,
{{1, CEPH_NOSNAP}}, 11, 0);
+ MockImageStateUpdateRequest mock_image_state_update_request;
+ expect_update_mirror_image_state(mock_image_state_update_request, 0);
expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
MockImageCopyRequest mock_image_copy_request;
expect_image_copy(mock_image_copy_request, 0, 1, 0, {},
expect_create_non_primary_request(mock_create_non_primary_request,
false, "remote mirror uuid", 1,
{{1, CEPH_NOSNAP}}, 11, 0);
+ MockImageStateUpdateRequest mock_image_state_update_request;
+ expect_update_mirror_image_state(mock_image_state_update_request, 0);
MockApplyImageStateRequest mock_apply_state_request;
expect_apply_image_state(mock_apply_state_request, 0);
expect_mirror_image_snapshot_set_copy_progress(