]>
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/rbd_mirror/test_mock_fixture.h" | |
5 | #include "include/rbd/librbd.hpp" | |
6 | #include "librbd/journal/Types.h" | |
7 | #include "librbd/journal/TypeTraits.h" | |
8 | #include "test/journal/mock/MockJournaler.h" | |
9 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" | |
10 | #include "test/librbd/mock/MockImageCtx.h" | |
11 | #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h" | |
12 | ||
13 | namespace librbd { | |
14 | ||
15 | namespace { | |
16 | ||
17 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
11fdf7f2 | 18 | explicit MockTestImageCtx(librbd::ImageCtx &image_ctx) |
7c673cae FG |
19 | : librbd::MockImageCtx(image_ctx) { |
20 | } | |
21 | }; | |
22 | ||
23 | } // anonymous namespace | |
24 | ||
25 | namespace journal { | |
26 | ||
27 | template <> | |
28 | struct TypeTraits<librbd::MockTestImageCtx> { | |
29 | typedef ::journal::MockJournaler Journaler; | |
30 | }; | |
31 | ||
32 | } // namespace journal | |
33 | } // namespace librbd | |
34 | ||
35 | // template definitions | |
36 | #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.cc" | |
37 | template class rbd::mirror::image_sync::SyncPointPruneRequest<librbd::MockTestImageCtx>; | |
38 | ||
39 | namespace rbd { | |
40 | namespace mirror { | |
41 | namespace image_sync { | |
42 | ||
43 | using ::testing::_; | |
44 | using ::testing::InSequence; | |
45 | using ::testing::Return; | |
46 | using ::testing::StrEq; | |
47 | using ::testing::WithArg; | |
48 | ||
49 | class TestMockImageSyncSyncPointPruneRequest : public TestMockFixture { | |
50 | public: | |
51 | typedef SyncPointPruneRequest<librbd::MockTestImageCtx> MockSyncPointPruneRequest; | |
52 | ||
53 | void SetUp() override { | |
54 | TestMockFixture::SetUp(); | |
55 | ||
56 | librbd::RBD rbd; | |
57 | ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); | |
58 | ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); | |
59 | } | |
60 | ||
61 | void expect_update_client(journal::MockJournaler &mock_journaler, int r) { | |
62 | EXPECT_CALL(mock_journaler, update_client(_, _)) | |
63 | .WillOnce(WithArg<1>(CompleteContext(r))); | |
64 | } | |
65 | ||
66 | void expect_get_snap_id(librbd::MockTestImageCtx &mock_remote_image_ctx, | |
67 | const std::string &snap_name, uint64_t snap_id) { | |
68 | EXPECT_CALL(mock_remote_image_ctx, get_snap_id(_, StrEq(snap_name))) | |
69 | .WillOnce(Return(snap_id)); | |
70 | } | |
71 | ||
72 | void expect_image_refresh(librbd::MockTestImageCtx &mock_remote_image_ctx, int r) { | |
73 | EXPECT_CALL(*mock_remote_image_ctx.state, refresh(_)) | |
74 | .WillOnce(CompleteContext(r)); | |
75 | } | |
76 | ||
77 | void expect_snap_remove(librbd::MockTestImageCtx &mock_remote_image_ctx, | |
78 | const std::string &snap_name, int r) { | |
79 | EXPECT_CALL(*mock_remote_image_ctx.operations, snap_remove(_, StrEq(snap_name), _)) | |
80 | .WillOnce(WithArg<2>(CompleteContext(r))); | |
81 | } | |
82 | ||
83 | MockSyncPointPruneRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx, | |
84 | journal::MockJournaler &mock_journaler, | |
85 | bool sync_complete, Context *ctx) { | |
86 | return new MockSyncPointPruneRequest(&mock_remote_image_ctx, sync_complete, | |
87 | &mock_journaler, &m_client_meta, ctx); | |
88 | } | |
89 | ||
90 | librbd::ImageCtx *m_remote_image_ctx; | |
91 | librbd::journal::MirrorPeerClientMeta m_client_meta; | |
92 | }; | |
93 | ||
94 | TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncInProgressSuccess) { | |
95 | librbd::journal::MirrorPeerClientMeta client_meta; | |
96 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
97 | "snap1", | |
98 | boost::none); | |
99 | m_client_meta = client_meta; | |
100 | ||
101 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
102 | journal::MockJournaler mock_journaler; | |
103 | ||
104 | InSequence seq; | |
105 | expect_get_snap_id(mock_remote_image_ctx, "snap1", 123); | |
106 | expect_image_refresh(mock_remote_image_ctx, 0); | |
107 | expect_update_client(mock_journaler, 0); | |
108 | ||
109 | C_SaferCond ctx; | |
110 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
111 | mock_journaler, false, &ctx); | |
112 | req->send(); | |
113 | ASSERT_EQ(0, ctx.wait()); | |
114 | ASSERT_EQ(client_meta, m_client_meta); | |
115 | } | |
116 | ||
117 | TEST_F(TestMockImageSyncSyncPointPruneRequest, RestartedSyncInProgressSuccess) { | |
118 | librbd::journal::MirrorPeerClientMeta client_meta; | |
119 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
120 | "snap2", | |
121 | "snap1", boost::none); | |
122 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
123 | "snap1", | |
124 | boost::none); | |
125 | m_client_meta = client_meta; | |
126 | ||
127 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
128 | journal::MockJournaler mock_journaler; | |
129 | ||
130 | InSequence seq; | |
131 | expect_get_snap_id(mock_remote_image_ctx, "snap1", 123); | |
132 | expect_snap_remove(mock_remote_image_ctx, "snap2", 0); | |
133 | expect_image_refresh(mock_remote_image_ctx, 0); | |
134 | expect_update_client(mock_journaler, 0); | |
135 | ||
136 | C_SaferCond ctx; | |
137 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
138 | mock_journaler, false, &ctx); | |
139 | req->send(); | |
140 | ASSERT_EQ(0, ctx.wait()); | |
141 | ||
142 | client_meta.sync_points.pop_back(); | |
143 | ASSERT_EQ(client_meta, m_client_meta); | |
144 | } | |
145 | ||
146 | TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncInProgressMissingSnapSuccess) { | |
147 | librbd::journal::MirrorPeerClientMeta client_meta; | |
148 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
149 | "snap2", | |
150 | "snap1", | |
151 | boost::none); | |
152 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
153 | "snap1", | |
154 | boost::none); | |
155 | m_client_meta = client_meta; | |
156 | ||
157 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
158 | journal::MockJournaler mock_journaler; | |
159 | ||
160 | InSequence seq; | |
161 | expect_get_snap_id(mock_remote_image_ctx, "snap1", CEPH_NOSNAP); | |
162 | expect_snap_remove(mock_remote_image_ctx, "snap2", 0); | |
163 | expect_snap_remove(mock_remote_image_ctx, "snap1", 0); | |
164 | expect_image_refresh(mock_remote_image_ctx, 0); | |
165 | expect_update_client(mock_journaler, 0); | |
166 | ||
167 | C_SaferCond ctx; | |
168 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
169 | mock_journaler, false, &ctx); | |
170 | req->send(); | |
171 | ASSERT_EQ(0, ctx.wait()); | |
172 | ||
173 | client_meta.sync_points.clear(); | |
174 | ASSERT_EQ(client_meta, m_client_meta); | |
175 | } | |
176 | ||
177 | TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncInProgressUnexpectedFromSnapSuccess) { | |
178 | librbd::journal::MirrorPeerClientMeta client_meta; | |
179 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
180 | "snap2", | |
181 | "snap1", | |
182 | boost::none); | |
183 | m_client_meta = client_meta; | |
184 | ||
185 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
186 | journal::MockJournaler mock_journaler; | |
187 | ||
188 | InSequence seq; | |
189 | expect_get_snap_id(mock_remote_image_ctx, "snap2", 124); | |
190 | expect_snap_remove(mock_remote_image_ctx, "snap2", 0); | |
191 | expect_snap_remove(mock_remote_image_ctx, "snap1", 0); | |
192 | expect_image_refresh(mock_remote_image_ctx, 0); | |
193 | expect_update_client(mock_journaler, 0); | |
194 | ||
195 | C_SaferCond ctx; | |
196 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
197 | mock_journaler, false, &ctx); | |
198 | req->send(); | |
199 | ASSERT_EQ(0, ctx.wait()); | |
200 | ||
201 | client_meta.sync_points.clear(); | |
202 | ASSERT_EQ(client_meta, m_client_meta); | |
203 | } | |
204 | ||
205 | TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncCompleteSuccess) { | |
206 | librbd::journal::MirrorPeerClientMeta client_meta; | |
207 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
208 | "snap1", | |
209 | boost::none); | |
210 | m_client_meta = client_meta; | |
211 | ASSERT_EQ(librbd::journal::MIRROR_PEER_STATE_SYNCING, m_client_meta.state); | |
212 | ||
213 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
214 | journal::MockJournaler mock_journaler; | |
215 | ||
216 | InSequence seq; | |
217 | expect_snap_remove(mock_remote_image_ctx, "snap1", 0); | |
218 | expect_image_refresh(mock_remote_image_ctx, 0); | |
219 | expect_update_client(mock_journaler, 0); | |
220 | ||
221 | C_SaferCond ctx; | |
222 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
223 | mock_journaler, true, &ctx); | |
224 | req->send(); | |
225 | ASSERT_EQ(0, ctx.wait()); | |
226 | ASSERT_TRUE(m_client_meta.sync_points.empty()); | |
227 | ASSERT_EQ(librbd::journal::MIRROR_PEER_STATE_REPLAYING, m_client_meta.state); | |
228 | } | |
229 | ||
230 | TEST_F(TestMockImageSyncSyncPointPruneRequest, RestartedSyncCompleteSuccess) { | |
231 | librbd::journal::MirrorPeerClientMeta client_meta; | |
232 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
233 | "snap2", | |
234 | "snap1", | |
235 | boost::none); | |
236 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
237 | "snap1", | |
238 | boost::none); | |
239 | m_client_meta = client_meta; | |
240 | ||
241 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
242 | journal::MockJournaler mock_journaler; | |
243 | ||
244 | InSequence seq; | |
245 | expect_image_refresh(mock_remote_image_ctx, 0); | |
246 | expect_update_client(mock_journaler, 0); | |
247 | ||
248 | C_SaferCond ctx; | |
249 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
250 | mock_journaler, true, &ctx); | |
251 | req->send(); | |
252 | ASSERT_EQ(0, ctx.wait()); | |
253 | client_meta.sync_points.pop_front(); | |
254 | ASSERT_EQ(client_meta, m_client_meta); | |
255 | } | |
256 | ||
257 | TEST_F(TestMockImageSyncSyncPointPruneRequest, RestartedCatchUpSyncCompleteSuccess) { | |
258 | librbd::journal::MirrorPeerClientMeta client_meta; | |
259 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
260 | "snap3", | |
261 | "snap2", | |
262 | boost::none); | |
263 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
264 | "snap2", | |
265 | "snap1", | |
266 | boost::none); | |
267 | m_client_meta = client_meta; | |
268 | ||
269 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
270 | journal::MockJournaler mock_journaler; | |
271 | ||
272 | InSequence seq; | |
273 | expect_snap_remove(mock_remote_image_ctx, "snap1", 0); | |
274 | expect_image_refresh(mock_remote_image_ctx, 0); | |
275 | expect_update_client(mock_journaler, 0); | |
276 | ||
277 | C_SaferCond ctx; | |
278 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
279 | mock_journaler, true, &ctx); | |
280 | req->send(); | |
281 | ASSERT_EQ(0, ctx.wait()); | |
282 | client_meta.sync_points.pop_front(); | |
283 | ASSERT_EQ(client_meta, m_client_meta); | |
284 | } | |
285 | ||
286 | TEST_F(TestMockImageSyncSyncPointPruneRequest, SnapshotDNE) { | |
287 | librbd::journal::MirrorPeerClientMeta client_meta; | |
288 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
289 | "snap1", | |
290 | boost::none); | |
291 | m_client_meta = client_meta; | |
292 | ||
293 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
294 | journal::MockJournaler mock_journaler; | |
295 | ||
296 | InSequence seq; | |
297 | expect_snap_remove(mock_remote_image_ctx, "snap1", -ENOENT); | |
298 | expect_image_refresh(mock_remote_image_ctx, 0); | |
299 | expect_update_client(mock_journaler, 0); | |
300 | ||
301 | C_SaferCond ctx; | |
302 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
303 | mock_journaler, true, &ctx); | |
304 | req->send(); | |
305 | ASSERT_EQ(0, ctx.wait()); | |
306 | ASSERT_TRUE(m_client_meta.sync_points.empty()); | |
307 | } | |
308 | ||
309 | TEST_F(TestMockImageSyncSyncPointPruneRequest, ClientUpdateError) { | |
310 | librbd::journal::MirrorPeerClientMeta client_meta; | |
311 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
312 | "snap2", | |
313 | "snap1", | |
314 | boost::none); | |
315 | client_meta.sync_points.emplace_front(cls::rbd::UserSnapshotNamespace(), | |
316 | "snap1", | |
317 | boost::none); | |
318 | m_client_meta = client_meta; | |
319 | ||
320 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
321 | journal::MockJournaler mock_journaler; | |
322 | ||
323 | InSequence seq; | |
324 | expect_image_refresh(mock_remote_image_ctx, 0); | |
325 | expect_update_client(mock_journaler, -EINVAL); | |
326 | ||
327 | C_SaferCond ctx; | |
328 | MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx, | |
329 | mock_journaler, true, &ctx); | |
330 | req->send(); | |
331 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
332 | ||
333 | ASSERT_EQ(client_meta, m_client_meta); | |
334 | } | |
335 | ||
336 | } // namespace image_sync | |
337 | } // namespace mirror | |
338 | } // namespace rbd |