Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / operation / test_mock_SnapshotRemoveRequest.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/librados_test_stub/MockTestMemIoCtxImpl.h"
8 #include "common/bit_vector.hpp"
9 #include "librbd/ImageState.h"
10 #include "librbd/internal.h"
11 #include "librbd/operation/SnapshotRemoveRequest.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14
15 // template definitions
16 #include "librbd/operation/SnapshotRemoveRequest.cc"
17
18 namespace librbd {
19 namespace operation {
20
21 using ::testing::_;
22 using ::testing::DoAll;
23 using ::testing::DoDefault;
24 using ::testing::Return;
25 using ::testing::SetArgPointee;
26 using ::testing::StrEq;
27 using ::testing::WithArg;
28
29 class TestMockOperationSnapshotRemoveRequest : public TestMockFixture {
30 public:
31   typedef SnapshotRemoveRequest<MockImageCtx> MockSnapshotRemoveRequest;
32
33   int create_snapshot(const char *snap_name) {
34     librbd::ImageCtx *ictx;
35     int r = open_image(m_image_name, &ictx);
36     if (r < 0) {
37       return r;
38     }
39
40     r = snap_create(*ictx, snap_name);
41     if (r < 0) {
42       return r;
43     }
44
45     r = snap_protect(*ictx, snap_name);
46     if (r < 0) {
47       return r;
48     }
49     close_image(ictx);
50     return 0;
51   }
52
53   void expect_object_map_snap_remove(MockImageCtx &mock_image_ctx, int r) {
54     if (mock_image_ctx.object_map != nullptr) {
55       EXPECT_CALL(*mock_image_ctx.object_map, snapshot_remove(_, _))
56                     .WillOnce(WithArg<1>(CompleteContext(
57                       r, mock_image_ctx.image_ctx->op_work_queue)));
58     }
59   }
60
61   void expect_get_parent_spec(MockImageCtx &mock_image_ctx, int r) {
62     auto &expect = EXPECT_CALL(mock_image_ctx, get_parent_spec(_, _));
63     if (r < 0) {
64       expect.WillOnce(Return(r));
65     } else {
66       ParentSpec &parent_spec = mock_image_ctx.snap_info.rbegin()->second.parent.spec;
67       expect.WillOnce(DoAll(SetArgPointee<1>(parent_spec),
68                             Return(0)));
69     }
70   }
71
72   void expect_remove_child(MockImageCtx &mock_image_ctx, int r) {
73     bool deep_flatten = mock_image_ctx.image_ctx->test_features(RBD_FEATURE_DEEP_FLATTEN);
74     auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
75                                exec(RBD_CHILDREN, _, StrEq("rbd"), StrEq("remove_child"), _,
76                                     _, _));
77     if (deep_flatten) {
78       expect.Times(0);
79     } else {
80       expect.WillOnce(Return(r));
81     }
82   }
83
84   void expect_verify_lock_ownership(MockImageCtx &mock_image_ctx) {
85     if (mock_image_ctx.old_format) {
86       return;
87     }
88
89     if (mock_image_ctx.exclusive_lock != nullptr) {
90       EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
91                     .WillRepeatedly(Return(false));
92     }
93   }
94
95   void expect_snap_remove(MockImageCtx &mock_image_ctx, int r) {
96     auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
97                                exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
98                                StrEq(mock_image_ctx.old_format ? "snap_remove" :
99                                                                   "snapshot_remove"),
100                                 _, _, _));
101     if (r < 0) {
102       expect.WillOnce(Return(r));
103     } else {
104       expect.WillOnce(DoDefault());
105     }
106   }
107
108   void expect_rm_snap(MockImageCtx &mock_image_ctx) {
109     EXPECT_CALL(mock_image_ctx, rm_snap(_, _, _)).Times(1);
110   }
111
112   void expect_release_snap_id(MockImageCtx &mock_image_ctx) {
113     EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
114                                 selfmanaged_snap_remove(_))
115                                   .WillOnce(DoDefault());
116   }
117
118 };
119
120 TEST_F(TestMockOperationSnapshotRemoveRequest, Success) {
121   librbd::ImageCtx *ictx;
122   ASSERT_EQ(0, open_image(m_image_name, &ictx));
123   ASSERT_EQ(0, snap_create(*ictx, "snap1"));
124   ASSERT_EQ(0, ictx->state->refresh_if_required());
125
126   MockImageCtx mock_image_ctx(*ictx);
127
128   MockExclusiveLock mock_exclusive_lock;
129   if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
130     mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
131   }
132
133   MockObjectMap mock_object_map;
134   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
135     mock_image_ctx.object_map = &mock_object_map;
136   }
137
138   expect_op_work_queue(mock_image_ctx);
139
140   ::testing::InSequence seq;
141   uint64_t snap_id = ictx->snap_info.rbegin()->first;
142   expect_object_map_snap_remove(mock_image_ctx, 0);
143   expect_get_parent_spec(mock_image_ctx, 0);
144   expect_verify_lock_ownership(mock_image_ctx);
145   expect_snap_remove(mock_image_ctx, 0);
146   expect_rm_snap(mock_image_ctx);
147   expect_release_snap_id(mock_image_ctx);
148
149   C_SaferCond cond_ctx;
150   MockSnapshotRemoveRequest *req = new MockSnapshotRemoveRequest(
151     mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), "snap1",
152     snap_id);
153   {
154     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
155     req->send();
156   }
157   ASSERT_EQ(0, cond_ctx.wait());
158 }
159
160 TEST_F(TestMockOperationSnapshotRemoveRequest, FlattenedCloneRemovesChild) {
161   REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
162
163   ASSERT_EQ(0, create_snapshot("snap1"));
164
165   int order = 22;
166   uint64_t features;
167   ASSERT_TRUE(::get_features(&features));
168   std::string clone_name = get_temp_image_name();
169   ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
170                              clone_name.c_str(), features, &order, 0, 0));
171
172   librbd::ImageCtx *ictx;
173   ASSERT_EQ(0, open_image(clone_name, &ictx));
174   ASSERT_EQ(0, snap_create(*ictx, "snap1"));
175
176   librbd::NoOpProgressContext prog_ctx;
177   ASSERT_EQ(0, flatten(*ictx, prog_ctx));
178   ASSERT_EQ(0, ictx->state->refresh_if_required());
179
180   MockImageCtx mock_image_ctx(*ictx);
181
182   MockExclusiveLock mock_exclusive_lock;
183   if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
184     mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
185   }
186
187   MockObjectMap mock_object_map;
188   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
189     mock_image_ctx.object_map = &mock_object_map;
190   }
191
192   expect_op_work_queue(mock_image_ctx);
193
194   uint64_t snap_id = ictx->snap_info.rbegin()->first;
195   expect_object_map_snap_remove(mock_image_ctx, 0);
196   expect_get_parent_spec(mock_image_ctx, 0);
197   expect_remove_child(mock_image_ctx, -ENOENT);
198   expect_verify_lock_ownership(mock_image_ctx);
199   expect_snap_remove(mock_image_ctx, 0);
200   expect_rm_snap(mock_image_ctx);
201   expect_release_snap_id(mock_image_ctx);
202
203   C_SaferCond cond_ctx;
204   MockSnapshotRemoveRequest *req = new MockSnapshotRemoveRequest(
205     mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), "snap1",
206     snap_id);
207   {
208     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
209     req->send();
210   }
211   ASSERT_EQ(0, cond_ctx.wait());
212 }
213
214 TEST_F(TestMockOperationSnapshotRemoveRequest, ObjectMapSnapRemoveError) {
215   REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
216
217   librbd::ImageCtx *ictx;
218   ASSERT_EQ(0, open_image(m_image_name, &ictx));
219   ASSERT_EQ(0, snap_create(*ictx, "snap1"));
220   ASSERT_EQ(0, ictx->state->refresh_if_required());
221
222   MockImageCtx mock_image_ctx(*ictx);
223
224   MockObjectMap mock_object_map;
225   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
226     mock_image_ctx.object_map = &mock_object_map;
227   }
228
229   expect_op_work_queue(mock_image_ctx);
230
231   ::testing::InSequence seq;
232   uint64_t snap_id = ictx->snap_info.rbegin()->first;
233   expect_object_map_snap_remove(mock_image_ctx, -EINVAL);
234
235   C_SaferCond cond_ctx;
236   MockSnapshotRemoveRequest *req = new MockSnapshotRemoveRequest(
237     mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), "snap1",
238     snap_id);
239   {
240     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
241     req->send();
242   }
243   ASSERT_EQ(-EINVAL, cond_ctx.wait());
244 }
245
246 TEST_F(TestMockOperationSnapshotRemoveRequest, RemoveChildParentError) {
247   librbd::ImageCtx *ictx;
248   ASSERT_EQ(0, open_image(m_image_name, &ictx));
249   ASSERT_EQ(0, snap_create(*ictx, "snap1"));
250   ASSERT_EQ(0, ictx->state->refresh_if_required());
251
252   MockImageCtx mock_image_ctx(*ictx);
253
254   MockObjectMap mock_object_map;
255   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
256     mock_image_ctx.object_map = &mock_object_map;
257   }
258
259   expect_op_work_queue(mock_image_ctx);
260
261   ::testing::InSequence seq;
262   uint64_t snap_id = ictx->snap_info.rbegin()->first;
263   expect_object_map_snap_remove(mock_image_ctx, 0);
264   expect_get_parent_spec(mock_image_ctx, -ENOENT);
265
266   C_SaferCond cond_ctx;
267   MockSnapshotRemoveRequest *req = new MockSnapshotRemoveRequest(
268     mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), "snap1",
269     snap_id);
270   {
271     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
272     req->send();
273   }
274   ASSERT_EQ(-ENOENT, cond_ctx.wait());
275 }
276
277 TEST_F(TestMockOperationSnapshotRemoveRequest, RemoveChildError) {
278   REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
279
280   ASSERT_EQ(0, create_snapshot("snap1"));
281
282   int order = 22;
283   uint64_t features;
284   ASSERT_TRUE(::get_features(&features));
285   std::string clone_name = get_temp_image_name();
286   ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
287                              clone_name.c_str(), features, &order, 0, 0));
288
289   librbd::ImageCtx *ictx;
290   ASSERT_EQ(0, open_image(clone_name, &ictx));
291   if (ictx->test_features(RBD_FEATURE_DEEP_FLATTEN)) {
292     std::cout << "SKIPPING" << std::endl;
293     return SUCCEED();
294   }
295
296   ASSERT_EQ(0, snap_create(*ictx, "snap1"));
297
298   librbd::NoOpProgressContext prog_ctx;
299   ASSERT_EQ(0, flatten(*ictx, prog_ctx));
300   ASSERT_EQ(0, ictx->state->refresh_if_required());
301
302   MockImageCtx mock_image_ctx(*ictx);
303
304   MockObjectMap mock_object_map;
305   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
306     mock_image_ctx.object_map = &mock_object_map;
307   }
308
309   expect_op_work_queue(mock_image_ctx);
310
311   uint64_t snap_id = ictx->snap_info.rbegin()->first;
312   expect_object_map_snap_remove(mock_image_ctx, 0);
313   expect_get_parent_spec(mock_image_ctx, 0);
314   expect_remove_child(mock_image_ctx, -EINVAL);
315
316   C_SaferCond cond_ctx;
317   MockSnapshotRemoveRequest *req = new MockSnapshotRemoveRequest(
318     mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), "snap1",
319     snap_id);
320   {
321     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
322     req->send();
323   }
324   ASSERT_EQ(-EINVAL, cond_ctx.wait());
325 }
326
327 TEST_F(TestMockOperationSnapshotRemoveRequest, RemoveSnapError) {
328   librbd::ImageCtx *ictx;
329   ASSERT_EQ(0, open_image(m_image_name, &ictx));
330   ASSERT_EQ(0, snap_create(*ictx, "snap1"));
331   ASSERT_EQ(0, ictx->state->refresh_if_required());
332
333   MockImageCtx mock_image_ctx(*ictx);
334
335   MockExclusiveLock mock_exclusive_lock;
336   if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
337     mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
338   }
339
340   MockObjectMap mock_object_map;
341   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
342     mock_image_ctx.object_map = &mock_object_map;
343   }
344
345   expect_op_work_queue(mock_image_ctx);
346
347   ::testing::InSequence seq;
348   uint64_t snap_id = ictx->snap_info.rbegin()->first;
349   expect_object_map_snap_remove(mock_image_ctx, 0);
350   expect_get_parent_spec(mock_image_ctx, 0);
351   expect_verify_lock_ownership(mock_image_ctx);
352   expect_snap_remove(mock_image_ctx, -ENOENT);
353
354   C_SaferCond cond_ctx;
355   MockSnapshotRemoveRequest *req = new MockSnapshotRemoveRequest(
356     mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), "snap1",
357     snap_id);
358   {
359     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
360     req->send();
361   }
362   ASSERT_EQ(-ENOENT, cond_ctx.wait());
363 }
364
365 TEST_F(TestMockOperationSnapshotRemoveRequest, MissingSnap) {
366   librbd::ImageCtx *ictx;
367   ASSERT_EQ(0, open_image(m_image_name, &ictx));
368
369   MockImageCtx mock_image_ctx(*ictx);
370
371   MockExclusiveLock mock_exclusive_lock;
372   if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
373     mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
374   }
375
376   MockObjectMap mock_object_map;
377   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
378     mock_image_ctx.object_map = &mock_object_map;
379   }
380
381   expect_op_work_queue(mock_image_ctx);
382
383   ::testing::InSequence seq;
384   uint64_t snap_id = 456;
385
386   C_SaferCond cond_ctx;
387   MockSnapshotRemoveRequest *req = new MockSnapshotRemoveRequest(
388     mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), "snap1",
389     snap_id);
390   {
391     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
392     req->send();
393   }
394   ASSERT_EQ(-ENOENT, cond_ctx.wait());
395 }
396
397 } // namespace operation
398 } // namespace librbd