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/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>
24 #include <boost/scope_exit.hpp>
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
,
35 ceph_assert(s_instance
!= nullptr);
39 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
44 MockTestImageCtx
* MockTestImageCtx::s_instance
= nullptr;
46 } // anonymous namespace
49 struct Journal
<MockTestImageCtx
> {
50 static void get_work_queue(CephContext
*, MockContextWQ
**) {
57 struct TypeTraits
<MockTestImageCtx
> {
58 typedef librbd::MockContextWQ ContextWQ
;
62 class DetachChildRequest
<MockTestImageCtx
> {
64 static DetachChildRequest
*s_instance
;
65 static DetachChildRequest
*create(MockTestImageCtx
&image_ctx
,
67 ceph_assert(s_instance
!= nullptr);
68 s_instance
->on_finish
= on_finish
;
72 Context
*on_finish
= nullptr;
74 DetachChildRequest() {
78 MOCK_METHOD0(send
, void());
81 DetachChildRequest
<MockTestImageCtx
> *DetachChildRequest
<MockTestImageCtx
>::s_instance
;
84 class PreRemoveRequest
<MockTestImageCtx
> {
86 static PreRemoveRequest
*s_instance
;
87 static PreRemoveRequest
*create(MockTestImageCtx
* image_ctx
, bool force
,
89 ceph_assert(s_instance
!= nullptr);
90 s_instance
->on_finish
= on_finish
;
94 Context
*on_finish
= nullptr;
100 MOCK_METHOD0(send
, void());
103 PreRemoveRequest
<MockTestImageCtx
> *PreRemoveRequest
<MockTestImageCtx
>::s_instance
= nullptr;
110 struct TypeTraits
<MockTestImageCtx
> {
111 typedef librbd::MockContextWQ ContextWQ
;
114 } // namespace journal
116 namespace operation
{
119 class TrimRequest
<MockTestImageCtx
> {
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
;
130 Context
*on_finish
= nullptr;
136 MOCK_METHOD0(send
, void());
139 TrimRequest
<MockTestImageCtx
> *TrimRequest
<MockTestImageCtx
>::s_instance
;
141 } // namespace operation
146 class RemoveRequest
<MockTestImageCtx
> {
148 typedef ::librbd::image::TypeTraits
<MockTestImageCtx
> TypeTraits
;
149 typedef typename
TypeTraits::ContextWQ ContextWQ
;
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
;
160 Context
*on_finish
= nullptr;
166 MOCK_METHOD0(send
, void());
169 RemoveRequest
<MockTestImageCtx
> *RemoveRequest
<MockTestImageCtx
>::s_instance
= nullptr;
171 } // namespace journal
176 class DisableRequest
<MockTestImageCtx
> {
178 static DisableRequest
*s_instance
;
179 Context
*on_finish
= nullptr;
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
;
192 MOCK_METHOD0(send
, void());
195 DisableRequest
<MockTestImageCtx
> *DisableRequest
<MockTestImageCtx
>::s_instance
;
197 } // namespace mirror
198 } // namespace librbd
200 // template definitions
201 #include "librbd/image/RemoveRequest.cc"
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
;
216 class TestMockImageRemoveRequest
: public TestMockFixture
{
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
;
227 librbd::ImageCtx
*m_test_imctx
= NULL
;
228 MockTestImageCtx
*m_mock_imctx
= NULL
;
230 void SetUp() override
{
231 TestMockFixture::SetUp();
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
;
237 void TearDown() override
{
238 librbd::MockTestImageCtx::s_instance
= NULL
;
240 TestMockFixture::TearDown();
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
);
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);
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
);
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
));
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
));
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
));
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
));
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
));
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"),
299 .WillOnce(Return(r
));
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
));
309 TEST_F(TestMockImageRemoveRequest
, SuccessV1
) {
311 expect_op_work_queue(*m_mock_imctx
);
314 expect_state_open(*m_mock_imctx
, 0);
316 MockPreRemoveRequest mock_pre_remove_request
;
317 expect_pre_remove_image(*m_mock_imctx
, mock_pre_remove_request
, 0);
319 MockTrimRequest mock_trim_request
;
320 expect_trim(*m_mock_imctx
, mock_trim_request
, 0);
322 expect_state_close(*m_mock_imctx
);
324 ContextWQ op_work_queue
;
325 expect_wq_queue(op_work_queue
, 0);
328 librbd::NoOpProgressContext no_op
;
329 MockRemoveRequest
*req
= MockRemoveRequest::create(m_ioctx
, m_image_name
, "",
330 true, false, no_op
, &op_work_queue
, &ctx
);
333 ASSERT_EQ(0, ctx
.wait());
336 TEST_F(TestMockImageRemoveRequest
, OpenFailV1
) {
340 expect_state_open(*m_mock_imctx
, -ENOENT
);
342 ContextWQ op_work_queue
;
343 expect_wq_queue(op_work_queue
, 0);
346 librbd::NoOpProgressContext no_op
;
347 MockRemoveRequest
*req
= MockRemoveRequest::create(m_ioctx
, m_image_name
, "",
348 true, false, no_op
, &op_work_queue
, &ctx
);
351 ASSERT_EQ(0, ctx
.wait());
354 TEST_F(TestMockImageRemoveRequest
, SuccessV2CloneV1
) {
355 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
357 expect_op_work_queue(*m_mock_imctx
);
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;
364 expect_state_open(*m_mock_imctx
, 0);
366 MockPreRemoveRequest mock_pre_remove_request
;
367 expect_pre_remove_image(*m_mock_imctx
, mock_pre_remove_request
, 0);
369 MockTrimRequest mock_trim_request
;
370 expect_trim(*m_mock_imctx
, mock_trim_request
, 0);
372 MockDetachChildRequest mock_detach_child_request
;
373 expect_detach_child(*m_mock_imctx
, mock_detach_child_request
, 0);
375 MockMirrorDisableRequest mock_mirror_disable_request
;
376 expect_mirror_disable(*m_mock_imctx
, mock_mirror_disable_request
, 0);
378 expect_state_close(*m_mock_imctx
);
380 MockJournalRemoveRequest mock_journal_remove_request
;
381 expect_journal_remove(*m_mock_imctx
, mock_journal_remove_request
, 0);
383 expect_remove_mirror_image(m_ioctx
, 0);
384 expect_dir_remove_image(m_ioctx
, 0);
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
);
393 ASSERT_EQ(0, ctx
.wait());
396 TEST_F(TestMockImageRemoveRequest
, SuccessV2CloneV2
) {
397 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
399 expect_op_work_queue(*m_mock_imctx
);
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;
406 expect_state_open(*m_mock_imctx
, 0);
408 MockPreRemoveRequest mock_pre_remove_request
;
409 expect_pre_remove_image(*m_mock_imctx
, mock_pre_remove_request
, 0);
411 MockTrimRequest mock_trim_request
;
412 expect_trim(*m_mock_imctx
, mock_trim_request
, 0);
414 MockDetachChildRequest mock_detach_child_request
;
415 expect_detach_child(*m_mock_imctx
, mock_detach_child_request
, 0);
417 MockMirrorDisableRequest mock_mirror_disable_request
;
418 expect_mirror_disable(*m_mock_imctx
, mock_mirror_disable_request
, 0);
420 expect_state_close(*m_mock_imctx
);
422 MockJournalRemoveRequest mock_journal_remove_request
;
423 expect_journal_remove(*m_mock_imctx
, mock_journal_remove_request
, 0);
425 expect_remove_mirror_image(m_ioctx
, 0);
426 expect_dir_remove_image(m_ioctx
, 0);
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
);
435 ASSERT_EQ(0, ctx
.wait());
438 TEST_F(TestMockImageRemoveRequest
, NotExistsV2
) {
439 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
441 expect_op_work_queue(*m_mock_imctx
);
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;
448 expect_state_open(*m_mock_imctx
, 0);
450 MockPreRemoveRequest mock_pre_remove_request
;
451 expect_pre_remove_image(*m_mock_imctx
, mock_pre_remove_request
, 0);
453 MockTrimRequest mock_trim_request
;
454 expect_trim(*m_mock_imctx
, mock_trim_request
, 0);
456 MockDetachChildRequest mock_detach_child_request
;
457 expect_detach_child(*m_mock_imctx
, mock_detach_child_request
, 0);
459 MockMirrorDisableRequest mock_mirror_disable_request
;
460 expect_mirror_disable(*m_mock_imctx
, mock_mirror_disable_request
, 0);
462 expect_state_close(*m_mock_imctx
);
464 MockJournalRemoveRequest mock_journal_remove_request
;
465 expect_journal_remove(*m_mock_imctx
, mock_journal_remove_request
, 0);
467 expect_remove_mirror_image(m_ioctx
, 0);
468 expect_dir_remove_image(m_ioctx
, -ENOENT
);
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
);
476 ASSERT_EQ(-ENOENT
, ctx
.wait());
480 } // namespace librbd