using ::testing::DoAll;
using ::testing::DoDefault;
using ::testing::InSequence;
+using ::testing::Invoke;
using ::testing::Return;
using ::testing::WithArg;
using ::testing::StrEq;
}
}
- void expect_get_mutable_metadata(MockRefreshImageCtx &mock_image_ctx, int r) {
+ void expect_get_mutable_metadata(MockRefreshImageCtx &mock_image_ctx,
+ uint64_t features, int r) {
auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_size"), _, _, _));
if (r < 0) {
expect.WillOnce(Return(r));
} else {
+ uint64_t incompatible = (
+ mock_image_ctx.read_only ? features & RBD_FEATURES_INCOMPATIBLE :
+ features & RBD_FEATURES_RW_INCOMPATIBLE);
+
expect.WillOnce(DoDefault());
EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_features"), _, _, _))
- .WillOnce(DoDefault());
+ .WillOnce(WithArg<5>(Invoke([features, incompatible](bufferlist* out_bl) {
+ encode(features, *out_bl);
+ encode(incompatible, *out_bl);
+ return 0;
+ })));
EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapcontext"), _, _, _))
.WillOnce(DoDefault());
}
}
+ void expect_get_op_features(MockRefreshImageCtx &mock_image_ctx,
+ uint64_t op_features, int r) {
+ EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
+ StrEq("op_features_get"), _, _, _))
+ .WillOnce(WithArg<5>(Invoke([op_features, r](bufferlist* out_bl) {
+ encode(op_features, *out_bl);
+ return r;
+ })));
+ }
+
void expect_get_group(MockRefreshImageCtx &mock_image_ctx, int r) {
auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
expect_test_features(mock_image_ctx);
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
expect_test_features(mock_image_ctx);
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
expect_test_features(mock_image_ctx);
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
expect_test_features(mock_image_ctx);
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
expect_test_features(mock_image_ctx);
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
ASSERT_EQ(0, ctx.wait());
}
+TEST_F(TestMockImageRefreshRequest, SuccessOpFeatures) {
+ REQUIRE_FORMAT_V2();
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockRefreshImageCtx mock_image_ctx(*ictx);
+ MockRefreshParentRequest mock_refresh_parent_request;
+ MockExclusiveLock mock_exclusive_lock;
+ expect_op_work_queue(mock_image_ctx);
+ expect_test_features(mock_image_ctx);
+
+ mock_image_ctx.features |= RBD_FEATURE_OPERATIONS;
+
+ InSequence seq;
+ expect_get_mutable_metadata(mock_image_ctx, mock_image_ctx.features, 0);
+ expect_get_metadata(mock_image_ctx, 0);
+ expect_apply_metadata(mock_image_ctx, 0);
+ expect_get_flags(mock_image_ctx, 0);
+ expect_get_op_features(mock_image_ctx, 4096, 0);
+ expect_get_group(mock_image_ctx, 0);
+ expect_refresh_parent_is_required(mock_refresh_parent_request, false);
+ if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+ expect_init_exclusive_lock(mock_image_ctx, mock_exclusive_lock, 0);
+ }
+
+ C_SaferCond ctx;
+ MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx);
+ req->send();
+
+ ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(4096, mock_image_ctx.op_features);
+ ASSERT_TRUE(mock_image_ctx.operations_disabled);
+}
+
TEST_F(TestMockImageRefreshRequest, DisableExclusiveLock) {
REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
expect_op_work_queue(mock_image_ctx);
expect_test_features(mock_image_ctx);
// verify that exclusive lock is properly handled when object map
// and journaling were never enabled (or active)
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
expect_op_work_queue(mock_image_ctx);
expect_test_features(mock_image_ctx);
// verify that exclusive lock is properly handled when object map
// and journaling were never enabled (or active)
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
MockRefreshImageCtx mock_image_ctx(*ictx);
MockRefreshParentRequest mock_refresh_parent_request;
expect_is_exclusive_lock_owner(mock_exclusive_lock, true);
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
MockRefreshImageCtx mock_image_ctx(*ictx);
MockRefreshParentRequest mock_refresh_parent_request;
// journal should be immediately opened if exclusive lock owned
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
MockRefreshImageCtx mock_image_ctx(*ictx);
MockRefreshParentRequest mock_refresh_parent_request;
// do not open the journal if exclusive lock is not owned
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
expect_op_work_queue(mock_image_ctx);
expect_test_features(mock_image_ctx);
// verify journal is closed if feature disabled
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
MockRefreshImageCtx mock_image_ctx(*ictx);
MockRefreshParentRequest mock_refresh_parent_request;
// object map should be immediately opened if exclusive lock owned
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
MockRefreshImageCtx mock_image_ctx(*ictx);
MockRefreshParentRequest mock_refresh_parent_request;
// do not open the object map if exclusive lock is not owned
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
expect_op_work_queue(mock_image_ctx);
expect_test_features(mock_image_ctx);
// verify object map is closed if feature disabled
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
false));
}
+ ASSERT_EQ(0, ictx->state->refresh());
+
MockRefreshImageCtx mock_image_ctx(*ictx);
MockRefreshParentRequest mock_refresh_parent_request;
// object map should be immediately opened if exclusive lock owned
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_flags(mock_image_ctx, 0);
expect_test_features(mock_image_ctx);
InSequence seq;
- expect_get_mutable_metadata(mock_image_ctx, 0);
+ expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, -EINVAL);
expect_get_flags(mock_image_ctx, 0);