]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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/journal/RemoveRequest.h" | |
13 | #include "librbd/Operations.h" | |
14 | #include "librbd/operation/TrimRequest.h" | |
15 | #include "librbd/image/TypeTraits.h" | |
16 | #include "librbd/image/RemoveRequest.h" | |
17 | #include "librbd/image/RefreshParentRequest.h" | |
18 | #include "librbd/mirror/DisableRequest.h" | |
19 | #include "gmock/gmock.h" | |
20 | #include "gtest/gtest.h" | |
21 | #include <arpa/inet.h> | |
22 | #include <list> | |
23 | #include <boost/scope_exit.hpp> | |
24 | ||
25 | namespace librbd { | |
26 | namespace image { | |
27 | template <> | |
28 | struct TypeTraits<MockImageCtx> { | |
29 | typedef librbd::MockContextWQ ContextWQ; | |
30 | }; | |
31 | } | |
32 | ||
33 | namespace operation { | |
34 | ||
35 | template <> | |
36 | class TrimRequest<MockImageCtx> { | |
37 | public: | |
38 | static TrimRequest *s_instance; | |
39 | static TrimRequest *create(MockImageCtx &image_ctx, Context *on_finish, | |
40 | uint64_t original_size, uint64_t new_size, | |
41 | ProgressContext &prog_ctx) { | |
42 | assert(s_instance != nullptr); | |
43 | s_instance->on_finish = on_finish; | |
44 | return s_instance; | |
45 | } | |
46 | ||
47 | Context *on_finish = nullptr; | |
48 | ||
49 | TrimRequest() { | |
50 | s_instance = this; | |
51 | } | |
52 | ||
53 | MOCK_METHOD0(send, void()); | |
54 | }; | |
55 | ||
56 | } // namespace operation | |
57 | ||
58 | namespace journal { | |
59 | template <> | |
60 | class RemoveRequest<MockImageCtx> { | |
61 | private: | |
62 | typedef ::librbd::image::TypeTraits<MockImageCtx> TypeTraits; | |
63 | typedef typename TypeTraits::ContextWQ ContextWQ; | |
64 | public: | |
65 | static RemoveRequest *s_instance; | |
66 | static RemoveRequest *create(IoCtx &ioctx, const std::string &imageid, | |
67 | const std::string &client_id, | |
68 | ContextWQ *op_work_queue, Context *on_finish) { | |
69 | assert(s_instance != nullptr); | |
70 | s_instance->on_finish = on_finish; | |
71 | return s_instance; | |
72 | } | |
73 | ||
74 | Context *on_finish = nullptr; | |
75 | ||
76 | RemoveRequest() { | |
77 | s_instance = this; | |
78 | } | |
79 | ||
80 | MOCK_METHOD0(send, void()); | |
81 | }; | |
82 | RemoveRequest<MockImageCtx> *RemoveRequest<MockImageCtx>::s_instance = nullptr; | |
83 | } // namespace journal | |
84 | ||
85 | namespace mirror { | |
86 | ||
87 | template<> | |
88 | class DisableRequest<MockImageCtx> { | |
89 | public: | |
90 | static DisableRequest *s_instance; | |
91 | Context *on_finish = nullptr; | |
92 | ||
93 | static DisableRequest *create(MockImageCtx *image_ctx, bool force, | |
94 | bool remove, Context *on_finish) { | |
95 | assert(s_instance != nullptr); | |
96 | s_instance->on_finish = on_finish; | |
97 | return s_instance; | |
98 | } | |
99 | ||
100 | DisableRequest() { | |
101 | s_instance = this; | |
102 | } | |
103 | ||
104 | MOCK_METHOD0(send, void()); | |
105 | }; | |
106 | ||
107 | DisableRequest<MockImageCtx> *DisableRequest<MockImageCtx>::s_instance; | |
108 | ||
109 | } // namespace mirror | |
110 | } // namespace librbd | |
111 | ||
112 | // template definitions | |
113 | #include "librbd/image/RemoveRequest.cc" | |
114 | template class librbd::image::RemoveRequest<librbd::MockImageCtx>; | |
115 | ||
116 | namespace librbd { | |
117 | namespace image { | |
118 | ||
119 | using ::testing::_; | |
120 | using ::testing::DoAll; | |
121 | using ::testing::DoDefault; | |
122 | using ::testing::Invoke; | |
123 | using ::testing::InSequence; | |
124 | using ::testing::Return; | |
125 | using ::testing::WithArg; | |
126 | using ::testing::SetArgPointee; | |
127 | using ::testing::StrEq; | |
128 | ||
129 | class TestMockImageRemoveRequest : public TestMockFixture { | |
130 | public: | |
131 | typedef ::librbd::image::TypeTraits<MockImageCtx> TypeTraits; | |
132 | typedef typename TypeTraits::ContextWQ ContextWQ; | |
133 | typedef RemoveRequest<MockImageCtx> MockRemoveRequest; | |
134 | typedef librbd::operation::TrimRequest<MockImageCtx> MockTrimRequest; | |
135 | typedef librbd::journal::RemoveRequest<MockImageCtx> MockJournalRemoveRequest; | |
136 | typedef librbd::mirror::DisableRequest<MockImageCtx> MockMirrorDisableRequest; | |
137 | ||
138 | librbd::ImageCtx *m_test_imctx = NULL; | |
139 | MockImageCtx *m_mock_imctx = NULL; | |
140 | ||
141 | ||
142 | void TestImageRemoveSetUp() { | |
143 | ASSERT_EQ(0, open_image(m_image_name, &m_test_imctx)); | |
144 | m_mock_imctx = new MockImageCtx(*m_test_imctx); | |
145 | librbd::MockImageCtx::s_instance = m_mock_imctx; | |
146 | } | |
147 | void TestImageRemoveTearDown() { | |
148 | librbd::MockImageCtx::s_instance = NULL; | |
149 | delete m_mock_imctx; | |
150 | } | |
151 | ||
152 | void expect_state_open(MockImageCtx &mock_image_ctx, int r) { | |
153 | EXPECT_CALL(*mock_image_ctx.state, open(_, _)) | |
154 | .WillOnce(Invoke([r](bool open_parent, Context *on_ready) { | |
155 | on_ready->complete(r); | |
156 | })); | |
31f18b77 FG |
157 | if (r < 0) { |
158 | EXPECT_CALL(mock_image_ctx, destroy()); | |
159 | } | |
7c673cae FG |
160 | } |
161 | ||
162 | void expect_state_close(MockImageCtx &mock_image_ctx) { | |
163 | EXPECT_CALL(*mock_image_ctx.state, close(_)) | |
164 | .WillOnce(Invoke([](Context *on_ready) { | |
165 | on_ready->complete(0); | |
166 | })); | |
31f18b77 | 167 | EXPECT_CALL(mock_image_ctx, destroy()); |
7c673cae FG |
168 | } |
169 | ||
170 | void expect_wq_queue(ContextWQ &wq, int r) { | |
171 | EXPECT_CALL(wq, queue(_, r)) | |
172 | .WillRepeatedly(Invoke([](Context *on_ready, int r) { | |
173 | on_ready->complete(r); | |
174 | })); | |
175 | } | |
176 | ||
177 | void expect_get_group(MockImageCtx &mock_image_ctx, int r) { | |
178 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
179 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), | |
180 | StrEq("image_get_group"), _, _, _)); | |
181 | if (r < 0) { | |
182 | expect.WillOnce(Return(r)); | |
183 | } else { | |
184 | expect.WillOnce(DoDefault()); | |
185 | } | |
186 | } | |
187 | ||
188 | void expect_trim(MockImageCtx &mock_image_ctx, | |
189 | MockTrimRequest &mock_trim_request, int r) { | |
190 | EXPECT_CALL(mock_trim_request, send()) | |
191 | .WillOnce(FinishRequest(&mock_trim_request, r, &mock_image_ctx)); | |
192 | } | |
193 | ||
194 | void expect_journal_remove(MockImageCtx &mock_image_ctx, | |
195 | MockJournalRemoveRequest &mock_journal_remove_request, int r) { | |
196 | EXPECT_CALL(mock_journal_remove_request, send()) | |
197 | .WillOnce(FinishRequest(&mock_journal_remove_request, r, &mock_image_ctx)); | |
198 | } | |
199 | ||
200 | void expect_mirror_disable(MockImageCtx &mock_image_ctx, | |
201 | MockMirrorDisableRequest &mock_mirror_disable_request, int r) { | |
202 | EXPECT_CALL(mock_mirror_disable_request, send()) | |
203 | .WillOnce(FinishRequest(&mock_mirror_disable_request, r, &mock_image_ctx)); | |
204 | } | |
205 | ||
206 | void expect_remove_child(MockImageCtx &mock_image_ctx, int r) { | |
207 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
208 | exec(RBD_CHILDREN, _, StrEq("rbd"), StrEq("remove_child"), _, | |
209 | _, _)) | |
210 | .WillOnce(Return(r)); | |
211 | } | |
212 | ||
213 | void expect_remove_mirror_image(librados::IoCtx &ioctx, int r) { | |
214 | EXPECT_CALL(get_mock_io_ctx(ioctx), | |
215 | exec(StrEq("rbd_mirroring"), _, StrEq("rbd"), StrEq("mirror_image_remove"), | |
216 | _, _, _)) | |
217 | .WillOnce(Return(r)); | |
218 | } | |
219 | ||
220 | void expect_mirror_image_get(MockImageCtx &mock_image_ctx, int r) { | |
221 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
222 | exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_get"), | |
223 | _, _, _)) | |
224 | .WillOnce(Return(r)); | |
225 | } | |
226 | ||
227 | void expect_dir_remove_image(librados::IoCtx &ioctx, int r) { | |
228 | EXPECT_CALL(get_mock_io_ctx(ioctx), | |
229 | exec(RBD_DIRECTORY, _, StrEq("rbd"), StrEq("dir_remove_image"), | |
230 | _, _, _)) | |
231 | .WillOnce(Return(r)); | |
232 | } | |
233 | }; | |
234 | ||
235 | TEST_F(TestMockImageRemoveRequest, SuccessV1) { | |
236 | REQUIRE_FORMAT_V1(); | |
237 | TestImageRemoveSetUp(); | |
238 | ||
239 | C_SaferCond ctx; | |
240 | librbd::NoOpProgressContext no_op; | |
241 | ContextWQ op_work_queue; | |
242 | MockTrimRequest mock_trim_request; | |
243 | MockJournalRemoveRequest mock_journal_remove_request; | |
244 | ||
245 | InSequence seq; | |
246 | expect_state_open(*m_mock_imctx, 0); | |
247 | expect_get_group(*m_mock_imctx, 0); | |
248 | expect_trim(*m_mock_imctx, mock_trim_request, 0); | |
249 | expect_op_work_queue(*m_mock_imctx); | |
250 | expect_state_close(*m_mock_imctx); | |
251 | expect_wq_queue(op_work_queue, 0); | |
252 | ||
253 | MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "", | |
254 | true, false, no_op, &op_work_queue, &ctx); | |
255 | req->send(); | |
256 | ||
257 | ASSERT_EQ(0, ctx.wait()); | |
258 | ||
259 | TestImageRemoveTearDown(); | |
260 | } | |
261 | ||
262 | TEST_F(TestMockImageRemoveRequest, OpenFailV1) { | |
263 | REQUIRE_FORMAT_V1(); | |
264 | TestImageRemoveSetUp(); | |
265 | ||
266 | C_SaferCond ctx; | |
267 | librbd::NoOpProgressContext no_op; | |
268 | ContextWQ op_work_queue; | |
269 | MockTrimRequest mock_trim_request; | |
270 | ||
271 | InSequence seq; | |
272 | expect_state_open(*m_mock_imctx, -ENOENT); | |
273 | expect_wq_queue(op_work_queue, 0); | |
274 | ||
275 | MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "", | |
276 | true, false, no_op, &op_work_queue, &ctx); | |
277 | req->send(); | |
278 | ||
279 | ASSERT_EQ(0, ctx.wait()); | |
280 | ||
281 | TestImageRemoveTearDown(); | |
282 | } | |
283 | ||
284 | TEST_F(TestMockImageRemoveRequest, SuccessV2) { | |
285 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
286 | TestImageRemoveSetUp(); | |
287 | ||
288 | C_SaferCond ctx; | |
289 | librbd::NoOpProgressContext no_op; | |
290 | ContextWQ op_work_queue; | |
291 | MockTrimRequest mock_trim_request; | |
292 | MockJournalRemoveRequest mock_journal_remove_request; | |
293 | MockMirrorDisableRequest mock_mirror_disable_request; | |
294 | ||
295 | InSequence seq; | |
296 | expect_state_open(*m_mock_imctx, 0); | |
297 | expect_mirror_image_get(*m_mock_imctx, 0); | |
298 | expect_get_group(*m_mock_imctx, 0); | |
299 | expect_trim(*m_mock_imctx, mock_trim_request, 0); | |
300 | expect_op_work_queue(*m_mock_imctx); | |
301 | expect_remove_child(*m_mock_imctx, 0); | |
302 | expect_mirror_disable(*m_mock_imctx, mock_mirror_disable_request, 0); | |
303 | expect_state_close(*m_mock_imctx); | |
304 | expect_wq_queue(op_work_queue, 0); | |
305 | expect_journal_remove(*m_mock_imctx, mock_journal_remove_request, 0); | |
306 | expect_remove_mirror_image(m_ioctx, 0); | |
307 | expect_dir_remove_image(m_ioctx, 0); | |
308 | ||
309 | MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "", | |
310 | true, false, no_op, &op_work_queue, &ctx); | |
311 | req->send(); | |
312 | ||
313 | ASSERT_EQ(0, ctx.wait()); | |
314 | ||
315 | TestImageRemoveTearDown(); | |
316 | } | |
317 | ||
318 | TEST_F(TestMockImageRemoveRequest, NotExistsV2) { | |
319 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
320 | TestImageRemoveSetUp(); | |
321 | ||
322 | C_SaferCond ctx; | |
323 | librbd::NoOpProgressContext no_op; | |
324 | ContextWQ op_work_queue; | |
325 | MockTrimRequest mock_trim_request; | |
326 | MockJournalRemoveRequest mock_journal_remove_request; | |
327 | MockMirrorDisableRequest mock_mirror_disable_request; | |
328 | ||
329 | InSequence seq; | |
330 | expect_state_open(*m_mock_imctx, 0); | |
331 | expect_mirror_image_get(*m_mock_imctx, 0); | |
332 | expect_get_group(*m_mock_imctx, 0); | |
333 | expect_trim(*m_mock_imctx, mock_trim_request, 0); | |
334 | expect_op_work_queue(*m_mock_imctx); | |
335 | expect_remove_child(*m_mock_imctx, 0); | |
336 | expect_mirror_disable(*m_mock_imctx, mock_mirror_disable_request, 0); | |
337 | expect_state_close(*m_mock_imctx); | |
338 | expect_wq_queue(op_work_queue, 0); | |
339 | expect_journal_remove(*m_mock_imctx, mock_journal_remove_request, 0); | |
340 | expect_remove_mirror_image(m_ioctx, 0); | |
341 | expect_dir_remove_image(m_ioctx, -ENOENT); | |
342 | ||
343 | MockRemoveRequest *req = MockRemoveRequest::create(m_ioctx, m_image_name, "", | |
344 | true, false, no_op, &op_work_queue, &ctx); | |
345 | req->send(); | |
346 | ASSERT_EQ(-ENOENT, ctx.wait()); | |
347 | ||
348 | TestImageRemoveTearDown(); | |
349 | } | |
350 | ||
351 | } // namespace image | |
352 | } // namespace librbd |