struct UnlinkPeerRequest<MockTestImageCtx> {
uint64_t snap_id = CEPH_NOSNAP;
std::string mirror_peer_uuid;
+ bool allow_remove;
Context* on_finish = nullptr;
static UnlinkPeerRequest* s_instance;
static UnlinkPeerRequest *create(MockTestImageCtx *image_ctx,
uint64_t snap_id,
const std::string &mirror_peer_uuid,
+ bool allow_remove,
Context *on_finish) {
ceph_assert(s_instance != nullptr);
s_instance->snap_id = snap_id;
s_instance->mirror_peer_uuid = mirror_peer_uuid;
+ s_instance->allow_remove = allow_remove;
s_instance->on_finish = on_finish;
return s_instance;
}
if (r != 0) {
return;
}
- snap_create(mock_image_ctx, ns, snap_name);
+ auto mirror_ns =
+ std::get<cls::rbd::MirrorSnapshotNamespace>(ns);
+ mirror_ns.complete = true;
+ snap_create(mock_image_ctx, mirror_ns, snap_name);
}),
WithArg<4>(CompleteContext(
r, mock_image_ctx.image_ctx->op_work_queue))
));
}
+ void expect_refresh_image(MockTestImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(*mock_image_ctx.state, refresh(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
void expect_unlink_peer(MockTestImageCtx &mock_image_ctx,
MockUnlinkPeerRequest &mock_unlink_peer_request,
uint64_t snap_id, const std::string &peer_uuid,
- bool is_linked, int r) {
+ bool is_linked, bool complete, bool allow_remove,
+ int r) {
EXPECT_CALL(mock_unlink_peer_request, send())
.WillOnce(Invoke([&mock_image_ctx, &mock_unlink_peer_request,
- snap_id, peer_uuid, is_linked, r]() {
+ snap_id, peer_uuid, is_linked, complete, allow_remove, r]() {
ASSERT_EQ(mock_unlink_peer_request.mirror_peer_uuid,
peer_uuid);
ASSERT_EQ(mock_unlink_peer_request.snap_id, snap_id);
+ ASSERT_EQ(mock_unlink_peer_request.allow_remove, allow_remove);
if (r == 0) {
auto it = mock_image_ctx.snap_info.find(snap_id);
ASSERT_NE(it, mock_image_ctx.snap_info.end());
auto info =
- boost::get<cls::rbd::MirrorSnapshotNamespace>(
+ std::get_if<cls::rbd::MirrorSnapshotNamespace>(
&it->second.snap_namespace);
ASSERT_NE(nullptr, info);
+ ASSERT_EQ(complete, info->complete);
ASSERT_EQ(is_linked, info->mirror_peer_uuids.erase(
peer_uuid));
if (info->mirror_peer_uuids.empty()) {
{{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
"mirror", "mirror uuid"}}, 0);
expect_create_snapshot(mock_image_ctx, 0);
+ expect_refresh_image(mock_image_ctx, 0);
C_SaferCond ctx;
auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
ASSERT_EQ(-EINVAL, ctx.wait());
}
+TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkIncomplete) {
+ REQUIRE_FORMAT_V2();
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ cls::rbd::MirrorSnapshotNamespace ns{
+ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
+ ns.complete = false;
+ snap_create(mock_image_ctx, ns, "mirror_snap");
+
+ InSequence seq;
+
+ expect_clone_md_ctx(mock_image_ctx);
+ MockUtils mock_utils;
+ expect_can_create_primary_snapshot(mock_utils, false, false, true);
+ expect_get_mirror_peers(mock_image_ctx,
+ {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
+ "mirror", "mirror uuid"}}, 0);
+ expect_create_snapshot(mock_image_ctx, 0);
+ expect_refresh_image(mock_image_ctx, 0);
+ MockUnlinkPeerRequest mock_unlink_peer_request;
+ auto it = mock_image_ctx.snap_info.rbegin();
+ auto snap_id = it->first;
+ expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
+ true, false, true, 0);
+ C_SaferCond ctx;
+ auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
+ 0U, 0U, nullptr, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkPeer) {
REQUIRE_FORMAT_V2();
for (int i = 0; i < 3; i++) {
cls::rbd::MirrorSnapshotNamespace ns{
cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
+ ns.complete = true;
snap_create(mock_image_ctx, ns, "mirror_snap");
}
{{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
"mirror", "mirror uuid"}}, 0);
expect_create_snapshot(mock_image_ctx, 0);
+ expect_refresh_image(mock_image_ctx, 0);
MockUnlinkPeerRequest mock_unlink_peer_request;
auto it = mock_image_ctx.snap_info.rbegin();
auto snap_id = it->first;
expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
- true, 0);
+ true, true, true, 0);
C_SaferCond ctx;
auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
0U, 0U, nullptr, &ctx);
MockTestImageCtx mock_image_ctx(*ictx);
cls::rbd::MirrorSnapshotNamespace ns{
cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP};
+ ns.complete = true;
snap_create(mock_image_ctx, ns, "mirror_snap");
InSequence seq;
{{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
"mirror", "mirror uuid"}}, 0);
expect_create_snapshot(mock_image_ctx, 0);
+ expect_refresh_image(mock_image_ctx, 0);
MockUnlinkPeerRequest mock_unlink_peer_request;
auto it = mock_image_ctx.snap_info.rbegin();
auto snap_id = it->first;
- std::list<std::string> peer_uuids = {"uuid"};
expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
- false, 0);
+ false, true, true, 0);
C_SaferCond ctx;
auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
cls::rbd::MirrorSnapshotNamespace ns{
cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid1", "uuid2"}, "",
CEPH_NOSNAP};
+ ns.complete = true;
snap_create(mock_image_ctx, ns, "mirror_snap");
}
{"uuid2", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
"mirror", "mirror uuid"}}, 0);
expect_create_snapshot(mock_image_ctx, 0);
+ expect_refresh_image(mock_image_ctx, 0);
MockUnlinkPeerRequest mock_unlink_peer_request;
auto it = mock_image_ctx.snap_info.rbegin();
auto snap_id = it->first;
expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid1",
- true, 0);
+ true, true, true, 0);
expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid2",
- true, 0);
+ true, true, true, 0);
C_SaferCond ctx;
auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
0U, 0U, nullptr, &ctx);