1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 SUSE LINUX GmbH
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "test/rbd_mirror/test_mock_fixture.h"
16 #include "librbd/journal/TypeTraits.h"
17 #include "test/journal/mock/MockJournaler.h"
18 #include "test/librbd/mock/MockImageCtx.h"
19 #include "librbd/ImageState.h"
20 #include "tools/rbd_mirror/Threads.h"
21 #include "tools/rbd_mirror/ImageSync.h"
27 struct MockTestImageCtx
: public librbd::MockImageCtx
{
28 MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
29 : librbd::MockImageCtx(image_ctx
) {
33 } // anonymous namespace
38 struct TypeTraits
<librbd::MockTestImageCtx
> {
39 typedef ::journal::MockJournaler Journaler
;
42 } // namespace journal
48 using ::testing::Invoke
;
50 typedef ImageSync
<librbd::MockTestImageCtx
> MockImageSync
;
53 class ImageSync
<librbd::MockTestImageCtx
> {
55 static std::vector
<MockImageSync
*> instances
;
60 static ImageSync
* create(librbd::MockTestImageCtx
*local_image_ctx
,
61 librbd::MockTestImageCtx
*remote_image_ctx
,
62 SafeTimer
*timer
, Mutex
*timer_lock
,
63 const std::string
&mirror_uuid
,
64 journal::MockJournaler
*journaler
,
65 librbd::journal::MirrorPeerClientMeta
*client_meta
,
66 ContextWQ
*work_queue
, Context
*on_finish
,
67 ProgressContext
*progress_ctx
= nullptr) {
68 ImageSync
*sync
= new ImageSync();
69 sync
->on_finish
= on_finish
;
71 EXPECT_CALL(*sync
, send())
72 .WillRepeatedly(Invoke([sync
]() {
80 on_finish
->complete(r
);
85 instances
.push_back(this);
88 void put() { delete this; }
90 MOCK_METHOD0(cancel
, void());
91 MOCK_METHOD0(send
, void());
96 std::vector
<MockImageSync
*> MockImageSync::instances
;
102 // template definitions
103 #include "tools/rbd_mirror/ImageSyncThrottler.cc"
108 class TestMockImageSyncThrottler
: public TestMockFixture
{
110 typedef ImageSyncThrottler
<librbd::MockTestImageCtx
> MockImageSyncThrottler
;
112 void SetUp() override
{
113 TestMockFixture::SetUp();
116 ASSERT_EQ(0, create_image(rbd
, m_remote_io_ctx
, m_image_name
, m_image_size
));
117 ASSERT_EQ(0, open_image(m_remote_io_ctx
, m_image_name
, &m_remote_image_ctx
));
119 ASSERT_EQ(0, create_image(rbd
, m_local_io_ctx
, m_image_name
, m_image_size
));
120 ASSERT_EQ(0, open_image(m_local_io_ctx
, m_image_name
, &m_local_image_ctx
));
122 mock_sync_throttler
= new MockImageSyncThrottler();
124 m_mock_local_image_ctx
= new librbd::MockTestImageCtx(*m_local_image_ctx
);
125 m_mock_remote_image_ctx
= new librbd::MockTestImageCtx(*m_remote_image_ctx
);
126 m_mock_journaler
= new journal::MockJournaler();
129 void TearDown() override
{
130 MockImageSync::instances
.clear();
131 delete mock_sync_throttler
;
132 delete m_mock_local_image_ctx
;
133 delete m_mock_remote_image_ctx
;
134 delete m_mock_journaler
;
135 TestMockFixture::TearDown();
138 void start_sync(const std::string
& image_id
, Context
*ctx
) {
139 m_mock_local_image_ctx
->id
= image_id
;
140 mock_sync_throttler
->start_sync(m_mock_local_image_ctx
,
141 m_mock_remote_image_ctx
,
143 &m_threads
->timer_lock
,
147 m_threads
->work_queue
,
151 void cancel(const std::string
& mirror_uuid
, MockImageSync
*sync
,
154 EXPECT_CALL(*sync
, cancel())
155 .WillOnce(Invoke([sync
]() {
156 sync
->finish(-ECANCELED
);
159 EXPECT_CALL(*sync
, cancel()).Times(0);
161 mock_sync_throttler
->cancel_sync(m_local_io_ctx
, mirror_uuid
);
164 librbd::ImageCtx
*m_remote_image_ctx
;
165 librbd::ImageCtx
*m_local_image_ctx
;
166 librbd::MockTestImageCtx
*m_mock_local_image_ctx
;
167 librbd::MockTestImageCtx
*m_mock_remote_image_ctx
;
168 journal::MockJournaler
*m_mock_journaler
;
169 librbd::journal::MirrorPeerClientMeta m_client_meta
;
170 MockImageSyncThrottler
*mock_sync_throttler
;
173 TEST_F(TestMockImageSyncThrottler
, Single_Sync
) {
175 start_sync("image_id", &ctx
);
177 ASSERT_EQ(1u, MockImageSync::instances
.size());
178 MockImageSync
*sync
= MockImageSync::instances
[0];
179 ASSERT_EQ(true, sync
->syncing
);
181 ASSERT_EQ(0, ctx
.wait());
184 TEST_F(TestMockImageSyncThrottler
, Multiple_Syncs
) {
185 mock_sync_throttler
->set_max_concurrent_syncs(2);
188 start_sync("image_id_1", &ctx1
);
190 start_sync("image_id_2", &ctx2
);
192 start_sync("image_id_3", &ctx3
);
194 start_sync("image_id_4", &ctx4
);
196 ASSERT_EQ(4u, MockImageSync::instances
.size());
198 MockImageSync
*sync1
= MockImageSync::instances
[0];
199 ASSERT_TRUE(sync1
->syncing
);
201 MockImageSync
*sync2
= MockImageSync::instances
[1];
202 ASSERT_TRUE(sync2
->syncing
);
204 MockImageSync
*sync3
= MockImageSync::instances
[2];
205 ASSERT_FALSE(sync3
->syncing
);
207 MockImageSync
*sync4
= MockImageSync::instances
[3];
208 ASSERT_FALSE(sync4
->syncing
);
211 ASSERT_EQ(0, ctx1
.wait());
213 ASSERT_TRUE(sync3
->syncing
);
214 sync3
->finish(-EINVAL
);
215 ASSERT_EQ(-EINVAL
, ctx3
.wait());
217 ASSERT_TRUE(sync4
->syncing
);
220 ASSERT_EQ(0, ctx2
.wait());
223 ASSERT_EQ(0, ctx4
.wait());
226 TEST_F(TestMockImageSyncThrottler
, Cancel_Running_Sync
) {
228 start_sync("image_id_1", &ctx1
);
230 start_sync("image_id_2", &ctx2
);
232 ASSERT_EQ(2u, MockImageSync::instances
.size());
234 MockImageSync
*sync1
= MockImageSync::instances
[0];
235 ASSERT_TRUE(sync1
->syncing
);
237 MockImageSync
*sync2
= MockImageSync::instances
[1];
238 ASSERT_TRUE(sync2
->syncing
);
240 cancel("image_id_2", sync2
);
241 ASSERT_EQ(-ECANCELED
, ctx2
.wait());
244 ASSERT_EQ(0, ctx1
.wait());
247 TEST_F(TestMockImageSyncThrottler
, Cancel_Waiting_Sync
) {
248 mock_sync_throttler
->set_max_concurrent_syncs(1);
251 start_sync("image_id_1", &ctx1
);
253 start_sync("image_id_2", &ctx2
);
255 ASSERT_EQ(2u, MockImageSync::instances
.size());
257 MockImageSync
*sync1
= MockImageSync::instances
[0];
258 ASSERT_TRUE(sync1
->syncing
);
260 MockImageSync
*sync2
= MockImageSync::instances
[1];
261 ASSERT_FALSE(sync2
->syncing
);
263 cancel("image_id_2", sync2
, false);
264 ASSERT_EQ(-ECANCELED
, ctx2
.wait());
267 ASSERT_EQ(0, ctx1
.wait());
270 TEST_F(TestMockImageSyncThrottler
, Cancel_Running_Sync_Start_Waiting
) {
271 mock_sync_throttler
->set_max_concurrent_syncs(1);
274 start_sync("image_id_1", &ctx1
);
276 start_sync("image_id_2", &ctx2
);
278 ASSERT_EQ(2u, MockImageSync::instances
.size());
280 MockImageSync
*sync1
= MockImageSync::instances
[0];
281 ASSERT_TRUE(sync1
->syncing
);
283 MockImageSync
*sync2
= MockImageSync::instances
[1];
284 ASSERT_FALSE(sync2
->syncing
);
286 cancel("image_id_1", sync1
);
287 ASSERT_EQ(-ECANCELED
, ctx1
.wait());
289 ASSERT_TRUE(sync2
->syncing
);
291 ASSERT_EQ(0, ctx2
.wait());
294 TEST_F(TestMockImageSyncThrottler
, Increase_Max_Concurrent_Syncs
) {
295 mock_sync_throttler
->set_max_concurrent_syncs(2);
298 start_sync("image_id_1", &ctx1
);
300 start_sync("image_id_2", &ctx2
);
302 start_sync("image_id_3", &ctx3
);
304 start_sync("image_id_4", &ctx4
);
306 start_sync("image_id_5", &ctx5
);
308 ASSERT_EQ(5u, MockImageSync::instances
.size());
310 MockImageSync
*sync1
= MockImageSync::instances
[0];
311 ASSERT_TRUE(sync1
->syncing
);
313 MockImageSync
*sync2
= MockImageSync::instances
[1];
314 ASSERT_TRUE(sync2
->syncing
);
316 MockImageSync
*sync3
= MockImageSync::instances
[2];
317 ASSERT_FALSE(sync3
->syncing
);
319 MockImageSync
*sync4
= MockImageSync::instances
[3];
320 ASSERT_FALSE(sync4
->syncing
);
322 MockImageSync
*sync5
= MockImageSync::instances
[4];
323 ASSERT_FALSE(sync5
->syncing
);
325 mock_sync_throttler
->set_max_concurrent_syncs(4);
327 ASSERT_TRUE(sync3
->syncing
);
328 ASSERT_TRUE(sync4
->syncing
);
329 ASSERT_FALSE(sync5
->syncing
);
332 ASSERT_EQ(0, ctx1
.wait());
334 ASSERT_TRUE(sync5
->syncing
);
335 sync5
->finish(-EINVAL
);
336 ASSERT_EQ(-EINVAL
, ctx5
.wait());
339 ASSERT_EQ(0, ctx2
.wait());
342 ASSERT_EQ(0, ctx3
.wait());
345 ASSERT_EQ(0, ctx4
.wait());
348 TEST_F(TestMockImageSyncThrottler
, Decrease_Max_Concurrent_Syncs
) {
349 mock_sync_throttler
->set_max_concurrent_syncs(4);
352 start_sync("image_id_1", &ctx1
);
354 start_sync("image_id_2", &ctx2
);
356 start_sync("image_id_3", &ctx3
);
358 start_sync("image_id_4", &ctx4
);
360 start_sync("image_id_5", &ctx5
);
362 ASSERT_EQ(5u, MockImageSync::instances
.size());
364 MockImageSync
*sync1
= MockImageSync::instances
[0];
365 ASSERT_TRUE(sync1
->syncing
);
367 MockImageSync
*sync2
= MockImageSync::instances
[1];
368 ASSERT_TRUE(sync2
->syncing
);
370 MockImageSync
*sync3
= MockImageSync::instances
[2];
371 ASSERT_TRUE(sync3
->syncing
);
373 MockImageSync
*sync4
= MockImageSync::instances
[3];
374 ASSERT_TRUE(sync4
->syncing
);
376 MockImageSync
*sync5
= MockImageSync::instances
[4];
377 ASSERT_FALSE(sync5
->syncing
);
379 mock_sync_throttler
->set_max_concurrent_syncs(2);
381 ASSERT_FALSE(sync5
->syncing
);
384 ASSERT_EQ(0, ctx1
.wait());
386 ASSERT_FALSE(sync5
->syncing
);
389 ASSERT_EQ(0, ctx2
.wait());
391 ASSERT_FALSE(sync5
->syncing
);
394 ASSERT_EQ(0, ctx3
.wait());
396 ASSERT_TRUE(sync5
->syncing
);
399 ASSERT_EQ(0, ctx4
.wait());
402 ASSERT_EQ(0, ctx5
.wait());
406 } // namespace mirror