]>
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/mock/MockImageCtx.h" | |
5 | #include "test/rbd_mirror/test_mock_fixture.h" | |
c07f9fc5 | 6 | #include "tools/rbd_mirror/ImageDeleter.h" |
7c673cae | 7 | #include "tools/rbd_mirror/ImageReplayer.h" |
31f18b77 | 8 | #include "tools/rbd_mirror/InstanceWatcher.h" |
7c673cae | 9 | #include "tools/rbd_mirror/InstanceReplayer.h" |
c07f9fc5 | 10 | #include "tools/rbd_mirror/ServiceDaemon.h" |
7c673cae | 11 | #include "tools/rbd_mirror/Threads.h" |
c07f9fc5 | 12 | #include "tools/rbd_mirror/image_replayer/Types.h" |
7c673cae FG |
13 | |
14 | namespace librbd { | |
15 | ||
16 | namespace { | |
17 | ||
18 | struct MockTestImageCtx : public MockImageCtx { | |
19 | MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
20 | : librbd::MockImageCtx(image_ctx) { | |
21 | } | |
22 | }; | |
23 | ||
24 | } // anonymous namespace | |
25 | ||
26 | } // namespace librbd | |
27 | ||
28 | namespace rbd { | |
29 | namespace mirror { | |
30 | ||
31 | template <> | |
32 | struct Threads<librbd::MockTestImageCtx> { | |
33 | Mutex &timer_lock; | |
34 | SafeTimer *timer; | |
35 | ContextWQ *work_queue; | |
36 | ||
37 | Threads(Threads<librbd::ImageCtx> *threads) | |
38 | : timer_lock(threads->timer_lock), timer(threads->timer), | |
39 | work_queue(threads->work_queue) { | |
40 | } | |
41 | }; | |
42 | ||
c07f9fc5 FG |
43 | template <> |
44 | struct ImageDeleter<librbd::MockTestImageCtx> { | |
45 | MOCK_METHOD4(schedule_image_delete, void(RadosRef, int64_t, | |
46 | const std::string&, bool)); | |
47 | MOCK_METHOD4(wait_for_scheduled_deletion, | |
48 | void(int64_t, const std::string&, Context*, bool)); | |
49 | }; | |
50 | ||
51 | template<> | |
52 | struct ServiceDaemon<librbd::MockTestImageCtx> { | |
53 | MOCK_METHOD3(add_or_update_attribute, | |
54 | void(int64_t, const std::string&, | |
55 | const service_daemon::AttributeValue&)); | |
56 | }; | |
57 | ||
31f18b77 FG |
58 | template<> |
59 | struct InstanceWatcher<librbd::MockTestImageCtx> { | |
60 | }; | |
61 | ||
7c673cae FG |
62 | template<> |
63 | struct ImageReplayer<librbd::MockTestImageCtx> { | |
64 | static ImageReplayer* s_instance; | |
65 | std::string global_image_id; | |
66 | ||
67 | static ImageReplayer *create( | |
68 | Threads<librbd::MockTestImageCtx> *threads, | |
c07f9fc5 | 69 | ImageDeleter<librbd::MockTestImageCtx>* image_deleter, |
31f18b77 | 70 | InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher, |
7c673cae FG |
71 | RadosRef local, const std::string &local_mirror_uuid, int64_t local_pool_id, |
72 | const std::string &global_image_id) { | |
73 | assert(s_instance != nullptr); | |
74 | s_instance->global_image_id = global_image_id; | |
75 | return s_instance; | |
76 | } | |
77 | ||
78 | ImageReplayer() { | |
79 | assert(s_instance == nullptr); | |
80 | s_instance = this; | |
81 | } | |
82 | ||
83 | virtual ~ImageReplayer() { | |
84 | assert(s_instance == this); | |
85 | s_instance = nullptr; | |
86 | } | |
87 | ||
88 | MOCK_METHOD0(destroy, void()); | |
89 | MOCK_METHOD2(start, void(Context *, bool)); | |
90 | MOCK_METHOD2(stop, void(Context *, bool)); | |
91 | MOCK_METHOD0(restart, void()); | |
92 | MOCK_METHOD0(flush, void()); | |
93 | MOCK_METHOD2(print_status, void(Formatter *, stringstream *)); | |
94 | MOCK_METHOD3(add_remote_image, void(const std::string &, | |
95 | const std::string &, | |
96 | librados::IoCtx &)); | |
97 | MOCK_METHOD3(remove_remote_image, void(const std::string &, | |
98 | const std::string &, | |
99 | bool)); | |
100 | MOCK_METHOD0(remote_images_empty, bool()); | |
101 | MOCK_METHOD0(get_global_image_id, const std::string &()); | |
102 | MOCK_METHOD0(get_local_image_id, const std::string &()); | |
103 | MOCK_METHOD0(is_running, bool()); | |
104 | MOCK_METHOD0(is_stopped, bool()); | |
105 | MOCK_METHOD0(is_blacklisted, bool()); | |
c07f9fc5 FG |
106 | |
107 | MOCK_CONST_METHOD0(get_health_state, image_replayer::HealthState()); | |
7c673cae FG |
108 | }; |
109 | ||
7c673cae FG |
110 | ImageReplayer<librbd::MockTestImageCtx>* ImageReplayer<librbd::MockTestImageCtx>::s_instance = nullptr; |
111 | ||
112 | } // namespace mirror | |
113 | } // namespace rbd | |
114 | ||
115 | // template definitions | |
116 | #include "tools/rbd_mirror/InstanceReplayer.cc" | |
117 | ||
118 | namespace rbd { | |
119 | namespace mirror { | |
120 | ||
121 | using ::testing::_; | |
122 | using ::testing::InSequence; | |
123 | using ::testing::Invoke; | |
124 | using ::testing::Return; | |
125 | using ::testing::ReturnRef; | |
c07f9fc5 | 126 | using ::testing::WithArg; |
7c673cae FG |
127 | |
128 | class TestMockInstanceReplayer : public TestMockFixture { | |
129 | public: | |
c07f9fc5 | 130 | typedef ImageDeleter<librbd::MockTestImageCtx> MockImageDeleter; |
7c673cae FG |
131 | typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer; |
132 | typedef InstanceReplayer<librbd::MockTestImageCtx> MockInstanceReplayer; | |
31f18b77 | 133 | typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher; |
c07f9fc5 | 134 | typedef ServiceDaemon<librbd::MockTestImageCtx> MockServiceDaemon; |
7c673cae FG |
135 | typedef Threads<librbd::MockTestImageCtx> MockThreads; |
136 | ||
137 | void SetUp() override { | |
138 | TestMockFixture::SetUp(); | |
139 | ||
140 | m_mock_threads = new MockThreads(m_threads); | |
7c673cae FG |
141 | } |
142 | ||
143 | void TearDown() override { | |
144 | delete m_mock_threads; | |
145 | TestMockFixture::TearDown(); | |
146 | } | |
147 | ||
c07f9fc5 FG |
148 | void expect_wait_for_scheduled_deletion(MockImageDeleter& mock_image_deleter, |
149 | const std::string& global_image_id, | |
150 | int r) { | |
151 | EXPECT_CALL(mock_image_deleter, | |
152 | wait_for_scheduled_deletion(_, global_image_id, _, false)) | |
153 | .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { | |
154 | m_threads->work_queue->queue(ctx, r); | |
155 | }))); | |
156 | } | |
157 | ||
7c673cae | 158 | MockThreads *m_mock_threads; |
7c673cae FG |
159 | }; |
160 | ||
161 | TEST_F(TestMockInstanceReplayer, AcquireReleaseImage) { | |
c07f9fc5 FG |
162 | MockServiceDaemon mock_service_daemon; |
163 | MockImageDeleter mock_image_deleter; | |
31f18b77 | 164 | MockInstanceWatcher mock_instance_watcher; |
7c673cae FG |
165 | MockImageReplayer mock_image_replayer; |
166 | MockInstanceReplayer instance_replayer( | |
c07f9fc5 | 167 | m_mock_threads, &mock_service_daemon, &mock_image_deleter, |
7c673cae FG |
168 | rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)), |
169 | "local_mirror_uuid", m_local_io_ctx.get_id()); | |
170 | ||
171 | std::string global_image_id("global_image_id"); | |
172 | ||
173 | EXPECT_CALL(mock_image_replayer, get_global_image_id()) | |
174 | .WillRepeatedly(ReturnRef(global_image_id)); | |
175 | EXPECT_CALL(mock_image_replayer, is_blacklisted()) | |
176 | .WillRepeatedly(Return(false)); | |
177 | ||
c07f9fc5 FG |
178 | expect_wait_for_scheduled_deletion(mock_image_deleter, "global_image_id", 0); |
179 | ||
7c673cae FG |
180 | InSequence seq; |
181 | ||
182 | instance_replayer.init(); | |
183 | instance_replayer.add_peer("remote_mirror_uuid", m_remote_io_ctx); | |
184 | ||
185 | // Acquire | |
186 | ||
187 | C_SaferCond on_acquire; | |
188 | ||
189 | EXPECT_CALL(mock_image_replayer, add_remote_image("remote_mirror_uuid", | |
190 | "remote_image_id", _)); | |
191 | EXPECT_CALL(mock_image_replayer, is_stopped()) | |
192 | .WillOnce(Return(true)); | |
193 | EXPECT_CALL(mock_image_replayer, start(nullptr, false)); | |
194 | ||
31f18b77 FG |
195 | instance_replayer.acquire_image(&mock_instance_watcher, global_image_id, |
196 | "remote_mirror_uuid", "remote_image_id", | |
197 | &on_acquire); | |
7c673cae FG |
198 | ASSERT_EQ(0, on_acquire.wait()); |
199 | ||
200 | // Release | |
201 | ||
202 | C_SaferCond on_release; | |
203 | ||
204 | EXPECT_CALL(mock_image_replayer, | |
205 | remove_remote_image("remote_mirror_uuid", "remote_image_id", | |
206 | false)); | |
207 | EXPECT_CALL(mock_image_replayer, remote_images_empty()) | |
208 | .WillOnce(Return(true)); | |
209 | EXPECT_CALL(mock_image_replayer, is_stopped()) | |
210 | .WillOnce(Return(false)); | |
211 | EXPECT_CALL(mock_image_replayer, is_running()) | |
212 | .WillOnce(Return(false)); | |
213 | EXPECT_CALL(mock_image_replayer, is_stopped()) | |
214 | .WillOnce(Return(false)); | |
215 | EXPECT_CALL(mock_image_replayer, is_running()) | |
216 | .WillOnce(Return(true)); | |
217 | EXPECT_CALL(mock_image_replayer, stop(_, false)) | |
218 | .WillOnce(CompleteContext(0)); | |
219 | EXPECT_CALL(mock_image_replayer, is_stopped()) | |
220 | .WillOnce(Return(true)); | |
221 | EXPECT_CALL(mock_image_replayer, destroy()); | |
222 | ||
223 | instance_replayer.release_image("global_image_id", "remote_mirror_uuid", | |
224 | "remote_image_id", false, &on_release); | |
225 | ASSERT_EQ(0, on_release.wait()); | |
226 | ||
227 | instance_replayer.shut_down(); | |
228 | } | |
229 | ||
230 | } // namespace mirror | |
231 | } // namespace rbd |