]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/test_mock_InstanceReplayer.cc
update sources to v12.1.3
[ceph.git] / ceph / src / test / rbd_mirror / test_mock_InstanceReplayer.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/mock/MockImageCtx.h"
5 #include "test/rbd_mirror/test_mock_fixture.h"
6 #include "test/rbd_mirror/mock/MockContextWQ.h"
7 #include "test/rbd_mirror/mock/MockSafeTimer.h"
8 #include "tools/rbd_mirror/ImageDeleter.h"
9 #include "tools/rbd_mirror/ImageReplayer.h"
10 #include "tools/rbd_mirror/InstanceWatcher.h"
11 #include "tools/rbd_mirror/InstanceReplayer.h"
12 #include "tools/rbd_mirror/ServiceDaemon.h"
13 #include "tools/rbd_mirror/Threads.h"
14 #include "tools/rbd_mirror/image_replayer/Types.h"
15
16 namespace librbd {
17
18 namespace {
19
20 struct MockTestImageCtx : public MockImageCtx {
21 MockTestImageCtx(librbd::ImageCtx &image_ctx)
22 : librbd::MockImageCtx(image_ctx) {
23 }
24 };
25
26 } // anonymous namespace
27
28 } // namespace librbd
29
30 namespace rbd {
31 namespace mirror {
32
33 template <>
34 struct Threads<librbd::MockTestImageCtx> {
35 MockSafeTimer *timer;
36 Mutex &timer_lock;
37 Cond timer_cond;
38
39 MockContextWQ *work_queue;
40
41 Threads(Threads<librbd::ImageCtx> *threads)
42 : timer(new MockSafeTimer()),
43 timer_lock(threads->timer_lock),
44 work_queue(new MockContextWQ()) {
45 }
46 ~Threads() {
47 delete timer;
48 delete work_queue;
49 }
50 };
51
52 template <>
53 struct ImageDeleter<librbd::MockTestImageCtx> {
54 };
55
56 template<>
57 struct ServiceDaemon<librbd::MockTestImageCtx> {
58 MOCK_METHOD3(add_or_update_attribute,
59 void(int64_t, const std::string&,
60 const service_daemon::AttributeValue&));
61 };
62
63 template<>
64 struct InstanceWatcher<librbd::MockTestImageCtx> {
65 };
66
67 template<>
68 struct ImageReplayer<librbd::MockTestImageCtx> {
69 static ImageReplayer* s_instance;
70 std::string global_image_id;
71
72 static ImageReplayer *create(
73 Threads<librbd::MockTestImageCtx> *threads,
74 ImageDeleter<librbd::MockTestImageCtx>* image_deleter,
75 InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
76 RadosRef local, const std::string &local_mirror_uuid, int64_t local_pool_id,
77 const std::string &global_image_id) {
78 assert(s_instance != nullptr);
79 s_instance->global_image_id = global_image_id;
80 return s_instance;
81 }
82
83 ImageReplayer() {
84 assert(s_instance == nullptr);
85 s_instance = this;
86 }
87
88 virtual ~ImageReplayer() {
89 assert(s_instance == this);
90 s_instance = nullptr;
91 }
92
93 MOCK_METHOD0(destroy, void());
94 MOCK_METHOD2(start, void(Context *, bool));
95 MOCK_METHOD2(stop, void(Context *, bool));
96 MOCK_METHOD0(restart, void());
97 MOCK_METHOD0(flush, void());
98 MOCK_METHOD2(print_status, void(Formatter *, stringstream *));
99 MOCK_METHOD2(add_peer, void(const std::string &, librados::IoCtx &));
100 MOCK_METHOD0(get_global_image_id, const std::string &());
101 MOCK_METHOD0(get_local_image_id, const std::string &());
102 MOCK_METHOD0(is_running, bool());
103 MOCK_METHOD0(is_stopped, bool());
104 MOCK_METHOD0(is_blacklisted, bool());
105
106 MOCK_CONST_METHOD0(is_finished, bool());
107 MOCK_METHOD1(set_finished, void(bool));
108
109 MOCK_CONST_METHOD0(get_health_state, image_replayer::HealthState());
110 };
111
112 ImageReplayer<librbd::MockTestImageCtx>* ImageReplayer<librbd::MockTestImageCtx>::s_instance = nullptr;
113
114 } // namespace mirror
115 } // namespace rbd
116
117 // template definitions
118 #include "tools/rbd_mirror/InstanceReplayer.cc"
119
120 namespace rbd {
121 namespace mirror {
122
123 using ::testing::_;
124 using ::testing::InSequence;
125 using ::testing::Invoke;
126 using ::testing::Return;
127 using ::testing::ReturnRef;
128 using ::testing::WithArg;
129
130 class TestMockInstanceReplayer : public TestMockFixture {
131 public:
132 typedef Threads<librbd::MockTestImageCtx> MockThreads;
133 typedef ImageDeleter<librbd::MockTestImageCtx> MockImageDeleter;
134 typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer;
135 typedef InstanceReplayer<librbd::MockTestImageCtx> MockInstanceReplayer;
136 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
137 typedef ServiceDaemon<librbd::MockTestImageCtx> MockServiceDaemon;
138
139 void expect_work_queue(MockThreads &mock_threads) {
140 EXPECT_CALL(*mock_threads.work_queue, queue(_, _))
141 .WillOnce(Invoke([this](Context *ctx, int r) {
142 m_threads->work_queue->queue(ctx, r);
143 }));
144 }
145
146 void expect_add_event_after(MockThreads &mock_threads,
147 Context** timer_ctx = nullptr) {
148 EXPECT_CALL(*mock_threads.timer, add_event_after(_, _))
149 .WillOnce(WithArg<1>(
150 Invoke([this, &mock_threads, timer_ctx](Context *ctx) {
151 assert(mock_threads.timer_lock.is_locked());
152 if (timer_ctx != nullptr) {
153 *timer_ctx = ctx;
154 mock_threads.timer_cond.SignalOne();
155 } else {
156 m_threads->work_queue->queue(
157 new FunctionContext([&mock_threads, ctx](int) {
158 Mutex::Locker timer_lock(mock_threads.timer_lock);
159 ctx->complete(0);
160 }), 0);
161 }
162 })));
163 }
164
165 void expect_cancel_event(MockThreads &mock_threads, bool canceled) {
166 EXPECT_CALL(*mock_threads.timer, cancel_event(_))
167 .WillOnce(Return(canceled));
168 }
169 };
170
171 TEST_F(TestMockInstanceReplayer, AcquireReleaseImage) {
172 MockThreads mock_threads(m_threads);
173 MockServiceDaemon mock_service_daemon;
174 MockImageDeleter mock_image_deleter;
175 MockInstanceWatcher mock_instance_watcher;
176 MockImageReplayer mock_image_replayer;
177 MockInstanceReplayer instance_replayer(
178 &mock_threads, &mock_service_daemon, &mock_image_deleter,
179 rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)),
180 "local_mirror_uuid", m_local_io_ctx.get_id());
181 std::string global_image_id("global_image_id");
182
183 EXPECT_CALL(mock_image_replayer, get_global_image_id())
184 .WillRepeatedly(ReturnRef(global_image_id));
185
186 InSequence seq;
187 expect_work_queue(mock_threads);
188 Context *timer_ctx = nullptr;
189 expect_add_event_after(mock_threads, &timer_ctx);
190 instance_replayer.init();
191 instance_replayer.add_peer("peer_uuid", m_remote_io_ctx);
192
193 // Acquire
194
195 C_SaferCond on_acquire;
196 EXPECT_CALL(mock_image_replayer, add_peer("peer_uuid", _));
197 EXPECT_CALL(mock_image_replayer, set_finished(false));
198 EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
199 EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
200 EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(false));
201 EXPECT_CALL(mock_image_replayer, start(nullptr, false));
202 expect_work_queue(mock_threads);
203
204 instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
205 &on_acquire);
206 ASSERT_EQ(0, on_acquire.wait());
207
208 // Release
209
210 C_SaferCond on_release;
211
212 EXPECT_CALL(mock_image_replayer, is_stopped())
213 .WillOnce(Return(false));
214 EXPECT_CALL(mock_image_replayer, is_running())
215 .WillOnce(Return(false));
216 expect_work_queue(mock_threads);
217 expect_add_event_after(mock_threads);
218 expect_work_queue(mock_threads);
219 EXPECT_CALL(mock_image_replayer, is_stopped())
220 .WillOnce(Return(false));
221 EXPECT_CALL(mock_image_replayer, is_running())
222 .WillOnce(Return(true));
223 EXPECT_CALL(mock_image_replayer, stop(_, false))
224 .WillOnce(CompleteContext(0));
225 expect_work_queue(mock_threads);
226 EXPECT_CALL(mock_image_replayer, is_stopped())
227 .WillOnce(Return(true));
228 expect_work_queue(mock_threads);
229 EXPECT_CALL(mock_image_replayer, destroy());
230
231 instance_replayer.release_image("global_image_id", &on_release);
232 ASSERT_EQ(0, on_release.wait());
233
234 expect_work_queue(mock_threads);
235 expect_cancel_event(mock_threads, true);
236 expect_work_queue(mock_threads);
237 instance_replayer.shut_down();
238 ASSERT_TRUE(timer_ctx != nullptr);
239 delete timer_ctx;
240 }
241
242 TEST_F(TestMockInstanceReplayer, RemoveFinishedImage) {
243 MockThreads mock_threads(m_threads);
244 MockServiceDaemon mock_service_daemon;
245 MockImageDeleter mock_image_deleter;
246 MockInstanceWatcher mock_instance_watcher;
247 MockImageReplayer mock_image_replayer;
248 MockInstanceReplayer instance_replayer(
249 &mock_threads, &mock_service_daemon, &mock_image_deleter,
250 rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)),
251 "local_mirror_uuid", m_local_io_ctx.get_id());
252 std::string global_image_id("global_image_id");
253
254 EXPECT_CALL(mock_image_replayer, get_global_image_id())
255 .WillRepeatedly(ReturnRef(global_image_id));
256
257 InSequence seq;
258 expect_work_queue(mock_threads);
259 Context *timer_ctx1 = nullptr;
260 expect_add_event_after(mock_threads, &timer_ctx1);
261 instance_replayer.init();
262 instance_replayer.add_peer("peer_uuid", m_remote_io_ctx);
263
264 // Acquire
265
266 C_SaferCond on_acquire;
267 EXPECT_CALL(mock_image_replayer, add_peer("peer_uuid", _));
268 EXPECT_CALL(mock_image_replayer, set_finished(false));
269 EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
270 EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
271 EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(false));
272 EXPECT_CALL(mock_image_replayer, start(nullptr, false));
273 expect_work_queue(mock_threads);
274
275 instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
276 &on_acquire);
277 ASSERT_EQ(0, on_acquire.wait());
278
279 // periodic start timer
280 Context *timer_ctx2 = nullptr;
281 expect_add_event_after(mock_threads, &timer_ctx2);
282
283 Context *start_image_replayers_ctx = nullptr;
284 EXPECT_CALL(*mock_threads.work_queue, queue(_, 0))
285 .WillOnce(Invoke([&start_image_replayers_ctx](Context *ctx, int r) {
286 start_image_replayers_ctx = ctx;
287 }));
288
289 ASSERT_TRUE(timer_ctx1 != nullptr);
290 {
291 Mutex::Locker timer_locker(mock_threads.timer_lock);
292 timer_ctx1->complete(0);
293 }
294
295 // remove finished image replayer
296 EXPECT_CALL(mock_image_replayer, get_health_state()).WillOnce(
297 Return(image_replayer::HEALTH_STATE_OK));
298 EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
299 EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
300 EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(true));
301 EXPECT_CALL(mock_image_replayer, destroy());
302 EXPECT_CALL(mock_service_daemon,add_or_update_attribute(_, _, _)).Times(3);
303
304 ASSERT_TRUE(start_image_replayers_ctx != nullptr);
305 start_image_replayers_ctx->complete(0);
306
307 // shut down
308 expect_work_queue(mock_threads);
309 expect_cancel_event(mock_threads, true);
310 expect_work_queue(mock_threads);
311 instance_replayer.shut_down();
312 ASSERT_TRUE(timer_ctx2 != nullptr);
313 delete timer_ctx2;
314 }
315 } // namespace mirror
316 } // namespace rbd