]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / rbd_mirror / image_replayer / test_mock_BootstrapRequest.cc
index cde2df07bdbabfaf4b7ea761ffab79c0e0f05f40..6c7c30a2cfde5f605b3591c7f46cdb099f90cdbd 100644 (file)
@@ -43,7 +43,7 @@ static std::string s_image_id;
 
 template <>
 std::string generate_image_id<MockTestImageCtx>(librados::IoCtx&) {
-  assert(!s_image_id.empty());
+  ceph_assert(!s_image_id.empty());
   return s_image_id;
 }
 
@@ -55,6 +55,18 @@ namespace mirror {
 
 class ProgressContext;
 
+template <>
+struct Threads<librbd::MockTestImageCtx> {
+  Mutex &timer_lock;
+  SafeTimer *timer;
+  ContextWQ *work_queue;
+
+  Threads(Threads<librbd::ImageCtx> *threads)
+    : timer_lock(threads->timer_lock), timer(threads->timer),
+      work_queue(threads->work_queue) {
+  }
+};
+
 template<>
 struct ImageSync<librbd::MockTestImageCtx> {
   static ImageSync* s_instance;
@@ -63,18 +75,18 @@ struct ImageSync<librbd::MockTestImageCtx> {
   static ImageSync* create(
       librbd::MockTestImageCtx *local_image_ctx,
       librbd::MockTestImageCtx *remote_image_ctx,
-      SafeTimer *timer, Mutex *timer_lock, const std::string &mirror_uuid,
-      ::journal::MockJournaler *journaler,
+      SafeTimer *timer, Mutex *timer_lock,
+      const std::string &mirror_uuid, ::journal::MockJournaler *journaler,
       librbd::journal::MirrorPeerClientMeta *client_meta, ContextWQ *work_queue,
       InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
       Context *on_finish, ProgressContext *progress_ctx) {
-    assert(s_instance != nullptr);
+    ceph_assert(s_instance != nullptr);
     s_instance->on_finish = on_finish;
     return s_instance;
   }
 
   ImageSync() {
-    assert(s_instance == nullptr);
+    ceph_assert(s_instance == nullptr);
     s_instance = this;
   }
   ~ImageSync() {
@@ -104,7 +116,7 @@ struct CloseImageRequest<librbd::MockTestImageCtx> {
 
   static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx,
                                    Context *on_finish) {
-    assert(s_instance != nullptr);
+    ceph_assert(s_instance != nullptr);
     s_instance->image_ctx = image_ctx;
     s_instance->on_finish = on_finish;
     s_instance->construct(*image_ctx);
@@ -112,7 +124,7 @@ struct CloseImageRequest<librbd::MockTestImageCtx> {
   }
 
   CloseImageRequest() {
-    assert(s_instance == nullptr);
+    ceph_assert(s_instance == nullptr);
     s_instance = this;
   }
   ~CloseImageRequest() {
@@ -128,22 +140,22 @@ struct CreateImageRequest<librbd::MockTestImageCtx> {
   static CreateImageRequest* s_instance;
   Context *on_finish = nullptr;
 
-  static CreateImageRequest* create(librados::IoCtx &local_io_ctx,
-                                    ContextWQ *work_queue,
+  static CreateImageRequest* create(Threads<librbd::MockTestImageCtx>* threads,
+                                    librados::IoCtx &local_io_ctx,
                                     const std::string &global_image_id,
                                     const std::string &remote_mirror_uuid,
                                     const std::string &local_image_name,
                                    const std::string &local_image_id,
                                     librbd::MockTestImageCtx *remote_image_ctx,
                                     Context *on_finish) {
-    assert(s_instance != nullptr);
+    ceph_assert(s_instance != nullptr);
     s_instance->on_finish = on_finish;
     s_instance->construct(local_image_id);
     return s_instance;
   }
 
   CreateImageRequest() {
-    assert(s_instance == nullptr);
+    ceph_assert(s_instance == nullptr);
     s_instance = this;
   }
   ~CreateImageRequest() {
@@ -162,14 +174,14 @@ struct IsPrimaryRequest<librbd::MockTestImageCtx> {
 
   static IsPrimaryRequest* create(librbd::MockTestImageCtx *image_ctx,
                                   bool *primary, Context *on_finish) {
-    assert(s_instance != nullptr);
+    ceph_assert(s_instance != nullptr);
     s_instance->primary = primary;
     s_instance->on_finish = on_finish;
     return s_instance;
   }
 
   IsPrimaryRequest() {
-    assert(s_instance == nullptr);
+    ceph_assert(s_instance == nullptr);
     s_instance = this;
   }
   ~IsPrimaryRequest() {
@@ -189,7 +201,7 @@ struct OpenImageRequest<librbd::MockTestImageCtx> {
                                   librbd::MockTestImageCtx **image_ctx,
                                   const std::string &image_id,
                                   bool read_only, Context *on_finish) {
-    assert(s_instance != nullptr);
+    ceph_assert(s_instance != nullptr);
     s_instance->image_ctx = image_ctx;
     s_instance->on_finish = on_finish;
     s_instance->construct(io_ctx, image_id);
@@ -197,7 +209,7 @@ struct OpenImageRequest<librbd::MockTestImageCtx> {
   }
 
   OpenImageRequest() {
-    assert(s_instance == nullptr);
+    ceph_assert(s_instance == nullptr);
     s_instance = this;
   }
   ~OpenImageRequest() {
@@ -220,7 +232,7 @@ struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
                                        const std::string &local_image_id,
                                        ContextWQ *work_queue,
                                        Context *on_finish) {
-    assert(s_instance != nullptr);
+    ceph_assert(s_instance != nullptr);
     s_instance->image_ctx = local_image_ctx;
     s_instance->on_finish = on_finish;
     s_instance->construct(local_io_ctx, local_image_id);
@@ -228,7 +240,7 @@ struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
   }
 
   OpenLocalImageRequest() {
-    assert(s_instance == nullptr);
+    ceph_assert(s_instance == nullptr);
     s_instance = this;
   }
   ~OpenLocalImageRequest() {
@@ -277,6 +289,7 @@ MATCHER_P(IsSameIoCtx, io_ctx, "") {
 
 class TestMockImageReplayerBootstrapRequest : public TestMockFixture {
 public:
+  typedef Threads<librbd::MockTestImageCtx> MockThreads;
   typedef BootstrapRequest<librbd::MockTestImageCtx> MockBootstrapRequest;
   typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest;
   typedef CreateImageRequest<librbd::MockTestImageCtx> MockCreateImageRequest;
@@ -329,7 +342,7 @@ public:
                                         const librbd::journal::ClientData &client_data,
                                         int r) {
     bufferlist bl;
-    ::encode(client_data, bl);
+    encode(client_data, bl);
 
     EXPECT_CALL(mock_journaler, register_client(ContentsEqual(bl), _))
       .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
@@ -349,7 +362,7 @@ public:
                                       const librbd::journal::ClientData &client_data,
                                       int r) {
     bufferlist bl;
-    ::encode(client_data, bl);
+    encode(client_data, bl);
 
     EXPECT_CALL(mock_journaler, update_client(ContentsEqual(bl), _))
       .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
@@ -437,11 +450,12 @@ public:
 
   bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
     bufferlist bl;
-    ::encode(tag_data, bl);
+    encode(tag_data, bl);
     return bl;
   }
 
-  MockBootstrapRequest *create_request(MockInstanceWatcher *mock_instance_watcher,
+  MockBootstrapRequest *create_request(MockThreads* mock_threads,
+                                       MockInstanceWatcher *mock_instance_watcher,
                                        ::journal::MockJournaler &mock_journaler,
                                        const std::string &local_image_id,
                                        const std::string &remote_image_id,
@@ -451,16 +465,13 @@ public:
                                        cls::journal::ClientState *client_state,
                                        librbd::journal::MirrorPeerClientMeta *mirror_peer_client_meta,
                                        Context *on_finish) {
-    return new MockBootstrapRequest(m_local_io_ctx,
+    return new MockBootstrapRequest(mock_threads, m_local_io_ctx,
                                     m_remote_io_ctx,
                                     mock_instance_watcher,
                                     &m_local_test_image_ctx,
                                     local_image_id,
                                     remote_image_id,
                                     global_image_id,
-                                    m_threads->work_queue,
-                                    m_threads->timer,
-                                    &m_threads->timer_lock,
                                     local_mirror_uuid,
                                     remote_mirror_uuid,
                                     &mock_journaler,
@@ -483,7 +494,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -512,13 +523,15 @@ TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
-    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
-    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+    &mock_threads, &mock_instance_watcher, mock_journaler,
+    mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+    "local mirror uuid", "remote mirror uuid", &client_state,
+    &mirror_peer_client_meta, &ctx);
   request->send();
   ASSERT_EQ(-EREMOTEIO, ctx.wait());
 }
@@ -567,15 +580,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteNotTagOwner) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
     mock_local_image_ctx.id};
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
-    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
-    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+    &mock_threads, &mock_instance_watcher, mock_journaler,
+    mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+    "local mirror uuid", "remote mirror uuid", &client_state,
+    &mirror_peer_client_meta, &ctx);
   request->send();
   ASSERT_EQ(-EREMOTEIO, ctx.wait());
 }
@@ -589,7 +604,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -638,15 +653,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
     mock_local_image_ctx.id};
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
-    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
-    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+    &mock_threads, &mock_instance_watcher, mock_journaler,
+    mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+    "local mirror uuid", "remote mirror uuid", &client_state,
+    &mirror_peer_client_meta, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
@@ -660,7 +677,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -719,15 +736,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
     mock_local_image_ctx.id};
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
-    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
-    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+    &mock_threads, &mock_instance_watcher, mock_journaler,
+    mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+    "local mirror uuid", "remote mirror uuid", &client_state,
+    &mirror_peer_client_meta, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
@@ -741,7 +760,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -788,15 +807,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
     mock_local_image_ctx.id};
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
-    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
-    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+    &mock_threads, &mock_instance_watcher, mock_journaler,
+    mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+    "local mirror uuid", "remote mirror uuid", &client_state,
+    &mirror_peer_client_meta, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
@@ -810,7 +831,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -856,15 +877,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
     mock_local_image_ctx.id};
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
-    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
-    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+    &mock_threads, &mock_instance_watcher, mock_journaler,
+    mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+    "local mirror uuid", "remote mirror uuid", &client_state,
+    &mirror_peer_client_meta, &ctx);
   request->send();
   ASSERT_EQ(-EEXIST, ctx.wait());
   ASSERT_EQ(NULL, m_local_test_image_ctx);
@@ -879,7 +902,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -913,15 +936,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
     mock_local_image_ctx.id};
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
-    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
-    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+    &mock_threads, &mock_instance_watcher, mock_journaler,
+    mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+    "local mirror uuid", "remote mirror uuid", &client_state,
+    &mirror_peer_client_meta, &ctx);
   m_do_resync = false;
   request->send();
   ASSERT_EQ(0, ctx.wait());
@@ -937,7 +962,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -964,7 +989,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
   client_data.client_meta = mirror_peer_client_meta;
   client.data.clear();
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   expect_journaler_update_client(mock_journaler, client_data, 0);
 
   // create the local image
@@ -988,12 +1013,13 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   mirror_peer_client_meta.image_id = "";
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, "",
+    &mock_threads, &mock_instance_watcher, mock_journaler, "",
     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
     "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
   request->send();
@@ -1009,7 +1035,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
   cls::journal::Client client;
   librbd::journal::ClientData client_data{
     librbd::journal::ImageClientMeta{123}};
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   ::journal::MockJournaler mock_journaler;
   expect_journaler_get_client(mock_journaler,
                               librbd::Journal<>::IMAGE_CLIENT_ID,
@@ -1051,7 +1077,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
   client_data.client_meta = mirror_peer_client_meta;
   client.data.clear();
-  ::encode(client_data, client.data);
+  encode(client_data, client.data);
   expect_journaler_update_client(mock_journaler, client_data, 0);
 
   // create the missing local image
@@ -1074,12 +1100,90 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
   MockInstanceWatcher mock_instance_watcher;
   cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
   mirror_peer_client_meta.image_id = "missing image id";
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   MockBootstrapRequest *request = create_request(
-    &mock_instance_watcher, mock_journaler, "missing image id",
+    &mock_threads, &mock_instance_watcher, mock_journaler, "missing image id",
+    mock_remote_image_ctx.id, "global image id", "local mirror uuid",
+    "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+  request->send();
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageReplayerBootstrapRequest, LocalImageIdCollision) {
+  create_local_image();
+
+  InSequence seq;
+
+  // lookup remote image tag class
+  cls::journal::Client client;
+  librbd::journal::ClientData client_data{
+    librbd::journal::ImageClientMeta{123}};
+  encode(client_data, client.data);
+  ::journal::MockJournaler mock_journaler;
+  expect_journaler_get_client(mock_journaler,
+                              librbd::Journal<>::IMAGE_CLIENT_ID,
+                              client, 0);
+
+  // open the remote image
+  librbd::MockJournal mock_journal;
+  librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  MockOpenImageRequest mock_open_image_request;
+  expect_open_image(mock_open_image_request, m_remote_io_ctx,
+                    mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
+
+  // test if remote image is primary
+  MockIsPrimaryRequest mock_is_primary_request;
+  expect_is_primary(mock_is_primary_request, true, 0);
+
+  // update client state back to syncing
+  librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+  mock_local_image_ctx.journal = &mock_journal;
+
+  librbd::util::s_image_id = mock_local_image_ctx.id;
+  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
+  client_data.client_meta = mirror_peer_client_meta;
+  client.data.clear();
+  encode(client_data, client.data);
+  expect_journaler_update_client(mock_journaler, client_data, 0);
+
+  // create the local image
+  MockCreateImageRequest mock_create_image_request;
+  expect_create_image(mock_create_image_request, mock_local_image_ctx.id,
+                      -EBADF);
+
+  expect_journaler_update_client(mock_journaler, client_data, 0);
+  expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
+
+  // open the local image
+  MockOpenLocalImageRequest mock_open_local_image_request;
+  expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
+                          mock_local_image_ctx.id, &mock_local_image_ctx, 0);
+  expect_is_resync_requested(mock_journal, false, 0);
+
+  expect_journal_get_tag_tid(mock_journal, 345);
+  expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
+
+  // sync the remote image to the local image
+  MockImageSync mock_image_sync;
+  expect_image_sync(mock_image_sync, 0);
+
+  MockCloseImageRequest mock_close_image_request;
+  expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
+
+  C_SaferCond ctx;
+  MockThreads mock_threads(m_threads);
+  MockInstanceWatcher mock_instance_watcher;
+  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
+  mirror_peer_client_meta.image_id = "";
+  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  MockBootstrapRequest *request = create_request(
+    &mock_threads, &mock_instance_watcher, mock_journaler, "",
     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
     "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
   request->send();