Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / test_mock_ObjectMap.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 "librbd/ObjectMap.h"
8 #include "librbd/object_map/RefreshRequest.h"
9 #include "librbd/object_map/UnlockRequest.h"
10 #include "librbd/object_map/UpdateRequest.h"
11
12 namespace librbd {
13
14 namespace {
15
16 struct MockTestImageCtx : public MockImageCtx {
17   MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
18   }
19 };
20
21 } // anonymous namespace
22
23 namespace object_map {
24
25 template <>
26 struct RefreshRequest<MockTestImageCtx> {
27   Context *on_finish = nullptr;
28   ceph::BitVector<2u> *object_map = nullptr;
29   static RefreshRequest *s_instance;
30   static RefreshRequest *create(MockTestImageCtx &image_ctx,
31                                 ceph::BitVector<2u> *object_map,
32                                 uint64_t snap_id, Context *on_finish) {
33     assert(s_instance != nullptr);
34     s_instance->on_finish = on_finish;
35     s_instance->object_map = object_map;
36     return s_instance;
37   }
38
39   MOCK_METHOD0(send, void());
40
41   RefreshRequest() {
42     s_instance = this;
43   }
44 };
45
46 template <>
47 struct UnlockRequest<MockTestImageCtx> {
48   Context *on_finish = nullptr;
49   static UnlockRequest *s_instance;
50   static UnlockRequest *create(MockTestImageCtx &image_ctx,
51                                Context *on_finish) {
52     assert(s_instance != nullptr);
53     s_instance->on_finish = on_finish;
54     return s_instance;
55   }
56
57   MOCK_METHOD0(send, void());
58   UnlockRequest() {
59     s_instance = this;
60   }
61 };
62
63 template <>
64 struct UpdateRequest<MockTestImageCtx> {
65   Context *on_finish = nullptr;
66   static UpdateRequest *s_instance;
67   static UpdateRequest *create(MockTestImageCtx &image_ctx,
68                                ceph::BitVector<2u> *object_map,
69                                uint64_t snap_id,
70                                uint64_t start_object_no, uint64_t end_object_no,
71                                uint8_t new_state,
72                                const boost::optional<uint8_t> &current_state,
73                                const ZTracer::Trace &parent_trace,
74                                Context *on_finish) {
75     assert(s_instance != nullptr);
76     s_instance->on_finish = on_finish;
77     s_instance->construct(snap_id, start_object_no, end_object_no, new_state,
78                           current_state);
79     return s_instance;
80   }
81
82   MOCK_METHOD5(construct, void(uint64_t snap_id, uint64_t start_object_no,
83                                uint64_t end_object_no, uint8_t new_state,
84                                const boost::optional<uint8_t> &current_state));
85   MOCK_METHOD0(send, void());
86   UpdateRequest() {
87     s_instance = this;
88   }
89 };
90
91 RefreshRequest<MockTestImageCtx> *RefreshRequest<MockTestImageCtx>::s_instance = nullptr;
92 UnlockRequest<MockTestImageCtx> *UnlockRequest<MockTestImageCtx>::s_instance = nullptr;
93 UpdateRequest<MockTestImageCtx> *UpdateRequest<MockTestImageCtx>::s_instance = nullptr;
94
95 } // namespace object_map
96 } // namespace librbd
97
98 #include "librbd/ObjectMap.cc"
99
100 namespace librbd {
101
102 using testing::_;
103 using testing::InSequence;
104 using testing::Invoke;
105
106 class TestMockObjectMap : public TestMockFixture {
107 public:
108   typedef ObjectMap<MockTestImageCtx> MockObjectMap;
109   typedef object_map::RefreshRequest<MockTestImageCtx> MockRefreshRequest;
110   typedef object_map::UnlockRequest<MockTestImageCtx> MockUnlockRequest;
111   typedef object_map::UpdateRequest<MockTestImageCtx> MockUpdateRequest;
112
113   void expect_refresh(MockTestImageCtx &mock_image_ctx,
114                       MockRefreshRequest &mock_refresh_request,
115                       const ceph::BitVector<2u> &object_map, int r) {
116     EXPECT_CALL(mock_refresh_request, send())
117       .WillOnce(Invoke([&mock_image_ctx, &mock_refresh_request, &object_map, r]() {
118           *mock_refresh_request.object_map = object_map;
119           mock_image_ctx.image_ctx->op_work_queue->queue(mock_refresh_request.on_finish, r);
120         }));
121   }
122
123   void expect_unlock(MockTestImageCtx &mock_image_ctx,
124                      MockUnlockRequest &mock_unlock_request, int r) {
125     EXPECT_CALL(mock_unlock_request, send())
126       .WillOnce(Invoke([&mock_image_ctx, &mock_unlock_request, r]() {
127           mock_image_ctx.image_ctx->op_work_queue->queue(mock_unlock_request.on_finish, r);
128         }));
129   }
130
131   void expect_update(MockTestImageCtx &mock_image_ctx,
132                      MockUpdateRequest &mock_update_request,
133                      uint64_t snap_id, uint64_t start_object_no,
134                      uint64_t end_object_no, uint8_t new_state,
135                      const boost::optional<uint8_t> &current_state,
136                      Context **on_finish) {
137     EXPECT_CALL(mock_update_request, construct(snap_id, start_object_no,
138                                                end_object_no, new_state,
139                                                current_state))
140       .Times(1);
141     EXPECT_CALL(mock_update_request, send())
142       .WillOnce(Invoke([&mock_image_ctx, &mock_update_request, on_finish]() {
143           *on_finish = mock_update_request.on_finish;
144         }));
145   }
146
147 };
148
149 TEST_F(TestMockObjectMap, NonDetainedUpdate) {
150   REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
151
152   librbd::ImageCtx *ictx;
153   ASSERT_EQ(0, open_image(m_image_name, &ictx));
154
155   MockTestImageCtx mock_image_ctx(*ictx);
156
157   InSequence seq;
158   ceph::BitVector<2u> object_map;
159   object_map.resize(4);
160   MockRefreshRequest mock_refresh_request;
161   expect_refresh(mock_image_ctx, mock_refresh_request, object_map, 0);
162
163   MockUpdateRequest mock_update_request;
164   Context *finish_update_1;
165   expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP,
166                 0, 1, 1, {}, &finish_update_1);
167   Context *finish_update_2;
168   expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP,
169                 1, 2, 1, {}, &finish_update_2);
170
171   MockUnlockRequest mock_unlock_request;
172   expect_unlock(mock_image_ctx, mock_unlock_request, 0);
173
174   MockObjectMap mock_object_map(mock_image_ctx, CEPH_NOSNAP);
175   C_SaferCond open_ctx;
176   mock_object_map.open(&open_ctx);
177   ASSERT_EQ(0, open_ctx.wait());
178
179   C_SaferCond update_ctx1;
180   C_SaferCond update_ctx2;
181   {
182     RWLock::RLocker snap_locker(mock_image_ctx.snap_lock);
183     RWLock::WLocker object_map_locker(mock_image_ctx.object_map_lock);
184     mock_object_map.aio_update(CEPH_NOSNAP, 0, 1, {}, {}, &update_ctx1);
185     mock_object_map.aio_update(CEPH_NOSNAP, 1, 1, {}, {}, &update_ctx2);
186   }
187
188   finish_update_2->complete(0);
189   ASSERT_EQ(0, update_ctx2.wait());
190
191   finish_update_1->complete(0);
192   ASSERT_EQ(0, update_ctx1.wait());
193
194   C_SaferCond close_ctx;
195   mock_object_map.close(&close_ctx);
196   ASSERT_EQ(0, close_ctx.wait());
197 }
198
199 TEST_F(TestMockObjectMap, DetainedUpdate) {
200   REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
201
202   librbd::ImageCtx *ictx;
203   ASSERT_EQ(0, open_image(m_image_name, &ictx));
204
205   MockTestImageCtx mock_image_ctx(*ictx);
206
207   InSequence seq;
208   ceph::BitVector<2u> object_map;
209   object_map.resize(4);
210   MockRefreshRequest mock_refresh_request;
211   expect_refresh(mock_image_ctx, mock_refresh_request, object_map, 0);
212
213   MockUpdateRequest mock_update_request;
214   Context *finish_update_1;
215   expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP,
216                 1, 4, 1, {}, &finish_update_1);
217   Context *finish_update_2 = nullptr;
218   expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP,
219                 1, 3, 1, {}, &finish_update_2);
220   Context *finish_update_3 = nullptr;
221   expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP,
222                 2, 3, 1, {}, &finish_update_3);
223   Context *finish_update_4 = nullptr;
224   expect_update(mock_image_ctx, mock_update_request, CEPH_NOSNAP,
225                 0, 2, 1, {}, &finish_update_4);
226
227   MockUnlockRequest mock_unlock_request;
228   expect_unlock(mock_image_ctx, mock_unlock_request, 0);
229
230   MockObjectMap mock_object_map(mock_image_ctx, CEPH_NOSNAP);
231   C_SaferCond open_ctx;
232   mock_object_map.open(&open_ctx);
233   ASSERT_EQ(0, open_ctx.wait());
234
235   C_SaferCond update_ctx1;
236   C_SaferCond update_ctx2;
237   C_SaferCond update_ctx3;
238   C_SaferCond update_ctx4;
239   {
240     RWLock::RLocker snap_locker(mock_image_ctx.snap_lock);
241     RWLock::WLocker object_map_locker(mock_image_ctx.object_map_lock);
242     mock_object_map.aio_update(CEPH_NOSNAP, 1, 4, 1, {}, {}, &update_ctx1);
243     mock_object_map.aio_update(CEPH_NOSNAP, 1, 3, 1, {}, {}, &update_ctx2);
244     mock_object_map.aio_update(CEPH_NOSNAP, 2, 3, 1, {}, {}, &update_ctx3);
245     mock_object_map.aio_update(CEPH_NOSNAP, 0, 2, 1, {}, {}, &update_ctx4);
246   }
247
248   // updates 2, 3, and 4 are blocked on update 1
249   ASSERT_EQ(nullptr, finish_update_2);
250   finish_update_1->complete(0);
251   ASSERT_EQ(0, update_ctx1.wait());
252
253   // updates 3 and 4 are blocked on update 2
254   ASSERT_NE(nullptr, finish_update_2);
255   ASSERT_EQ(nullptr, finish_update_3);
256   ASSERT_EQ(nullptr, finish_update_4);
257   finish_update_2->complete(0);
258   ASSERT_EQ(0, update_ctx2.wait());
259
260   ASSERT_NE(nullptr, finish_update_3);
261   ASSERT_NE(nullptr, finish_update_4);
262   finish_update_3->complete(0);
263   finish_update_4->complete(0);
264   ASSERT_EQ(0, update_ctx3.wait());
265   ASSERT_EQ(0, update_ctx4.wait());
266
267   C_SaferCond close_ctx;
268   mock_object_map.close(&close_ctx);
269   ASSERT_EQ(0, close_ctx.wait());
270 }
271
272 } // namespace librbd
273