]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/image/test_mock_RemoveRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / test / librbd / image / test_mock_RemoveRequest.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 "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/MockContextWQ.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "test/librados_test_stub/MockTestMemRadosClient.h"
10 #include "librbd/ImageState.h"
11 #include "librbd/internal.h"
12 #include "librbd/image/TypeTraits.h"
13 #include "librbd/image/DetachChildRequest.h"
14 #include "librbd/image/PreRemoveRequest.h"
15 #include "librbd/image/RemoveRequest.h"
16 #include "librbd/journal/RemoveRequest.h"
17 #include "librbd/journal/TypeTraits.h"
18 #include "librbd/mirror/DisableRequest.h"
19 #include "librbd/operation/TrimRequest.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include <arpa/inet.h>
23 #include <list>
24 #include <boost/scope_exit.hpp>
25
26 namespace librbd {
27 namespace {
28
29 struct MockTestImageCtx : public MockImageCtx {
30 static MockTestImageCtx* s_instance;
31 static MockTestImageCtx* create(const std::string &image_name,
32 const std::string &image_id,
33 const char *snap, librados::IoCtx& p,
34 bool read_only) {
35 ceph_assert(s_instance != nullptr);
36 return s_instance;
37 }
38
39 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
40 s_instance = this;
41 }
42 };
43
44 MockTestImageCtx* MockTestImageCtx::s_instance = nullptr;
45
46 } // anonymous namespace
47
48 template<>
49 struct Journal<MockTestImageCtx> {
50 static void get_work_queue(CephContext*, MockContextWQ**) {
51 }
52 };
53
54 namespace image {
55
56 template <>
57 struct TypeTraits<MockTestImageCtx> {
58 typedef librbd::MockContextWQ ContextWQ;
59 };
60
61 template <>
62 class DetachChildRequest<MockTestImageCtx> {
63 public:
64 static DetachChildRequest *s_instance;
65 static DetachChildRequest *create(MockTestImageCtx &image_ctx,
66 Context *on_finish) {
67 ceph_assert(s_instance != nullptr);
68 s_instance->on_finish = on_finish;
69 return s_instance;
70 }
71
72 Context *on_finish = nullptr;
73
74 DetachChildRequest() {
75 s_instance = this;
76 }
77
78 MOCK_METHOD0(send, void());
79 };
80
81 DetachChildRequest<MockTestImageCtx> *DetachChildRequest<MockTestImageCtx>::s_instance;
82
83 template <>
84 class PreRemoveRequest<MockTestImageCtx> {
85 public:
86 static PreRemoveRequest *s_instance;
87 static PreRemoveRequest *create(MockTestImageCtx* image_ctx, bool force,
88 Context* on_finish) {
89 ceph_assert(s_instance != nullptr);
90 s_instance->on_finish = on_finish;
91 return s_instance;
92 }
93
94 Context *on_finish = nullptr;
95
96 PreRemoveRequest() {
97 s_instance = this;
98 }
99
100 MOCK_METHOD0(send, void());
101 };
102
103 PreRemoveRequest<MockTestImageCtx> *PreRemoveRequest<MockTestImageCtx>::s_instance = nullptr;
104
105 } // namespace image
106
107 namespace journal {
108
109 template <>
110 struct TypeTraits<MockTestImageCtx> {
111 typedef librbd::MockContextWQ ContextWQ;
112 };
113
114 } // namespace journal
115
116 namespace operation {
117
118 template <>
119 class TrimRequest<MockTestImageCtx> {
120 public:
121 static TrimRequest *s_instance;
122 static TrimRequest *create(MockTestImageCtx &image_ctx, Context *on_finish,
123 uint64_t original_size, uint64_t new_size,
124 ProgressContext &prog_ctx) {
125 ceph_assert(s_instance != nullptr);
126 s_instance->on_finish = on_finish;
127 return s_instance;
128 }
129
130 Context *on_finish = nullptr;
131
132 TrimRequest() {
133 s_instance = this;
134 }
135
136 MOCK_METHOD0(send, void());
137 };
138
139 TrimRequest<MockTestImageCtx> *TrimRequest<MockTestImageCtx>::s_instance;
140
141 } // namespace operation
142
143 namespace journal {
144
145 template <>
146 class RemoveRequest<MockTestImageCtx> {
147 private:
148 typedef ::librbd::image::TypeTraits<MockTestImageCtx> TypeTraits;
149 typedef typename TypeTraits::ContextWQ ContextWQ;
150 public:
151 static RemoveRequest *s_instance;
152 static RemoveRequest *create(IoCtx &ioctx, const std::string &imageid,
153 const std::string &client_id,
154 ContextWQ *op_work_queue, Context *on_finish) {
155 ceph_assert(s_instance != nullptr);
156 s_instance->on_finish = on_finish;
157 return s_instance;
158 }
159
160 Context *on_finish = nullptr;
161
162 RemoveRequest() {
163 s_instance = this;
164 }
165
166 MOCK_METHOD0(send, void());
167 };
168
169 RemoveRequest<MockTestImageCtx> *RemoveRequest<MockTestImageCtx>::s_instance = nullptr;
170
171 } // namespace journal
172
173 namespace mirror {
174
175 template<>
176 class DisableRequest<MockTestImageCtx> {
177 public:
178 static DisableRequest *s_instance;
179 Context *on_finish = nullptr;
180
181 static DisableRequest *create(MockTestImageCtx *image_ctx, bool force,
182 bool remove, Context *on_finish) {
183 ceph_assert(s_instance != nullptr);
184 s_instance->on_finish = on_finish;
185 return s_instance;
186 }
187
188 DisableRequest() {
189 s_instance = this;
190 }
191
192 MOCK_METHOD0(send, void());
193 };
194
195 DisableRequest<MockTestImageCtx> *DisableRequest<MockTestImageCtx>::s_instance;
196
197 } // namespace mirror
198 } // namespace librbd
199
200 // template definitions
201 #include "librbd/image/RemoveRequest.cc"
202
203 namespace librbd {
204 namespace image {
205
206 using ::testing::_;
207 using ::testing::DoAll;
208 using ::testing::DoDefault;
209 using ::testing::Invoke;
210 using ::testing::InSequence;
211 using ::testing::Return;
212 using ::testing::WithArg;
213 using ::testing::SetArgPointee;
214 using ::testing::StrEq;
215
216 class TestMockImageRemoveRequest : public TestMockFixture {
217 public:
218 typedef ::librbd::image::TypeTraits<MockTestImageCtx> TypeTraits;
219 typedef typename TypeTraits::ContextWQ ContextWQ;
220 typedef RemoveRequest<MockTestImageCtx> MockRemoveRequest;
221 typedef PreRemoveRequest<MockTestImageCtx> MockPreRemoveRequest;
222 typedef DetachChildRequest<MockTestImageCtx> MockDetachChildRequest;
223 typedef librbd::operation::TrimRequest<MockTestImageCtx> MockTrimRequest;
224 typedef librbd::journal::RemoveRequest<MockTestImageCtx> MockJournalRemoveRequest;
225 typedef librbd::mirror::DisableRequest<MockTestImageCtx> MockMirrorDisableRequest;
226
227 librbd::ImageCtx *m_test_imctx = NULL;
228 MockTestImageCtx *m_mock_imctx = NULL;
229
230 void SetUp() override {
231 TestMockFixture::SetUp();
232
233 ASSERT_EQ(0, open_image(m_image_name, &m_test_imctx));
234 m_mock_imctx = new MockTestImageCtx(*m_test_imctx);
235 librbd::MockTestImageCtx::s_instance = m_mock_imctx;
236 }
237 void TearDown() override {
238 librbd::MockTestImageCtx::s_instance = NULL;
239 delete m_mock_imctx;
240 TestMockFixture::TearDown();
241 }
242
243 void expect_state_open(MockTestImageCtx &mock_image_ctx, int r) {
244 EXPECT_CALL(*mock_image_ctx.state, open(_, _))
245 .WillOnce(Invoke([r](bool open_parent, Context *on_ready) {
246 on_ready->complete(r);
247 }));
248 }
249
250 void expect_state_close(MockTestImageCtx &mock_image_ctx) {
251 EXPECT_CALL(*mock_image_ctx.state, close(_))
252 .WillOnce(Invoke([](Context *on_ready) {
253 on_ready->complete(0);
254 }));
255 }
256
257 void expect_wq_queue(ContextWQ &wq, int r) {
258 EXPECT_CALL(wq, queue(_, r))
259 .WillRepeatedly(Invoke([](Context *on_ready, int r) {
260 on_ready->complete(r);
261 }));
262 }
263
264 void expect_pre_remove_image(MockTestImageCtx &mock_image_ctx,
265 MockPreRemoveRequest& mock_request, int r) {
266 EXPECT_CALL(mock_request, send())
267 .WillOnce(FinishRequest(&mock_request, r, &mock_image_ctx));
268 }
269
270 void expect_trim(MockTestImageCtx &mock_image_ctx,
271 MockTrimRequest &mock_trim_request, int r) {
272 EXPECT_CALL(mock_trim_request, send())
273 .WillOnce(FinishRequest(&mock_trim_request, r, &mock_image_ctx));
274 }
275
276 void expect_journal_remove(MockTestImageCtx &mock_image_ctx,
277 MockJournalRemoveRequest &mock_journal_remove_request, int r) {
278 EXPECT_CALL(mock_journal_remove_request, send())
279 .WillOnce(FinishRequest(&mock_journal_remove_request, r, &mock_image_ctx));
280 }
281
282 void expect_mirror_disable(MockTestImageCtx &mock_image_ctx,
283 MockMirrorDisableRequest &mock_mirror_disable_request, int r) {
284 EXPECT_CALL(mock_mirror_disable_request, send())
285 .WillOnce(FinishRequest(&mock_mirror_disable_request, r, &mock_image_ctx));
286 }
287
288 void expect_remove_mirror_image(librados::IoCtx &ioctx, int r) {
289 EXPECT_CALL(get_mock_io_ctx(ioctx),
290 exec(StrEq("rbd_mirroring"), _, StrEq("rbd"),
291 StrEq("mirror_image_remove"), _, _, _, _))
292 .WillOnce(Return(r));
293 }
294
295 void expect_dir_remove_image(librados::IoCtx &ioctx, int r) {
296 EXPECT_CALL(get_mock_io_ctx(ioctx),
297 exec(RBD_DIRECTORY, _, StrEq("rbd"), StrEq("dir_remove_image"),
298 _, _, _, _))
299 .WillOnce(Return(r));
300 }
301
302 void expect_detach_child(MockTestImageCtx &mock_image_ctx,
303 MockDetachChildRequest& mock_request, int r) {
304 EXPECT_CALL(mock_request, send())
305 .WillOnce(FinishRequest(&mock_request, r, &mock_image_ctx));
306 }
307 };
308
309 TEST_F(TestMockImageRemoveRequest, SuccessV1) {
310 REQUIRE_FORMAT_V1();
311 expect_op_work_queue(*m_mock_imctx);
312
313 InSequence seq;
314 expect_state_open(*m_mock_imctx, 0);
315
316 MockPreRemoveRequest mock_pre_remove_request;
317 expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0);
318
319 MockTrimRequest mock_trim_request;
320 expect_trim(*m_mock_imctx, mock_trim_request, 0);
321
322 expect_state_close(*m_mock_imctx);
323
324 ContextWQ op_work_queue;
325 expect_wq_queue(op_work_queue, 0);
326
327 C_SaferCond ctx;
328 librbd::NoOpProgressContext no_op;
329 MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "",
330 true, false, no_op, &op_work_queue, &ctx);
331 req->send();
332
333 ASSERT_EQ(0, ctx.wait());
334 }
335
336 TEST_F(TestMockImageRemoveRequest, OpenFailV1) {
337 REQUIRE_FORMAT_V1();
338
339 InSequence seq;
340 expect_state_open(*m_mock_imctx, -ENOENT);
341
342 ContextWQ op_work_queue;
343 expect_wq_queue(op_work_queue, 0);
344
345 C_SaferCond ctx;
346 librbd::NoOpProgressContext no_op;
347 MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "",
348 true, false, no_op, &op_work_queue, &ctx);
349 req->send();
350
351 ASSERT_EQ(0, ctx.wait());
352 }
353
354 TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV1) {
355 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
356
357 expect_op_work_queue(*m_mock_imctx);
358
359 m_mock_imctx->parent_md.spec.pool_id = m_ioctx.get_id();
360 m_mock_imctx->parent_md.spec.image_id = "parent id";
361 m_mock_imctx->parent_md.spec.snap_id = 234;
362
363 InSequence seq;
364 expect_state_open(*m_mock_imctx, 0);
365
366 MockPreRemoveRequest mock_pre_remove_request;
367 expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0);
368
369 MockTrimRequest mock_trim_request;
370 expect_trim(*m_mock_imctx, mock_trim_request, 0);
371
372 MockDetachChildRequest mock_detach_child_request;
373 expect_detach_child(*m_mock_imctx, mock_detach_child_request, 0);
374
375 MockMirrorDisableRequest mock_mirror_disable_request;
376 expect_mirror_disable(*m_mock_imctx, mock_mirror_disable_request, 0);
377
378 expect_state_close(*m_mock_imctx);
379
380 MockJournalRemoveRequest mock_journal_remove_request;
381 expect_journal_remove(*m_mock_imctx, mock_journal_remove_request, 0);
382
383 expect_remove_mirror_image(m_ioctx, 0);
384 expect_dir_remove_image(m_ioctx, 0);
385
386 C_SaferCond ctx;
387 librbd::NoOpProgressContext no_op;
388 ContextWQ op_work_queue;
389 MockRemoveRequest *req = MockRemoveRequest::create(
390 m_ioctx, m_image_name, "", true, false, no_op, &op_work_queue, &ctx);
391 req->send();
392
393 ASSERT_EQ(0, ctx.wait());
394 }
395
396 TEST_F(TestMockImageRemoveRequest, SuccessV2CloneV2) {
397 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
398
399 expect_op_work_queue(*m_mock_imctx);
400
401 m_mock_imctx->parent_md.spec.pool_id = m_ioctx.get_id();
402 m_mock_imctx->parent_md.spec.image_id = "parent id";
403 m_mock_imctx->parent_md.spec.snap_id = 234;
404
405 InSequence seq;
406 expect_state_open(*m_mock_imctx, 0);
407
408 MockPreRemoveRequest mock_pre_remove_request;
409 expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0);
410
411 MockTrimRequest mock_trim_request;
412 expect_trim(*m_mock_imctx, mock_trim_request, 0);
413
414 MockDetachChildRequest mock_detach_child_request;
415 expect_detach_child(*m_mock_imctx, mock_detach_child_request, 0);
416
417 MockMirrorDisableRequest mock_mirror_disable_request;
418 expect_mirror_disable(*m_mock_imctx, mock_mirror_disable_request, 0);
419
420 expect_state_close(*m_mock_imctx);
421
422 MockJournalRemoveRequest mock_journal_remove_request;
423 expect_journal_remove(*m_mock_imctx, mock_journal_remove_request, 0);
424
425 expect_remove_mirror_image(m_ioctx, 0);
426 expect_dir_remove_image(m_ioctx, 0);
427
428 C_SaferCond ctx;
429 librbd::NoOpProgressContext no_op;
430 ContextWQ op_work_queue;
431 MockRemoveRequest *req = MockRemoveRequest::create(
432 m_ioctx, m_image_name, "", true, false, no_op, &op_work_queue, &ctx);
433 req->send();
434
435 ASSERT_EQ(0, ctx.wait());
436 }
437
438 TEST_F(TestMockImageRemoveRequest, NotExistsV2) {
439 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
440
441 expect_op_work_queue(*m_mock_imctx);
442
443 m_mock_imctx->parent_md.spec.pool_id = m_ioctx.get_id();
444 m_mock_imctx->parent_md.spec.image_id = "parent id";
445 m_mock_imctx->parent_md.spec.snap_id = 234;
446
447 InSequence seq;
448 expect_state_open(*m_mock_imctx, 0);
449
450 MockPreRemoveRequest mock_pre_remove_request;
451 expect_pre_remove_image(*m_mock_imctx, mock_pre_remove_request, 0);
452
453 MockTrimRequest mock_trim_request;
454 expect_trim(*m_mock_imctx, mock_trim_request, 0);
455
456 MockDetachChildRequest mock_detach_child_request;
457 expect_detach_child(*m_mock_imctx, mock_detach_child_request, 0);
458
459 MockMirrorDisableRequest mock_mirror_disable_request;
460 expect_mirror_disable(*m_mock_imctx, mock_mirror_disable_request, 0);
461
462 expect_state_close(*m_mock_imctx);
463
464 MockJournalRemoveRequest mock_journal_remove_request;
465 expect_journal_remove(*m_mock_imctx, mock_journal_remove_request, 0);
466
467 expect_remove_mirror_image(m_ioctx, 0);
468 expect_dir_remove_image(m_ioctx, -ENOENT);
469
470 C_SaferCond ctx;
471 librbd::NoOpProgressContext no_op;
472 ContextWQ op_work_queue;
473 MockRemoveRequest *req = MockRemoveRequest::create(
474 m_ioctx, m_image_name, "", true, false, no_op, &op_work_queue, &ctx);
475 req->send();
476 ASSERT_EQ(-ENOENT, ctx.wait());
477 }
478
479 } // namespace image
480 } // namespace librbd