1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
7 #include "common/bit_vector.hpp"
8 #include "cls/rbd/cls_rbd_types.h"
9 #include "librbd/internal.h"
10 #include "librbd/ObjectMap.h"
11 #include "librbd/object_map/SnapshotCreateRequest.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
16 namespace object_map
{
19 using ::testing::DoDefault
;
20 using ::testing::Return
;
21 using ::testing::StrEq
;
23 class TestMockObjectMapSnapshotCreateRequest
: public TestMockFixture
{
25 void inject_snap_info(librbd::ImageCtx
*ictx
, uint64_t snap_id
) {
26 std::unique_lock image_locker
{ictx
->image_lock
};
27 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "snap name", snap_id
,
28 ictx
->size
, ictx
->parent_md
,
29 RBD_PROTECTION_STATUS_UNPROTECTED
, 0, utime_t());
32 void expect_read_map(librbd::ImageCtx
*ictx
, int r
) {
34 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
35 read(ObjectMap
<>::object_map_name(ictx
->id
, CEPH_NOSNAP
),
36 0, 0, _
)).WillOnce(Return(r
));
38 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
39 read(ObjectMap
<>::object_map_name(ictx
->id
, CEPH_NOSNAP
),
40 0, 0, _
)).WillOnce(DoDefault());
44 void expect_write_map(librbd::ImageCtx
*ictx
, uint64_t snap_id
, int r
) {
46 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
48 ObjectMap
<>::object_map_name(ictx
->id
, snap_id
), _
, _
))
51 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
53 ObjectMap
<>::object_map_name(ictx
->id
, snap_id
), _
, _
))
54 .WillOnce(DoDefault());
58 void expect_add_snapshot(librbd::ImageCtx
*ictx
, int r
) {
59 std::string
oid(ObjectMap
<>::object_map_name(ictx
->id
, CEPH_NOSNAP
));
61 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
62 exec(oid
, _
, StrEq("lock"), StrEq("assert_locked"), _
, _
, _
))
65 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
66 exec(oid
, _
, StrEq("lock"), StrEq("assert_locked"), _
, _
, _
))
67 .WillOnce(DoDefault());
68 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
69 exec(oid
, _
, StrEq("rbd"), StrEq("object_map_snap_add"), _
, _
, _
))
70 .WillOnce(DoDefault());
74 void expect_invalidate(librbd::ImageCtx
*ictx
) {
75 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
76 exec(ictx
->header_oid
, _
, StrEq("rbd"), StrEq("set_flags"), _
, _
, _
))
77 .WillOnce(DoDefault());
81 TEST_F(TestMockObjectMapSnapshotCreateRequest
, Success
) {
82 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
84 librbd::ImageCtx
*ictx
;
85 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
86 ASSERT_EQ(0, acquire_exclusive_lock(*ictx
));
88 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
89 ceph::BitVector
<2> object_map
;
92 inject_snap_info(ictx
, snap_id
);
93 expect_read_map(ictx
, 0);
94 expect_write_map(ictx
, snap_id
, 0);
95 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
96 expect_add_snapshot(ictx
, 0);
100 AsyncRequest
<> *request
= new SnapshotCreateRequest(
101 *ictx
, &object_map_lock
, &object_map
, snap_id
, &cond_ctx
);
103 std::shared_lock image_locker
{ictx
->image_lock
};
106 ASSERT_EQ(0, cond_ctx
.wait());
108 expect_unlock_exclusive_lock(*ictx
);
111 TEST_F(TestMockObjectMapSnapshotCreateRequest
, ReadMapError
) {
112 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
114 librbd::ImageCtx
*ictx
;
115 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
116 ASSERT_EQ(0, acquire_exclusive_lock(*ictx
));
118 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
119 ceph::BitVector
<2> object_map
;
121 uint64_t snap_id
= 1;
122 inject_snap_info(ictx
, snap_id
);
123 expect_read_map(ictx
, -ENOENT
);
124 expect_invalidate(ictx
);
126 C_SaferCond cond_ctx
;
127 AsyncRequest
<> *request
= new SnapshotCreateRequest(
128 *ictx
, &object_map_lock
, &object_map
, snap_id
, &cond_ctx
);
130 std::shared_lock image_locker
{ictx
->image_lock
};
133 ASSERT_EQ(0, cond_ctx
.wait());
135 expect_unlock_exclusive_lock(*ictx
);
138 TEST_F(TestMockObjectMapSnapshotCreateRequest
, WriteMapError
) {
139 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
141 librbd::ImageCtx
*ictx
;
142 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
143 ASSERT_EQ(0, acquire_exclusive_lock(*ictx
));
145 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
146 ceph::BitVector
<2> object_map
;
148 uint64_t snap_id
= 1;
149 inject_snap_info(ictx
, snap_id
);
150 expect_read_map(ictx
, 0);
151 expect_write_map(ictx
, snap_id
, -EINVAL
);
152 expect_invalidate(ictx
);
154 C_SaferCond cond_ctx
;
155 AsyncRequest
<> *request
= new SnapshotCreateRequest(
156 *ictx
, &object_map_lock
, &object_map
, snap_id
, &cond_ctx
);
158 std::shared_lock image_locker
{ictx
->image_lock
};
161 ASSERT_EQ(0, cond_ctx
.wait());
163 expect_unlock_exclusive_lock(*ictx
);
166 TEST_F(TestMockObjectMapSnapshotCreateRequest
, AddSnapshotError
) {
167 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
169 librbd::ImageCtx
*ictx
;
170 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
171 ASSERT_EQ(0, acquire_exclusive_lock(*ictx
));
173 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
174 ceph::BitVector
<2> object_map
;
176 uint64_t snap_id
= 1;
177 inject_snap_info(ictx
, snap_id
);
178 expect_read_map(ictx
, 0);
179 expect_write_map(ictx
, snap_id
, 0);
180 expect_add_snapshot(ictx
, -EINVAL
);
181 expect_invalidate(ictx
);
183 C_SaferCond cond_ctx
;
184 AsyncRequest
<> *request
= new SnapshotCreateRequest(
185 *ictx
, &object_map_lock
, &object_map
, snap_id
, &cond_ctx
);
187 std::shared_lock image_locker
{ictx
->image_lock
};
190 ASSERT_EQ(0, cond_ctx
.wait());
192 expect_unlock_exclusive_lock(*ictx
);
195 TEST_F(TestMockObjectMapSnapshotCreateRequest
, FlagCleanObjects
) {
196 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
198 librbd::ImageCtx
*ictx
;
199 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
200 ASSERT_EQ(0, acquire_exclusive_lock(*ictx
));
202 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
203 ceph::BitVector
<2> object_map
;
204 object_map
.resize(1024);
205 for (uint64_t i
= 0; i
< object_map
.size(); ++i
) {
206 object_map
[i
] = i
% 2 == 0 ? OBJECT_EXISTS
: OBJECT_NONEXISTENT
;
209 uint64_t snap_id
= 1;
210 inject_snap_info(ictx
, snap_id
);
212 C_SaferCond cond_ctx
;
213 AsyncRequest
<> *request
= new SnapshotCreateRequest(
214 *ictx
, &object_map_lock
, &object_map
, snap_id
, &cond_ctx
);
216 std::shared_lock image_locker
{ictx
->image_lock
};
219 ASSERT_EQ(0, cond_ctx
.wait());
221 for (uint64_t i
= 0; i
< object_map
.size(); ++i
) {
222 ASSERT_EQ(i
% 2 == 0 ? OBJECT_EXISTS_CLEAN
: OBJECT_NONEXISTENT
,
227 } // namespace object_map
228 } // namespace librbd