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