#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
#include "librbd/Operations.h"
+#include "librbd/deep_copy/SetHeadRequest.h"
#include "librbd/deep_copy/SnapshotCopyRequest.h"
#include "librbd/deep_copy/SnapshotCreateRequest.h"
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
namespace deep_copy {
+template <>
+class SetHeadRequest<librbd::MockTestImageCtx> {
+public:
+ static SetHeadRequest* s_instance;
+ Context *on_finish;
+
+ static SetHeadRequest* create(librbd::MockTestImageCtx *image_ctx,
+ uint64_t size,
+ const librbd::ParentSpec &parent_spec,
+ uint64_t parent_overlap, Context *on_finish) {
+ assert(s_instance != nullptr);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ SetHeadRequest() {
+ s_instance = this;
+ }
+
+ MOCK_METHOD0(send, void());
+};
+
template <>
struct SnapshotCreateRequest<librbd::MockTestImageCtx> {
static SnapshotCreateRequest* s_instance;
MOCK_METHOD0(send, void());
};
+SetHeadRequest<librbd::MockTestImageCtx>* SetHeadRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
SnapshotCreateRequest<librbd::MockTestImageCtx>* SnapshotCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
} // namespace deep_copy
class TestMockDeepCopySnapshotCopyRequest : public TestMockFixture {
public:
+ typedef SetHeadRequest<librbd::MockTestImageCtx> MockSetHeadRequest;
typedef SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
typedef SnapshotCreateRequest<librbd::MockTestImageCtx> MockSnapshotCreateRequest;
Return(r)));
}
+ void expect_set_head(MockSetHeadRequest &mock_set_head_request, int r) {
+ EXPECT_CALL(mock_set_head_request, send())
+ .WillOnce(Invoke([this, &mock_set_head_request, r]() {
+ mock_set_head_request.on_finish->complete(r);
+ }));
+ }
+
static void inject_snap(librbd::MockTestImageCtx &mock_image_ctx,
uint64_t snap_id, const std::string &snap_name) {
mock_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(),
MockSnapshotCopyRequest *create_request(
librbd::MockTestImageCtx &mock_src_image_ctx,
- librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish) {
+ librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish,
+ librados::snap_t snap_id_end = CEPH_NOSNAP) {
return new MockSnapshotCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx,
- CEPH_NOSNAP, m_work_queue, &m_snap_seqs,
+ snap_id_end, m_work_queue, &m_snap_seqs,
on_finish);
}
TEST_F(TestMockDeepCopySnapshotCopyRequest, Empty) {
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+ MockSetHeadRequest mock_set_head_request;
librbd::MockExclusiveLock mock_exclusive_lock;
prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
expect_test_features(mock_dst_image_ctx);
InSequence seq;
+ expect_set_head(mock_set_head_request, 0);
C_SaferCond ctx;
MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
MockSnapshotCreateRequest mock_snapshot_create_request;
+ MockSetHeadRequest mock_set_head_request;
librbd::MockExclusiveLock mock_exclusive_lock;
prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap2", 14, 0);
expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
expect_snap_is_protected(mock_src_image_ctx, src_snap_id2, false, 0);
+ expect_set_head(mock_set_head_request, 0);
C_SaferCond ctx;
MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
MockSnapshotCreateRequest mock_snapshot_create_request;
+ MockSetHeadRequest mock_set_head_request;
librbd::MockExclusiveLock mock_exclusive_lock;
prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
expect_start_op(mock_exclusive_lock);
expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1", 12, 0);
expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
+ expect_set_head(mock_set_head_request, 0);
C_SaferCond ctx;
MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+ MockSetHeadRequest mock_set_head_request;
librbd::MockExclusiveLock mock_exclusive_lock;
prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
+ expect_set_head(mock_set_head_request, 0);
C_SaferCond ctx;
MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
MockSnapshotCreateRequest mock_snapshot_create_request;
+ MockSetHeadRequest mock_set_head_request;
librbd::MockExclusiveLock mock_exclusive_lock;
prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1",
12, 0);
expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
+ expect_set_head(mock_set_head_request, 0);
C_SaferCond ctx;
MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
MockSnapshotCreateRequest mock_snapshot_create_request;
+ MockSetHeadRequest mock_set_head_request;
librbd::MockExclusiveLock mock_exclusive_lock;
prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
expect_snap_is_protected(mock_dst_image_ctx, 12, false, 0);
expect_start_op(mock_exclusive_lock);
expect_snap_protect(mock_dst_image_ctx, "snap1", 0);
+ expect_set_head(mock_set_head_request, 0);
C_SaferCond ctx;
MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+ MockSetHeadRequest mock_set_head_request;
librbd::MockExclusiveLock mock_exclusive_lock;
prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
expect_snap_is_protected(mock_dst_image_ctx, dst_snap_id1, false, 0);
expect_start_op(mock_exclusive_lock);
expect_snap_protect(mock_dst_image_ctx, "snap1", 0);
+ expect_set_head(mock_set_head_request, 0);
C_SaferCond ctx;
MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
ASSERT_EQ(-ECANCELED, ctx.wait());
}
+TEST_F(TestMockDeepCopySnapshotCopyRequest, SetHeadError) {
+ librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
+ librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+ MockSetHeadRequest mock_set_head_request;
+
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
+
+ expect_test_features(mock_dst_image_ctx);
+
+ InSequence seq;
+ expect_set_head(mock_set_head_request, -EINVAL);
+
+ C_SaferCond ctx;
+ MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
+ mock_dst_image_ctx, &ctx);
+ request->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockDeepCopySnapshotCopyRequest, NoSetHead) {
+ REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+ ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
+
+ uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
+ {cls::rbd::UserSnapshotNamespace(), "snap1"}];
+
+ librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
+ librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+ MockSnapshotCreateRequest mock_snapshot_create_request;
+
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
+
+ expect_test_features(mock_dst_image_ctx);
+
+ InSequence seq;
+ expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
+ expect_start_op(mock_exclusive_lock);
+ expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1",
+ 12, 0);
+ expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
+
+ C_SaferCond ctx;
+ MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
+ mock_dst_image_ctx, &ctx,
+ src_snap_id1);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+
+ validate_snap_seqs({{src_snap_id1, 12}});
+}
+
} // namespace deep_copy
} // namespace librbd
#include "librbd/internal.h"
#include "librbd/deep_copy/ImageCopyRequest.h"
#include "librbd/deep_copy/MetadataCopyRequest.h"
-#include "librbd/deep_copy/SetHeadRequest.h"
#include "librbd/deep_copy/SnapshotCopyRequest.h"
#include "test/librbd/mock/MockImageCtx.h"
#include "test/librbd/mock/MockObjectMap.h"
MOCK_METHOD0(send, void());
};
-template <>
-class SetHeadRequest<librbd::MockTestImageCtx> {
-public:
- static SetHeadRequest* s_instance;
- Context *on_finish;
-
- static SetHeadRequest* create(librbd::MockTestImageCtx *image_ctx,
- uint64_t size,
- const librbd::ParentSpec &parent_spec,
- uint64_t parent_overlap, Context *on_finish) {
- assert(s_instance != nullptr);
- s_instance->on_finish = on_finish;
- return s_instance;
- }
-
- SetHeadRequest() {
- s_instance = this;
- }
-
- MOCK_METHOD0(send, void());
-};
-
template <>
class SnapshotCopyRequest<librbd::MockTestImageCtx> {
public:
ImageCopyRequest<librbd::MockTestImageCtx>* ImageCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
MetadataCopyRequest<librbd::MockTestImageCtx>* MetadataCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-SetHeadRequest<librbd::MockTestImageCtx>* SetHeadRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
SnapshotCopyRequest<librbd::MockTestImageCtx>* SnapshotCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
} // namespace deep_copy
typedef librbd::DeepCopyRequest<librbd::MockTestImageCtx> MockDeepCopyRequest;
typedef librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
typedef librbd::deep_copy::MetadataCopyRequest<librbd::MockTestImageCtx> MockMetadataCopyRequest;
- typedef librbd::deep_copy::SetHeadRequest<librbd::MockTestImageCtx> MockSetHeadRequest;
typedef librbd::deep_copy::SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
librbd::ImageCtx *m_src_image_ctx;
}));
}
- void expect_set_head(MockSetHeadRequest &mock_set_head_request, int r) {
- EXPECT_CALL(mock_set_head_request, send())
- .WillOnce(Invoke([this, &mock_set_head_request, r]() {
- mock_set_head_request.on_finish->complete(r);
- }));
- }
-
void expect_copy_image(MockImageCopyRequest &mock_image_copy_request, int r) {
EXPECT_CALL(mock_image_copy_request, send())
.WillOnce(Invoke([this, &mock_image_copy_request, r]() {
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
MockImageCopyRequest mock_image_copy_request;
MockMetadataCopyRequest mock_metadata_copy_request;
- MockSetHeadRequest mock_set_head_request;
MockSnapshotCopyRequest mock_snapshot_copy_request;
librbd::MockExclusiveLock mock_exclusive_lock;
InSequence seq;
expect_copy_snapshots(mock_snapshot_copy_request, 0);
- expect_set_head(mock_set_head_request, 0);
expect_copy_image(mock_image_copy_request, 0);
if (mock_object_map != nullptr) {
expect_refresh_object_map(mock_dst_image_ctx, mock_object_map);
ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockDeepCopyRequest, ErrorOnSetHead) {
- librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
- librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
- MockSetHeadRequest mock_set_head_request;
- MockSnapshotCopyRequest mock_snapshot_copy_request;
-
- InSequence seq;
- expect_copy_snapshots(mock_snapshot_copy_request, 0);
- expect_set_head(mock_set_head_request, -EINVAL);
-
- C_SaferCond ctx;
- librbd::SnapSeqs snap_seqs;
- librbd::NoOpProgressContext no_op;
- auto request = librbd::DeepCopyRequest<librbd::MockTestImageCtx>::create(
- &mock_src_image_ctx, &mock_dst_image_ctx, 0, CEPH_NOSNAP, boost::none,
- m_work_queue, &snap_seqs, &no_op, &ctx);
- request->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
TEST_F(TestMockDeepCopyRequest, ErrorOnCopyImage) {
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
MockImageCopyRequest mock_image_copy_request;
- MockSetHeadRequest mock_set_head_request;
MockSnapshotCopyRequest mock_snapshot_copy_request;
InSequence seq;
expect_copy_snapshots(mock_snapshot_copy_request, 0);
- expect_set_head(mock_set_head_request, 0);
expect_copy_image(mock_image_copy_request, -EINVAL);
C_SaferCond ctx;
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
MockImageCopyRequest mock_image_copy_request;
MockMetadataCopyRequest mock_metadata_copy_request;
- MockSetHeadRequest mock_set_head_request;
MockSnapshotCopyRequest mock_snapshot_copy_request;
librbd::MockExclusiveLock mock_exclusive_lock;
InSequence seq;
expect_copy_snapshots(mock_snapshot_copy_request, 0);
- expect_set_head(mock_set_head_request, 0);
expect_copy_image(mock_image_copy_request, 0);
if (mock_object_map != nullptr) {
expect_refresh_object_map(mock_dst_image_ctx, mock_object_map);