]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/mirror/snapshot/test_mock_PromoteRequest.cc
import 15.2.2 octopus source
[ceph.git] / ceph / src / test / librbd / mirror / snapshot / test_mock_PromoteRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "include/stringify.h"
5 #include "test/librbd/test_mock_fixture.h"
6 #include "test/librbd/test_support.h"
7 #include "test/librbd/mock/MockImageCtx.h"
8 #include "test/librbd/mock/MockOperations.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "test/librados_test_stub/MockTestMemRadosClient.h"
11 #include "librbd/image/ListWatchersRequest.h"
12 #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h"
13 #include "librbd/mirror/snapshot/CreatePrimaryRequest.h"
14 #include "librbd/mirror/snapshot/PromoteRequest.h"
15 #include "librbd/mirror/snapshot/Utils.h"
16
17 namespace librbd {
18
19 namespace {
20
21 struct MockTestImageCtx : public MockImageCtx {
22 explicit MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
23 }
24 };
25
26 } // anonymous namespace
27
28 namespace image {
29
30 template <>
31 struct ListWatchersRequest<MockTestImageCtx> {
32 std::list<obj_watch_t> *watchers;
33 Context* on_finish = nullptr;
34 static ListWatchersRequest* s_instance;
35 static ListWatchersRequest *create(MockTestImageCtx &image_ctx, int flags,
36 std::list<obj_watch_t> *watchers,
37 Context *on_finish) {
38 ceph_assert(s_instance != nullptr);
39 s_instance->watchers = watchers;
40 s_instance->on_finish = on_finish;
41 return s_instance;
42 }
43
44 MOCK_METHOD0(send, void());
45
46 ListWatchersRequest() {
47 s_instance = this;
48 }
49 };
50
51 ListWatchersRequest<MockTestImageCtx>* ListWatchersRequest<MockTestImageCtx>::s_instance = nullptr;
52
53 } // namespace image
54
55 namespace mirror {
56 namespace snapshot {
57 namespace util {
58
59 namespace {
60
61 struct Mock {
62 static Mock* s_instance;
63
64 Mock() {
65 s_instance = this;
66 }
67
68 MOCK_METHOD5(can_create_primary_snapshot,
69 bool(librbd::MockTestImageCtx *, bool, bool, bool*, uint64_t *));
70 };
71
72 Mock *Mock::s_instance = nullptr;
73
74 } // anonymous namespace
75
76 template<> bool can_create_primary_snapshot(librbd::MockTestImageCtx *image_ctx,
77 bool demoted, bool force,
78 bool* requires_orphan,
79 uint64_t *rollback_snap_id) {
80 return Mock::s_instance->can_create_primary_snapshot(image_ctx, demoted,
81 force, requires_orphan,
82 rollback_snap_id);
83 }
84
85 } // namespace util
86
87 template <>
88 struct CreateNonPrimaryRequest<MockTestImageCtx> {
89 std::string primary_mirror_uuid;
90 uint64_t primary_snap_id = CEPH_NOSNAP;
91 Context* on_finish = nullptr;
92 static CreateNonPrimaryRequest* s_instance;
93 static CreateNonPrimaryRequest *create(MockTestImageCtx *image_ctx,
94 bool demoted,
95 const std::string &primary_mirror_uuid,
96 uint64_t primary_snap_id,
97 SnapSeqs snap_seqs,
98 const ImageState &image_state,
99 uint64_t *snap_id,
100 Context *on_finish) {
101 ceph_assert(s_instance != nullptr);
102 s_instance->primary_mirror_uuid = primary_mirror_uuid;
103 s_instance->primary_snap_id = primary_snap_id;
104 s_instance->on_finish = on_finish;
105 return s_instance;
106 }
107
108 MOCK_METHOD0(send, void());
109
110 CreateNonPrimaryRequest() {
111 s_instance = this;
112 }
113 };
114
115 CreateNonPrimaryRequest<MockTestImageCtx>* CreateNonPrimaryRequest<MockTestImageCtx>::s_instance = nullptr;
116
117 template <>
118 struct CreatePrimaryRequest<MockTestImageCtx> {
119 bool demoted = false;
120 bool force = false;
121 Context* on_finish = nullptr;
122 static CreatePrimaryRequest* s_instance;
123 static CreatePrimaryRequest *create(MockTestImageCtx *image_ctx,
124 const std::string& global_image_id,
125 uint64_t clean_since_snap_id,
126 uint32_t flags, uint64_t *snap_id,
127 Context *on_finish) {
128 ceph_assert(s_instance != nullptr);
129 s_instance->demoted = ((flags & CREATE_PRIMARY_FLAG_DEMOTED) != 0);
130 s_instance->force = ((flags & CREATE_PRIMARY_FLAG_FORCE) != 0);
131 s_instance->on_finish = on_finish;
132 return s_instance;
133 }
134
135 MOCK_METHOD0(send, void());
136
137 CreatePrimaryRequest() {
138 s_instance = this;
139 }
140 };
141
142 CreatePrimaryRequest<MockTestImageCtx>* CreatePrimaryRequest<MockTestImageCtx>::s_instance = nullptr;
143
144 } // namespace snapshot
145 } // namespace mirror
146 } // namespace librbd
147
148 // template definitions
149 #include "librbd/mirror/snapshot/PromoteRequest.cc"
150 template class librbd::mirror::snapshot::PromoteRequest<librbd::MockTestImageCtx>;
151
152 namespace librbd {
153 namespace mirror {
154 namespace snapshot {
155
156 using ::testing::_;
157 using ::testing::DoAll;
158 using ::testing::InSequence;
159 using ::testing::Invoke;
160 using ::testing::Return;
161 using ::testing::StrEq;
162 using ::testing::WithArg;
163 using ::testing::WithArgs;
164
165 class TestMockMirrorSnapshotPromoteRequest : public TestMockFixture {
166 public:
167 typedef librbd::image::ListWatchersRequest<MockTestImageCtx> MockListWatchersRequest;
168 typedef PromoteRequest<MockTestImageCtx> MockPromoteRequest;
169 typedef CreateNonPrimaryRequest<MockTestImageCtx> MockCreateNonPrimaryRequest;
170 typedef CreatePrimaryRequest<MockTestImageCtx> MockCreatePrimaryRequest;
171 typedef util::Mock MockUtils;
172
173 void expect_can_create_primary_snapshot(MockUtils &mock_utils, bool force,
174 bool requires_orphan,
175 uint64_t rollback_snap_id,
176 bool result) {
177 EXPECT_CALL(mock_utils,
178 can_create_primary_snapshot(_, false, force, _, _))
179 .WillOnce(DoAll(
180 WithArgs<3,4 >(Invoke(
181 [requires_orphan, rollback_snap_id]
182 (bool* orphan, uint64_t *snap_id) {
183 *orphan = requires_orphan;
184 *snap_id = rollback_snap_id;
185 })),
186 Return(result)));
187 }
188
189 void expect_create_orphan_snapshot(
190 MockTestImageCtx &mock_image_ctx,
191 MockCreateNonPrimaryRequest &mock_create_non_primary_request, int r) {
192 EXPECT_CALL(mock_create_non_primary_request, send())
193 .WillOnce(
194 Invoke([&mock_image_ctx, &mock_create_non_primary_request, r]() {
195 mock_image_ctx.image_ctx->op_work_queue->queue(
196 mock_create_non_primary_request.on_finish, r);
197 }));
198 }
199
200 void expect_list_watchers(
201 MockTestImageCtx &mock_image_ctx,
202 MockListWatchersRequest &mock_list_watchers_request,
203 const std::list<obj_watch_t> &watchers, int r) {
204 EXPECT_CALL(mock_list_watchers_request, send())
205 .WillOnce(
206 Invoke([&mock_image_ctx, &mock_list_watchers_request, watchers, r]() {
207 *mock_list_watchers_request.watchers = watchers;
208 mock_image_ctx.image_ctx->op_work_queue->queue(
209 mock_list_watchers_request.on_finish, r);
210 }));
211 }
212
213 void expect_acquire_lock(MockTestImageCtx &mock_image_ctx, int r) {
214 if (mock_image_ctx.exclusive_lock == nullptr) {
215 return;
216 }
217 EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
218 .WillOnce(Return(false));
219 EXPECT_CALL(*mock_image_ctx.exclusive_lock, block_requests(_));
220 EXPECT_CALL(*mock_image_ctx.exclusive_lock, acquire_lock(_))
221 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
222 if (r == 0) {
223 EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
224 .WillOnce(Return(true));
225 }
226 }
227
228 void expect_get_snap_info(MockTestImageCtx &mock_image_ctx,
229 uint64_t snap_id, const SnapInfo* snap_info) {
230 EXPECT_CALL(mock_image_ctx, get_snap_info(snap_id))
231 .WillOnce(Return(snap_info));
232 }
233
234 void expect_rollback(MockTestImageCtx &mock_image_ctx, uint64_t snap_id,
235 const SnapInfo* snap_info, int r) {
236 expect_get_snap_info(mock_image_ctx, snap_id, snap_info);
237 EXPECT_CALL(*mock_image_ctx.operations,
238 execute_snap_rollback(snap_info->snap_namespace,
239 snap_info->name, _, _))
240 .WillOnce(WithArg<3>(CompleteContext(
241 r, mock_image_ctx.image_ctx->op_work_queue)));
242 }
243
244 void expect_create_promote_snapshot(
245 MockTestImageCtx &mock_image_ctx,
246 MockCreatePrimaryRequest &mock_create_primary_request, int r) {
247 EXPECT_CALL(mock_create_primary_request, send())
248 .WillOnce(
249 Invoke([&mock_image_ctx, &mock_create_primary_request, r]() {
250 mock_image_ctx.image_ctx->op_work_queue->queue(
251 mock_create_primary_request.on_finish, r);
252 }));
253 }
254
255 void expect_release_lock(MockTestImageCtx &mock_image_ctx, int r) {
256 if (mock_image_ctx.exclusive_lock == nullptr) {
257 return;
258 }
259 EXPECT_CALL(*mock_image_ctx.exclusive_lock, unblock_requests());
260 EXPECT_CALL(*mock_image_ctx.exclusive_lock, release_lock(_))
261 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
262 }
263 };
264
265 TEST_F(TestMockMirrorSnapshotPromoteRequest, Success) {
266 REQUIRE_FORMAT_V2();
267
268 librbd::ImageCtx *ictx;
269 ASSERT_EQ(0, open_image(m_image_name, &ictx));
270
271 MockTestImageCtx mock_image_ctx(*ictx);
272
273 InSequence seq;
274
275 MockUtils mock_utils;
276 expect_can_create_primary_snapshot(mock_utils, true, false, CEPH_NOSNAP,
277 true);
278 MockCreatePrimaryRequest mock_create_primary_request;
279 expect_create_promote_snapshot(mock_image_ctx, mock_create_primary_request,
280 0);
281 C_SaferCond ctx;
282 auto req = new MockPromoteRequest(&mock_image_ctx, "gid", &ctx);
283 req->send();
284 ASSERT_EQ(0, ctx.wait());
285 }
286
287 TEST_F(TestMockMirrorSnapshotPromoteRequest, SuccessForce) {
288 REQUIRE_FORMAT_V2();
289
290 librbd::ImageCtx *ictx;
291 ASSERT_EQ(0, open_image(m_image_name, &ictx));
292
293 MockTestImageCtx mock_image_ctx(*ictx);
294 expect_op_work_queue(mock_image_ctx);
295
296 MockExclusiveLock mock_exclusive_lock;
297 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
298 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
299 }
300
301 InSequence seq;
302
303 MockUtils mock_utils;
304 expect_can_create_primary_snapshot(mock_utils, true, true, CEPH_NOSNAP, true);
305 MockCreateNonPrimaryRequest mock_create_non_primary_request;
306 expect_create_orphan_snapshot(mock_image_ctx, mock_create_non_primary_request,
307 0);
308 MockListWatchersRequest mock_list_watchers_request;
309 expect_list_watchers(mock_image_ctx, mock_list_watchers_request, {}, 0);
310 expect_acquire_lock(mock_image_ctx, 0);
311
312 SnapInfo snap_info = {"snap", cls::rbd::MirrorSnapshotNamespace{}, 0,
313 {}, 0, 0, {}};
314 MockCreatePrimaryRequest mock_create_primary_request;
315 expect_create_promote_snapshot(mock_image_ctx, mock_create_primary_request,
316 0);
317 expect_release_lock(mock_image_ctx, 0);
318
319 C_SaferCond ctx;
320 auto req = new MockPromoteRequest(&mock_image_ctx, "gid", &ctx);
321 req->send();
322 ASSERT_EQ(0, ctx.wait());
323 }
324
325 TEST_F(TestMockMirrorSnapshotPromoteRequest, SuccessRollback) {
326 REQUIRE_FORMAT_V2();
327
328 librbd::ImageCtx *ictx;
329 ASSERT_EQ(0, open_image(m_image_name, &ictx));
330
331 MockTestImageCtx mock_image_ctx(*ictx);
332 expect_op_work_queue(mock_image_ctx);
333
334 MockExclusiveLock mock_exclusive_lock;
335 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
336 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
337 }
338
339 InSequence seq;
340
341 MockUtils mock_utils;
342 expect_can_create_primary_snapshot(mock_utils, true, false, 123, true);
343 MockCreateNonPrimaryRequest mock_create_non_primary_request;
344 expect_create_orphan_snapshot(mock_image_ctx, mock_create_non_primary_request,
345 0);
346 MockListWatchersRequest mock_list_watchers_request;
347 expect_list_watchers(mock_image_ctx, mock_list_watchers_request, {}, 0);
348 expect_acquire_lock(mock_image_ctx, 0);
349
350 SnapInfo snap_info = {"snap", cls::rbd::MirrorSnapshotNamespace{}, 0,
351 {}, 0, 0, {}};
352 expect_rollback(mock_image_ctx, 123, &snap_info, 0);
353 MockCreatePrimaryRequest mock_create_primary_request;
354 expect_create_promote_snapshot(mock_image_ctx, mock_create_primary_request,
355 0);
356 expect_release_lock(mock_image_ctx, 0);
357
358 C_SaferCond ctx;
359 auto req = new MockPromoteRequest(&mock_image_ctx, "gid", &ctx);
360 req->send();
361 ASSERT_EQ(0, ctx.wait());
362 }
363
364 TEST_F(TestMockMirrorSnapshotPromoteRequest, ErrorCannotRollback) {
365 REQUIRE_FORMAT_V2();
366
367 librbd::ImageCtx *ictx;
368 ASSERT_EQ(0, open_image(m_image_name, &ictx));
369
370 MockTestImageCtx mock_image_ctx(*ictx);
371 expect_op_work_queue(mock_image_ctx);
372
373 InSequence seq;
374
375 MockUtils mock_utils;
376 expect_can_create_primary_snapshot(mock_utils, true, false, CEPH_NOSNAP,
377 false);
378
379 C_SaferCond ctx;
380 auto req = new MockPromoteRequest(&mock_image_ctx, "gid", &ctx);
381 req->send();
382 ASSERT_EQ(-EINVAL, ctx.wait());
383 }
384
385 } // namespace snapshot
386 } // namespace mirror
387 } // namespace librbd
388