]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / test / librbd / operation / test_mock_DisableFeaturesRequest.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "test/librbd/test_mock_fixture.h"
5#include "test/librbd/test_support.h"
6#include "test/librbd/mock/MockImageCtx.h"
7#include "test/librbd/mock/MockJournalPolicy.h"
8#include "cls/rbd/cls_rbd_client.h"
9#include "librbd/internal.h"
f67539c2 10#include "librbd/Journal.h"
7c673cae
FG
11#include "librbd/image/SetFlagsRequest.h"
12#include "librbd/io/AioCompletion.h"
13#include "librbd/mirror/DisableRequest.h"
14#include "librbd/journal/RemoveRequest.h"
15#include "librbd/journal/StandardPolicy.h"
16#include "librbd/journal/Types.h"
f67539c2 17#include "librbd/journal/TypeTraits.h"
7c673cae
FG
18#include "librbd/object_map/RemoveRequest.h"
19#include "librbd/operation/DisableFeaturesRequest.h"
20#include "gmock/gmock.h"
21#include "gtest/gtest.h"
22
23namespace librbd {
24
25namespace {
26
27struct MockOperationImageCtx : public MockImageCtx {
28 MockOperationImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
29 }
30};
31
32} // anonymous namespace
33
f67539c2
TL
34template<>
35struct Journal<MockOperationImageCtx> {
36 static void get_work_queue(CephContext*, MockContextWQ**) {
37 }
38};
39
7c673cae
FG
40namespace image {
41
42template<>
43class SetFlagsRequest<MockOperationImageCtx> {
44public:
45 static SetFlagsRequest *s_instance;
46 Context *on_finish = nullptr;
47
48 static SetFlagsRequest *create(MockOperationImageCtx *image_ctx, uint64_t flags,
49 uint64_t mask, Context *on_finish) {
11fdf7f2 50 ceph_assert(s_instance != nullptr);
7c673cae
FG
51 s_instance->on_finish = on_finish;
52 return s_instance;
53 }
54
55 SetFlagsRequest() {
56 s_instance = this;
57 }
58
59 MOCK_METHOD0(send, void());
60};
61
62SetFlagsRequest<MockOperationImageCtx> *SetFlagsRequest<MockOperationImageCtx>::s_instance;
63
64} // namespace image
65
66namespace journal {
67
68template<>
69class RemoveRequest<MockOperationImageCtx> {
70public:
71 static RemoveRequest *s_instance;
72 Context *on_finish = nullptr;
73
74 static RemoveRequest *create(IoCtx &ioctx, const std::string &imageid,
75 const std::string &client_id,
76 MockContextWQ *op_work_queue,
77 Context *on_finish) {
11fdf7f2 78 ceph_assert(s_instance != nullptr);
7c673cae
FG
79 s_instance->on_finish = on_finish;
80 return s_instance;
81 }
82
83 RemoveRequest() {
84 s_instance = this;
85 }
86
87 MOCK_METHOD0(send, void());
88};
89
90RemoveRequest<MockOperationImageCtx> *RemoveRequest<MockOperationImageCtx>::s_instance;
91
92template<>
93class StandardPolicy<MockOperationImageCtx> : public MockJournalPolicy {
94public:
95 StandardPolicy(MockOperationImageCtx* image_ctx) {
96 }
97};
98
f67539c2
TL
99template <>
100struct TypeTraits<MockOperationImageCtx> {
101 typedef librbd::MockContextWQ ContextWQ;
102};
103
7c673cae
FG
104} // namespace journal
105
106namespace mirror {
107
108template<>
109class DisableRequest<MockOperationImageCtx> {
110public:
111 static DisableRequest *s_instance;
112 Context *on_finish = nullptr;
113
114 static DisableRequest *create(MockOperationImageCtx *image_ctx, bool force,
115 bool remove, Context *on_finish) {
11fdf7f2 116 ceph_assert(s_instance != nullptr);
7c673cae
FG
117 s_instance->on_finish = on_finish;
118 return s_instance;
119 }
120
121 DisableRequest() {
122 s_instance = this;
123 }
124
125 MOCK_METHOD0(send, void());
126};
127
128DisableRequest<MockOperationImageCtx> *DisableRequest<MockOperationImageCtx>::s_instance;
129
130} // namespace mirror
131
132namespace object_map {
133
134template<>
135class RemoveRequest<MockOperationImageCtx> {
136public:
137 static RemoveRequest *s_instance;
138 Context *on_finish = nullptr;
139
140 static RemoveRequest *create(MockOperationImageCtx *image_ctx, Context *on_finish) {
11fdf7f2 141 ceph_assert(s_instance != nullptr);
7c673cae
FG
142 s_instance->on_finish = on_finish;
143 return s_instance;
144 }
145
146 RemoveRequest() {
147 s_instance = this;
148 }
149
150 MOCK_METHOD0(send, void());
151};
152
153RemoveRequest<MockOperationImageCtx> *RemoveRequest<MockOperationImageCtx>::s_instance;
154
155} // namespace object_map
156
157template <>
158struct AsyncRequest<MockOperationImageCtx> : public AsyncRequest<MockImageCtx> {
159 MockOperationImageCtx &m_image_ctx;
160
161 AsyncRequest(MockOperationImageCtx &image_ctx, Context *on_finish)
162 : AsyncRequest<MockImageCtx>(image_ctx, on_finish), m_image_ctx(image_ctx) {
163 }
164};
165
166} // namespace librbd
167
168// template definitions
169#include "librbd/AsyncRequest.cc"
170#include "librbd/AsyncObjectThrottle.cc"
171#include "librbd/operation/Request.cc"
172#include "librbd/operation/DisableFeaturesRequest.cc"
173
174namespace librbd {
175namespace operation {
176
177using ::testing::Invoke;
178using ::testing::Return;
179using ::testing::WithArg;
180using ::testing::_;
181
182class TestMockOperationDisableFeaturesRequest : public TestMockFixture {
183public:
184 typedef librbd::image::SetFlagsRequest<MockOperationImageCtx> MockSetFlagsRequest;
185 typedef librbd::journal::RemoveRequest<MockOperationImageCtx> MockRemoveJournalRequest;
186 typedef librbd::mirror::DisableRequest<MockOperationImageCtx> MockDisableMirrorRequest;
187 typedef librbd::object_map::RemoveRequest<MockOperationImageCtx> MockRemoveObjectMapRequest;
188 typedef DisableFeaturesRequest<MockOperationImageCtx> MockDisableFeaturesRequest;
189
9f95a23c 190 class MirrorModeEnabler {
7c673cae 191 public:
9f95a23c
TL
192 MirrorModeEnabler(librados::IoCtx &ioctx, cls::rbd::MirrorMode mirror_mode)
193 : m_ioctx(ioctx), m_mirror_mode(mirror_mode) {
7c673cae 194 EXPECT_EQ(0, librbd::cls_client::mirror_uuid_set(&m_ioctx, "test-uuid"));
9f95a23c 195 EXPECT_EQ(0, librbd::cls_client::mirror_mode_set(&m_ioctx, m_mirror_mode));
7c673cae
FG
196 }
197
9f95a23c 198 ~MirrorModeEnabler() {
7c673cae 199 EXPECT_EQ(0, librbd::cls_client::mirror_mode_set(
9f95a23c 200 &m_ioctx, cls::rbd::MIRROR_MODE_DISABLED));
7c673cae
FG
201 }
202 private:
203 librados::IoCtx &m_ioctx;
9f95a23c 204 cls::rbd::MirrorMode m_mirror_mode;
7c673cae
FG
205 };
206
207 void expect_prepare_lock(MockOperationImageCtx &mock_image_ctx) {
208 EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
209 .WillOnce(Invoke([](Context *on_ready) {
210 on_ready->complete(0);
211 }));
212 expect_op_work_queue(mock_image_ctx);
213 }
214
215 void expect_handle_prepare_lock_complete(MockOperationImageCtx &mock_image_ctx) {
216 EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
217 }
218
219 void expect_block_writes(MockOperationImageCtx &mock_image_ctx) {
f67539c2 220 EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, block_writes(_))
7c673cae
FG
221 .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
222 }
223
224 void expect_unblock_writes(MockOperationImageCtx &mock_image_ctx) {
f67539c2 225 EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, unblock_writes()).Times(1);
7c673cae
FG
226 }
227
228 void expect_verify_lock_ownership(MockOperationImageCtx &mock_image_ctx) {
229 if (mock_image_ctx.exclusive_lock != nullptr) {
230 EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
231 .WillRepeatedly(Return(true));
232 }
233 }
234
235 void expect_block_requests(MockOperationImageCtx &mock_image_ctx) {
236 if (mock_image_ctx.exclusive_lock != nullptr) {
237 EXPECT_CALL(*mock_image_ctx.exclusive_lock, block_requests(0)).Times(1);
238 }
239 }
240
241 void expect_unblock_requests(MockOperationImageCtx &mock_image_ctx) {
242 if (mock_image_ctx.exclusive_lock != nullptr) {
243 EXPECT_CALL(*mock_image_ctx.exclusive_lock, unblock_requests()).Times(1);
244 }
245 }
246
247 void expect_set_flags_request_send(
248 MockOperationImageCtx &mock_image_ctx,
249 MockSetFlagsRequest &mock_set_flags_request, int r) {
250 EXPECT_CALL(mock_set_flags_request, send())
251 .WillOnce(FinishRequest(&mock_set_flags_request, r,
252 &mock_image_ctx));
253 }
254
255 void expect_disable_mirror_request_send(
256 MockOperationImageCtx &mock_image_ctx,
257 MockDisableMirrorRequest &mock_disable_mirror_request, int r) {
258 EXPECT_CALL(mock_disable_mirror_request, send())
259 .WillOnce(FinishRequest(&mock_disable_mirror_request, r,
260 &mock_image_ctx));
261 }
262
263 void expect_close_journal(MockOperationImageCtx &mock_image_ctx, int r) {
264 EXPECT_CALL(*mock_image_ctx.journal, close(_))
265 .WillOnce(Invoke([&mock_image_ctx, r](Context *on_finish) {
266 mock_image_ctx.journal = nullptr;
267 mock_image_ctx.image_ctx->op_work_queue->queue(on_finish, r);
268 }));
269 }
270
271 void expect_remove_journal_request_send(
272 MockOperationImageCtx &mock_image_ctx,
273 MockRemoveJournalRequest &mock_remove_journal_request, int r) {
274 EXPECT_CALL(mock_remove_journal_request, send())
275 .WillOnce(FinishRequest(&mock_remove_journal_request, r,
276 &mock_image_ctx));
277 }
278
279 void expect_remove_object_map_request_send(
280 MockOperationImageCtx &mock_image_ctx,
281 MockRemoveObjectMapRequest &mock_remove_object_map_request, int r) {
282 EXPECT_CALL(mock_remove_object_map_request, send())
283 .WillOnce(FinishRequest(&mock_remove_object_map_request, r,
284 &mock_image_ctx));
285 }
286
287 void expect_notify_update(MockOperationImageCtx &mock_image_ctx) {
288 EXPECT_CALL(mock_image_ctx, notify_update(_))
289 .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
290 }
291
292};
293
294TEST_F(TestMockOperationDisableFeaturesRequest, All) {
295 REQUIRE_FORMAT_V2();
296
297 librbd::ImageCtx *ictx;
298 ASSERT_EQ(0, open_image(m_image_name, &ictx));
299
300 uint64_t features;
301 ASSERT_EQ(0, librbd::get_features(ictx, &features));
302
303 uint64_t features_to_disable = RBD_FEATURES_MUTABLE & features;
304
305 REQUIRE(features_to_disable);
306
307 MockOperationImageCtx mock_image_ctx(*ictx);
308 MockExclusiveLock mock_exclusive_lock;
9f95a23c 309 MockJournal mock_journal;
7c673cae 310 MockObjectMap mock_object_map;
9f95a23c 311 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
7c673cae
FG
312 mock_object_map);
313
314 expect_verify_lock_ownership(mock_image_ctx);
315
316 MockSetFlagsRequest mock_set_flags_request;
317 MockRemoveJournalRequest mock_remove_journal_request;
318 MockDisableMirrorRequest mock_disable_mirror_request;
319 MockRemoveObjectMapRequest mock_remove_object_map_request;
320
321 ::testing::InSequence seq;
322 expect_prepare_lock(mock_image_ctx);
323 expect_block_writes(mock_image_ctx);
324 if (mock_image_ctx.journal != nullptr) {
325 expect_is_journal_replaying(*mock_image_ctx.journal);
326 }
327 expect_block_requests(mock_image_ctx);
328 if (features_to_disable & RBD_FEATURE_JOURNALING) {
329 expect_disable_mirror_request_send(mock_image_ctx,
330 mock_disable_mirror_request, 0);
331 expect_close_journal(mock_image_ctx, 0);
332 expect_remove_journal_request_send(mock_image_ctx,
333 mock_remove_journal_request, 0);
334 }
335 if (features_to_disable & RBD_FEATURE_OBJECT_MAP) {
336 expect_remove_object_map_request_send(mock_image_ctx,
337 mock_remove_object_map_request, 0);
338 }
339 if (features_to_disable & (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF)) {
340 expect_set_flags_request_send(mock_image_ctx,
341 mock_set_flags_request, 0);
342 }
343 expect_notify_update(mock_image_ctx);
344 expect_unblock_requests(mock_image_ctx);
345 expect_unblock_writes(mock_image_ctx);
346 expect_handle_prepare_lock_complete(mock_image_ctx);
347
348 C_SaferCond cond_ctx;
349 MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
350 mock_image_ctx, &cond_ctx, 0, features_to_disable, false);
351 {
9f95a23c 352 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
7c673cae
FG
353 req->send();
354 }
355 ASSERT_EQ(0, cond_ctx.wait());
356}
357
358TEST_F(TestMockOperationDisableFeaturesRequest, ObjectMap) {
359 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
360
361 librbd::ImageCtx *ictx;
362 ASSERT_EQ(0, open_image(m_image_name, &ictx));
363
364 MockOperationImageCtx mock_image_ctx(*ictx);
365 MockExclusiveLock mock_exclusive_lock;
366 MockJournal mock_journal;
367 MockObjectMap mock_object_map;
368 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
369 mock_object_map);
370
371 expect_verify_lock_ownership(mock_image_ctx);
372
373 MockSetFlagsRequest mock_set_flags_request;
374 MockRemoveObjectMapRequest mock_remove_object_map_request;
375
376 ::testing::InSequence seq;
377 expect_prepare_lock(mock_image_ctx);
378 expect_block_writes(mock_image_ctx);
379 if (mock_image_ctx.journal != nullptr) {
380 expect_is_journal_replaying(*mock_image_ctx.journal);
381 }
382 expect_block_requests(mock_image_ctx);
383 expect_append_op_event(mock_image_ctx, true, 0);
384 expect_remove_object_map_request_send(mock_image_ctx,
385 mock_remove_object_map_request, 0);
386 expect_set_flags_request_send(mock_image_ctx,
387 mock_set_flags_request, 0);
388 expect_notify_update(mock_image_ctx);
389 expect_unblock_requests(mock_image_ctx);
390 expect_unblock_writes(mock_image_ctx);
391 expect_handle_prepare_lock_complete(mock_image_ctx);
392 expect_commit_op_event(mock_image_ctx, 0);
393
394 C_SaferCond cond_ctx;
395 MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
396 mock_image_ctx, &cond_ctx, 0,
397 RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF, false);
398 {
9f95a23c 399 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
7c673cae
FG
400 req->send();
401 }
402 ASSERT_EQ(0, cond_ctx.wait());
403}
404
405TEST_F(TestMockOperationDisableFeaturesRequest, ObjectMapError) {
406 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
407
408 librbd::ImageCtx *ictx;
409 ASSERT_EQ(0, open_image(m_image_name, &ictx));
410
411 MockOperationImageCtx mock_image_ctx(*ictx);
412 MockExclusiveLock mock_exclusive_lock;
413 MockJournal mock_journal;
414 MockObjectMap mock_object_map;
415 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
416 mock_object_map);
417
418 expect_verify_lock_ownership(mock_image_ctx);
419
420 MockSetFlagsRequest mock_set_flags_request;
421 MockRemoveObjectMapRequest mock_remove_object_map_request;
422
423 ::testing::InSequence seq;
424 expect_prepare_lock(mock_image_ctx);
425 expect_block_writes(mock_image_ctx);
426 if (mock_image_ctx.journal != nullptr) {
427 expect_is_journal_replaying(*mock_image_ctx.journal);
428 }
429 expect_block_requests(mock_image_ctx);
430 expect_append_op_event(mock_image_ctx, true, 0);
431 expect_remove_object_map_request_send(mock_image_ctx,
432 mock_remove_object_map_request, -EINVAL);
433 expect_unblock_requests(mock_image_ctx);
434 expect_unblock_writes(mock_image_ctx);
435 expect_handle_prepare_lock_complete(mock_image_ctx);
436 expect_commit_op_event(mock_image_ctx, -EINVAL);
437
438 C_SaferCond cond_ctx;
439 MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
440 mock_image_ctx, &cond_ctx, 0,
441 RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF, false);
442 {
9f95a23c 443 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
7c673cae
FG
444 req->send();
445 }
446 ASSERT_EQ(-EINVAL, cond_ctx.wait());
447}
448
449TEST_F(TestMockOperationDisableFeaturesRequest, Mirroring) {
450 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
451
9f95a23c
TL
452 MirrorModeEnabler mirror_mode_enabler(m_ioctx, cls::rbd::MIRROR_MODE_POOL);
453
7c673cae
FG
454 librbd::ImageCtx *ictx;
455 ASSERT_EQ(0, open_image(m_image_name, &ictx));
456
457 MockOperationImageCtx mock_image_ctx(*ictx);
458 MockExclusiveLock mock_exclusive_lock;
9f95a23c 459 MockJournal mock_journal;
7c673cae 460 MockObjectMap mock_object_map;
9f95a23c 461 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
7c673cae
FG
462 mock_object_map);
463
464 expect_verify_lock_ownership(mock_image_ctx);
465
466 MockRemoveJournalRequest mock_remove_journal_request;
467 MockDisableMirrorRequest mock_disable_mirror_request;
468
469 ::testing::InSequence seq;
470 expect_prepare_lock(mock_image_ctx);
471 expect_block_writes(mock_image_ctx);
472 expect_is_journal_replaying(*mock_image_ctx.journal);
473 expect_block_requests(mock_image_ctx);
474 expect_disable_mirror_request_send(mock_image_ctx,
475 mock_disable_mirror_request, 0);
476 expect_close_journal(mock_image_ctx, 0);
477 expect_remove_journal_request_send(mock_image_ctx,
478 mock_remove_journal_request, 0);
479 expect_notify_update(mock_image_ctx);
480 expect_unblock_requests(mock_image_ctx);
481 expect_unblock_writes(mock_image_ctx);
482 expect_handle_prepare_lock_complete(mock_image_ctx);
483
484 C_SaferCond cond_ctx;
485 MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
486 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_JOURNALING, false);
487 {
9f95a23c 488 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
7c673cae
FG
489 req->send();
490 }
491 ASSERT_EQ(0, cond_ctx.wait());
492}
493
494TEST_F(TestMockOperationDisableFeaturesRequest, MirroringError) {
495 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
496
497 librbd::ImageCtx *ictx;
498 ASSERT_EQ(0, open_image(m_image_name, &ictx));
499
500 MockOperationImageCtx mock_image_ctx(*ictx);
501 MockExclusiveLock mock_exclusive_lock;
9f95a23c 502 MockJournal mock_journal;
7c673cae 503 MockObjectMap mock_object_map;
9f95a23c 504 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
7c673cae
FG
505 mock_object_map);
506
507 expect_verify_lock_ownership(mock_image_ctx);
508
509 MockRemoveJournalRequest mock_remove_journal_request;
510 MockDisableMirrorRequest mock_disable_mirror_request;
511
512 ::testing::InSequence seq;
513 expect_prepare_lock(mock_image_ctx);
514 expect_block_writes(mock_image_ctx);
515 expect_is_journal_replaying(*mock_image_ctx.journal);
516 expect_block_requests(mock_image_ctx);
517 expect_disable_mirror_request_send(mock_image_ctx,
518 mock_disable_mirror_request, -EINVAL);
519 expect_close_journal(mock_image_ctx, 0);
520 expect_remove_journal_request_send(mock_image_ctx,
521 mock_remove_journal_request, 0);
522 expect_notify_update(mock_image_ctx);
523 expect_unblock_requests(mock_image_ctx);
524 expect_unblock_writes(mock_image_ctx);
525 expect_handle_prepare_lock_complete(mock_image_ctx);
526
527 C_SaferCond cond_ctx;
528 MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
529 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_JOURNALING, false);
530 {
9f95a23c 531 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
7c673cae
FG
532 req->send();
533 }
534 ASSERT_EQ(0, cond_ctx.wait());
535}
536
537} // namespace operation
538} // namespace librbd