]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/image_deleter/test_mock_TrashRemoveRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / test / rbd_mirror / image_deleter / test_mock_TrashRemoveRequest.cc
CommitLineData
eafe8130
TL
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/rbd_mirror/test_mock_fixture.h"
5#include "cls/rbd/cls_rbd_types.h"
6#include "librbd/ImageCtx.h"
7#include "librbd/TrashWatcher.h"
8#include "librbd/Utils.h"
9#include "librbd/trash/RemoveRequest.h"
10#include "tools/rbd_mirror/Threads.h"
11#include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
12#include "tools/rbd_mirror/image_deleter/TrashRemoveRequest.h"
13#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
14#include "test/librbd/mock/MockImageCtx.h"
15
16namespace librbd {
17
18namespace {
19
20struct MockTestImageCtx : public librbd::MockImageCtx {
21 MockTestImageCtx(librbd::ImageCtx &image_ctx)
22 : librbd::MockImageCtx(image_ctx) {
23 }
24};
25
26} // anonymous namespace
27
28template<>
29struct TrashWatcher<MockTestImageCtx> {
30 static TrashWatcher* s_instance;
31 static void notify_image_removed(librados::IoCtx&,
32 const std::string& image_id, Context *ctx) {
33 ceph_assert(s_instance != nullptr);
34 s_instance->notify_image_removed(image_id, ctx);
35 }
36
37 MOCK_METHOD2(notify_image_removed, void(const std::string&, Context*));
38
39 TrashWatcher() {
40 s_instance = this;
41 }
42};
43
44TrashWatcher<MockTestImageCtx>* TrashWatcher<MockTestImageCtx>::s_instance = nullptr;
45
46namespace trash {
47
48template <>
49struct RemoveRequest<librbd::MockTestImageCtx> {
50 static RemoveRequest *s_instance;
51 Context *on_finish = nullptr;
52
53 static RemoveRequest *create(librados::IoCtx &io_ctx,
54 const std::string &image_id,
55 ContextWQ *work_queue,
56 bool force,
57 librbd::ProgressContext &progress_ctx,
58 Context *on_finish) {
59 ceph_assert(s_instance != nullptr);
60 EXPECT_TRUE(force);
61 s_instance->construct(image_id);
62 s_instance->on_finish = on_finish;
63 return s_instance;
64 }
65
66 MOCK_METHOD1(construct, void(const std::string&));
67 MOCK_METHOD0(send, void());
68
69 RemoveRequest() {
70 s_instance = this;
71 }
72};
73
74RemoveRequest<librbd::MockTestImageCtx>* RemoveRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
75
76} // namespace trash
77} // namespace librbd
78
79namespace rbd {
80namespace mirror {
81namespace image_deleter {
82
83template <>
84struct SnapshotPurgeRequest<librbd::MockTestImageCtx> {
85 static SnapshotPurgeRequest *s_instance;
86 Context *on_finish = nullptr;
87
88 static SnapshotPurgeRequest *create(librados::IoCtx &io_ctx,
89 const std::string &image_id,
90 Context *on_finish) {
91 ceph_assert(s_instance != nullptr);
92 s_instance->construct(image_id);
93 s_instance->on_finish = on_finish;
94 return s_instance;
95 }
96
97 MOCK_METHOD1(construct, void(const std::string&));
98 MOCK_METHOD0(send, void());
99
100 SnapshotPurgeRequest() {
101 s_instance = this;
102 }
103};
104
105SnapshotPurgeRequest<librbd::MockTestImageCtx>* SnapshotPurgeRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
106
107} // namespace image_deleter
108} // namespace mirror
109} // namespace rbd
110
111#include "tools/rbd_mirror/image_deleter/TrashRemoveRequest.cc"
112
113namespace rbd {
114namespace mirror {
115namespace image_deleter {
116
117using ::testing::_;
9f95a23c 118using ::testing::DoAll;
eafe8130
TL
119using ::testing::Invoke;
120using ::testing::InSequence;
121using ::testing::Return;
122using ::testing::StrEq;
123using ::testing::WithArg;
124using ::testing::WithArgs;
125
126class TestMockImageDeleterTrashRemoveRequest : public TestMockFixture {
127public:
128 typedef TrashRemoveRequest<librbd::MockTestImageCtx> MockTrashRemoveRequest;
129 typedef SnapshotPurgeRequest<librbd::MockTestImageCtx> MockSnapshotPurgeRequest;
130 typedef librbd::TrashWatcher<librbd::MockTestImageCtx> MockTrashWatcher;
131 typedef librbd::trash::RemoveRequest<librbd::MockTestImageCtx> MockLibrbdTrashRemoveRequest;
132
133 void expect_trash_get(const cls::rbd::TrashImageSpec& trash_spec, int r) {
134 using ceph::encode;
135 EXPECT_CALL(get_mock_io_ctx(m_local_io_ctx),
136 exec(StrEq(RBD_TRASH), _, StrEq("rbd"),
137 StrEq("trash_get"), _, _, _))
138 .WillOnce(WithArg<5>(Invoke([trash_spec, r](bufferlist* bl) {
139 encode(trash_spec, *bl);
140 return r;
141 })));
142 }
143
144 void expect_trash_state_set(const std::string& image_id, int r) {
145 bufferlist in_bl;
146 encode(image_id, in_bl);
147 encode(cls::rbd::TRASH_IMAGE_STATE_REMOVING, in_bl);
148 encode(cls::rbd::TRASH_IMAGE_STATE_NORMAL, in_bl);
149
150 EXPECT_CALL(get_mock_io_ctx(m_local_io_ctx),
151 exec(StrEq(RBD_TRASH), _, StrEq("rbd"),
152 StrEq("trash_state_set"),
153 ContentsEqual(in_bl), _, _))
154 .WillOnce(Return(r));
155 }
156
157 void expect_get_snapcontext(const std::string& image_id,
158 const ::SnapContext &snapc, int r) {
159 bufferlist bl;
160 encode(snapc, bl);
161
162 EXPECT_CALL(get_mock_io_ctx(m_local_io_ctx),
163 exec(librbd::util::header_name(image_id), _, StrEq("rbd"),
164 StrEq("get_snapcontext"), _, _, _))
165 .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) {
166 *out_bl = bl;
167 })),
168 Return(r)));
169 }
170
171 void expect_snapshot_purge(MockSnapshotPurgeRequest &snapshot_purge_request,
172 const std::string &image_id, int r) {
173 EXPECT_CALL(snapshot_purge_request, construct(image_id));
174 EXPECT_CALL(snapshot_purge_request, send())
175 .WillOnce(Invoke([this, &snapshot_purge_request, r]() {
176 m_threads->work_queue->queue(
177 snapshot_purge_request.on_finish, r);
178 }));
179 }
180
181 void expect_image_remove(MockLibrbdTrashRemoveRequest &image_remove_request,
182 const std::string &image_id, int r) {
183 EXPECT_CALL(image_remove_request, construct(image_id));
184 EXPECT_CALL(image_remove_request, send())
185 .WillOnce(Invoke([this, &image_remove_request, r]() {
186 m_threads->work_queue->queue(
187 image_remove_request.on_finish, r);
188 }));
189 }
190
191 void expect_notify_image_removed(MockTrashWatcher& mock_trash_watcher,
192 const std::string& image_id) {
193 EXPECT_CALL(mock_trash_watcher, notify_image_removed(image_id, _))
194 .WillOnce(WithArg<1>(Invoke([this](Context *ctx) {
195 m_threads->work_queue->queue(ctx, 0);
196 })));
197 }
198
199};
200
201TEST_F(TestMockImageDeleterTrashRemoveRequest, Success) {
202 InSequence seq;
203
204 cls::rbd::TrashImageSpec trash_image_spec{
205 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
206 expect_trash_get(trash_image_spec, 0);
207
208 expect_trash_state_set("image id", 0);
209
210 expect_get_snapcontext("image id", {1, {1}}, 0);
211
212 MockSnapshotPurgeRequest mock_snapshot_purge_request;
213 expect_snapshot_purge(mock_snapshot_purge_request, "image id", 0);
214
215 MockLibrbdTrashRemoveRequest mock_image_remove_request;
216 expect_image_remove(mock_image_remove_request, "image id", 0);
217
218 MockTrashWatcher mock_trash_watcher;
219 expect_notify_image_removed(mock_trash_watcher, "image id");
220
221 C_SaferCond ctx;
222 ErrorResult error_result;
223 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
224 &error_result,
225 m_threads->work_queue, &ctx);
226 req->send();
227 ASSERT_EQ(0, ctx.wait());
228}
229
230TEST_F(TestMockImageDeleterTrashRemoveRequest, TrashDNE) {
231 InSequence seq;
232
233 cls::rbd::TrashImageSpec trash_image_spec{
234 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
235 expect_trash_get(trash_image_spec, -ENOENT);
236
237 C_SaferCond ctx;
238 ErrorResult error_result;
239 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
240 &error_result,
241 m_threads->work_queue, &ctx);
242 req->send();
243 ASSERT_EQ(0, ctx.wait());
244}
245
246TEST_F(TestMockImageDeleterTrashRemoveRequest, TrashError) {
247 InSequence seq;
248
249 cls::rbd::TrashImageSpec trash_image_spec{
250 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
251 expect_trash_get(trash_image_spec, -EPERM);
252
253 C_SaferCond ctx;
254 ErrorResult error_result;
255 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
256 &error_result,
257 m_threads->work_queue, &ctx);
258 req->send();
259 ASSERT_EQ(-EPERM, ctx.wait());
260}
261
262TEST_F(TestMockImageDeleterTrashRemoveRequest, TrashSourceIncorrect) {
263 InSequence seq;
264
265 cls::rbd::TrashImageSpec trash_image_spec{
266 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", {}, {}};
267 expect_trash_get(trash_image_spec, 0);
268
269 C_SaferCond ctx;
270 ErrorResult error_result;
271 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
272 &error_result,
273 m_threads->work_queue, &ctx);
274 req->send();
275 ASSERT_EQ(0, ctx.wait());
276}
277
278TEST_F(TestMockImageDeleterTrashRemoveRequest, TrashStateIncorrect) {
279 InSequence seq;
280
281 cls::rbd::TrashImageSpec trash_image_spec{
282 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
283 trash_image_spec.state = cls::rbd::TRASH_IMAGE_STATE_RESTORING;
284 expect_trash_get(trash_image_spec, 0);
285
286 C_SaferCond ctx;
287 ErrorResult error_result;
288 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
289 &error_result,
290 m_threads->work_queue, &ctx);
291 req->send();
292 ASSERT_EQ(-EBUSY, ctx.wait());
293 ASSERT_EQ(ERROR_RESULT_RETRY_IMMEDIATELY, error_result);
294}
295
296TEST_F(TestMockImageDeleterTrashRemoveRequest, TrashSetStateDNE) {
297 InSequence seq;
298
299 cls::rbd::TrashImageSpec trash_image_spec{
300 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
301 expect_trash_get(trash_image_spec, 0);
302
303 expect_trash_state_set("image id", -ENOENT);
304
305 C_SaferCond ctx;
306 ErrorResult error_result;
307 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
308 &error_result,
309 m_threads->work_queue, &ctx);
310 req->send();
311 ASSERT_EQ(0, ctx.wait());
312}
313
314TEST_F(TestMockImageDeleterTrashRemoveRequest, TrashSetStateError) {
315 InSequence seq;
316
317 cls::rbd::TrashImageSpec trash_image_spec{
318 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
319 expect_trash_get(trash_image_spec, 0);
320
321 expect_trash_state_set("image id", -EPERM);
322
323 C_SaferCond ctx;
324 ErrorResult error_result;
325 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
326 &error_result,
327 m_threads->work_queue, &ctx);
328 req->send();
329 ASSERT_EQ(-EPERM, ctx.wait());
330}
331
332TEST_F(TestMockImageDeleterTrashRemoveRequest, GetSnapContextDNE) {
333 InSequence seq;
334
335 cls::rbd::TrashImageSpec trash_image_spec{
336 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
337 expect_trash_get(trash_image_spec, 0);
338
339 expect_trash_state_set("image id", 0);
340
341 expect_get_snapcontext("image id", {1, {1}}, -ENOENT);
342
343 MockLibrbdTrashRemoveRequest mock_image_remove_request;
344 expect_image_remove(mock_image_remove_request, "image id", 0);
345
346 MockTrashWatcher mock_trash_watcher;
347 expect_notify_image_removed(mock_trash_watcher, "image id");
348
349 C_SaferCond ctx;
350 ErrorResult error_result;
351 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
352 &error_result,
353 m_threads->work_queue, &ctx);
354 req->send();
355 ASSERT_EQ(0, ctx.wait());
356}
357
358TEST_F(TestMockImageDeleterTrashRemoveRequest, GetSnapContextError) {
359 InSequence seq;
360
361 cls::rbd::TrashImageSpec trash_image_spec{
362 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
363 expect_trash_get(trash_image_spec, 0);
364
365 expect_trash_state_set("image id", 0);
366
367 expect_get_snapcontext("image id", {1, {1}}, -EINVAL);
368
369 C_SaferCond ctx;
370 ErrorResult error_result;
371 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
372 &error_result,
373 m_threads->work_queue, &ctx);
374 req->send();
375 ASSERT_EQ(-EINVAL, ctx.wait());
376}
377
378TEST_F(TestMockImageDeleterTrashRemoveRequest, PurgeSnapshotBusy) {
379 InSequence seq;
380
381 cls::rbd::TrashImageSpec trash_image_spec{
382 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
383 expect_trash_get(trash_image_spec, 0);
384
385 expect_trash_state_set("image id", 0);
386
387 expect_get_snapcontext("image id", {1, {1}}, 0);
388
389 MockSnapshotPurgeRequest mock_snapshot_purge_request;
390 expect_snapshot_purge(mock_snapshot_purge_request, "image id", -EBUSY);
391
392 C_SaferCond ctx;
393 ErrorResult error_result;
394 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
395 &error_result,
396 m_threads->work_queue, &ctx);
397 req->send();
398 ASSERT_EQ(-EBUSY, ctx.wait());
399 ASSERT_EQ(ERROR_RESULT_RETRY_IMMEDIATELY, error_result);
400}
401
402TEST_F(TestMockImageDeleterTrashRemoveRequest, PurgeSnapshotError) {
403 InSequence seq;
404
405 cls::rbd::TrashImageSpec trash_image_spec{
406 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
407 expect_trash_get(trash_image_spec, 0);
408
409 expect_trash_state_set("image id", 0);
410
411 expect_get_snapcontext("image id", {1, {1}}, 0);
412
413 MockSnapshotPurgeRequest mock_snapshot_purge_request;
414 expect_snapshot_purge(mock_snapshot_purge_request, "image id", -EINVAL);
415
416 C_SaferCond ctx;
417 ErrorResult error_result;
418 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
419 &error_result,
420 m_threads->work_queue, &ctx);
421 req->send();
422 ASSERT_EQ(-EINVAL, ctx.wait());
423}
424
425TEST_F(TestMockImageDeleterTrashRemoveRequest, RemoveError) {
426 InSequence seq;
427
428 cls::rbd::TrashImageSpec trash_image_spec{
429 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, "image name", {}, {}};
430 expect_trash_get(trash_image_spec, 0);
431
432 expect_trash_state_set("image id", 0);
433
434 expect_get_snapcontext("image id", {1, {1}}, 0);
435
436 MockSnapshotPurgeRequest mock_snapshot_purge_request;
437 expect_snapshot_purge(mock_snapshot_purge_request, "image id", 0);
438
439 MockLibrbdTrashRemoveRequest mock_image_remove_request;
440 expect_image_remove(mock_image_remove_request, "image id", -EINVAL);
441
442 C_SaferCond ctx;
443 ErrorResult error_result;
444 auto req = MockTrashRemoveRequest::create(m_local_io_ctx, "image id",
445 &error_result,
446 m_threads->work_queue, &ctx);
447 req->send();
448 ASSERT_EQ(-EINVAL, ctx.wait());
449}
450
451} // namespace image_deleter
452} // namespace mirror
453} // namespace rbd