]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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/migration/MockStreamInterface.h" | |
7 | #include "include/rbd_types.h" | |
8 | #include "common/ceph_mutex.h" | |
9 | #include "librbd/migration/FileStream.h" | |
10 | #include "librbd/migration/RawSnapshot.h" | |
11 | #include "librbd/migration/SourceSpecBuilder.h" | |
12 | #include "gtest/gtest.h" | |
13 | #include "gmock/gmock.h" | |
14 | #include "json_spirit/json_spirit.h" | |
15 | ||
16 | namespace librbd { | |
17 | namespace { | |
18 | ||
19 | struct MockTestImageCtx : public MockImageCtx { | |
20 | MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) { | |
21 | } | |
22 | }; | |
23 | ||
24 | } // anonymous namespace | |
25 | ||
26 | namespace migration { | |
27 | ||
28 | template<> | |
29 | struct SourceSpecBuilder<librbd::MockTestImageCtx> { | |
30 | ||
31 | MOCK_CONST_METHOD2(build_stream, int(const json_spirit::mObject&, | |
32 | std::shared_ptr<StreamInterface>*)); | |
33 | ||
34 | }; | |
35 | ||
36 | } // namespace migration | |
37 | } // namespace librbd | |
38 | ||
39 | #include "librbd/migration/RawSnapshot.cc" | |
40 | ||
41 | using ::testing::_; | |
42 | using ::testing::InSequence; | |
43 | using ::testing::Invoke; | |
44 | using ::testing::WithArgs; | |
45 | ||
46 | namespace librbd { | |
47 | namespace migration { | |
48 | ||
49 | using ::testing::Invoke; | |
50 | ||
51 | class TestMockMigrationRawSnapshot : public TestMockFixture { | |
52 | public: | |
53 | typedef RawSnapshot<MockTestImageCtx> MockRawSnapshot; | |
54 | typedef SourceSpecBuilder<MockTestImageCtx> MockSourceSpecBuilder; | |
55 | ||
56 | librbd::ImageCtx *m_image_ctx; | |
57 | ||
58 | void SetUp() override { | |
59 | TestMockFixture::SetUp(); | |
60 | ||
61 | ASSERT_EQ(0, open_image(m_image_name, &m_image_ctx)); | |
62 | ||
63 | json_spirit::mObject stream_obj; | |
64 | stream_obj["type"] = "file"; | |
65 | json_object["stream"] = stream_obj; | |
66 | } | |
67 | ||
68 | void expect_build_stream(MockSourceSpecBuilder& mock_source_spec_builder, | |
69 | MockStreamInterface* mock_stream_interface, int r) { | |
70 | EXPECT_CALL(mock_source_spec_builder, build_stream(_, _)) | |
71 | .WillOnce(WithArgs<1>(Invoke([mock_stream_interface, r] | |
72 | (std::shared_ptr<StreamInterface>* ptr) { | |
73 | ptr->reset(mock_stream_interface); | |
74 | return r; | |
75 | }))); | |
76 | } | |
77 | ||
78 | void expect_stream_open(MockStreamInterface& mock_stream_interface, int r) { | |
79 | EXPECT_CALL(mock_stream_interface, open(_)) | |
80 | .WillOnce(Invoke([r](Context* ctx) { ctx->complete(r); })); | |
81 | } | |
82 | ||
83 | void expect_stream_close(MockStreamInterface& mock_stream_interface, int r) { | |
84 | EXPECT_CALL(mock_stream_interface, close(_)) | |
85 | .WillOnce(Invoke([r](Context* ctx) { ctx->complete(r); })); | |
86 | } | |
87 | ||
88 | void expect_stream_get_size(MockStreamInterface& mock_stream_interface, | |
89 | uint64_t size, int r) { | |
90 | EXPECT_CALL(mock_stream_interface, get_size(_, _)) | |
91 | .WillOnce(Invoke([size, r](uint64_t* out_size, Context* ctx) { | |
92 | *out_size = size; | |
93 | ctx->complete(r); | |
94 | })); | |
95 | } | |
96 | ||
97 | void expect_stream_read(MockStreamInterface& mock_stream_interface, | |
98 | const io::Extents& byte_extents, | |
99 | const bufferlist& bl, int r) { | |
100 | EXPECT_CALL(mock_stream_interface, read(byte_extents, _, _)) | |
101 | .WillOnce(WithArgs<1, 2>(Invoke([bl, r] | |
102 | (bufferlist* out_bl, Context* ctx) { | |
103 | *out_bl = bl; | |
104 | ctx->complete(r); | |
105 | }))); | |
106 | } | |
107 | ||
108 | json_spirit::mObject json_object; | |
109 | }; | |
110 | ||
111 | TEST_F(TestMockMigrationRawSnapshot, OpenClose) { | |
112 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
113 | ||
114 | InSequence seq; | |
115 | MockSourceSpecBuilder mock_source_spec_builder; | |
116 | ||
117 | auto mock_stream_interface = new MockStreamInterface(); | |
118 | expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0); | |
119 | ||
120 | expect_stream_open(*mock_stream_interface, 0); | |
121 | expect_stream_get_size(*mock_stream_interface, 123, 0); | |
122 | ||
123 | expect_stream_close(*mock_stream_interface, 0); | |
124 | ||
125 | json_object["name"] = "snap1"; | |
126 | MockRawSnapshot mock_raw_snapshot(&mock_image_ctx, json_object, | |
127 | &mock_source_spec_builder, 1); | |
128 | ||
129 | C_SaferCond ctx1; | |
130 | mock_raw_snapshot.open(nullptr, &ctx1); | |
131 | ASSERT_EQ(0, ctx1.wait()); | |
132 | ||
133 | auto snap_info = mock_raw_snapshot.get_snap_info(); | |
134 | ASSERT_EQ("snap1", snap_info.name); | |
135 | ASSERT_EQ(123, snap_info.size); | |
136 | ||
137 | C_SaferCond ctx2; | |
138 | mock_raw_snapshot.close(&ctx2); | |
139 | ASSERT_EQ(0, ctx2.wait()); | |
140 | } | |
141 | ||
142 | TEST_F(TestMockMigrationRawSnapshot, OpenError) { | |
143 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
144 | ||
145 | InSequence seq; | |
146 | MockSourceSpecBuilder mock_source_spec_builder; | |
147 | ||
148 | auto mock_stream_interface = new MockStreamInterface(); | |
149 | expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0); | |
150 | ||
151 | expect_stream_open(*mock_stream_interface, -ENOENT); | |
152 | ||
153 | MockRawSnapshot mock_raw_snapshot(&mock_image_ctx, json_object, | |
154 | &mock_source_spec_builder, 0); | |
155 | ||
156 | C_SaferCond ctx; | |
157 | mock_raw_snapshot.open(nullptr, &ctx); | |
158 | ASSERT_EQ(-ENOENT, ctx.wait()); | |
159 | } | |
160 | ||
161 | TEST_F(TestMockMigrationRawSnapshot, GetSizeError) { | |
162 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
163 | ||
164 | InSequence seq; | |
165 | MockSourceSpecBuilder mock_source_spec_builder; | |
166 | ||
167 | auto mock_stream_interface = new MockStreamInterface(); | |
168 | expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0); | |
169 | ||
170 | expect_stream_open(*mock_stream_interface, 0); | |
171 | expect_stream_get_size(*mock_stream_interface, 0, -EINVAL); | |
172 | ||
173 | expect_stream_close(*mock_stream_interface, 0); | |
174 | ||
175 | MockRawSnapshot mock_raw_snapshot(&mock_image_ctx, json_object, | |
176 | &mock_source_spec_builder, 0); | |
177 | ||
178 | C_SaferCond ctx; | |
179 | mock_raw_snapshot.open(nullptr, &ctx); | |
180 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
181 | } | |
182 | ||
183 | TEST_F(TestMockMigrationRawSnapshot, Read) { | |
184 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
185 | ||
186 | InSequence seq; | |
187 | MockSourceSpecBuilder mock_source_spec_builder; | |
188 | ||
189 | auto mock_stream_interface = new MockStreamInterface(); | |
190 | expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0); | |
191 | ||
192 | expect_stream_open(*mock_stream_interface, 0); | |
193 | expect_stream_get_size(*mock_stream_interface, 0, 0); | |
194 | ||
195 | bufferlist expect_bl; | |
196 | expect_bl.append(std::string(123, '1')); | |
197 | expect_stream_read(*mock_stream_interface, {{123, 123}}, expect_bl, 0); | |
198 | ||
199 | expect_stream_close(*mock_stream_interface, 0); | |
200 | ||
201 | MockRawSnapshot mock_raw_snapshot(&mock_image_ctx, json_object, | |
202 | &mock_source_spec_builder, 0); | |
203 | ||
204 | C_SaferCond ctx1; | |
205 | mock_raw_snapshot.open(nullptr, &ctx1); | |
206 | ASSERT_EQ(0, ctx1.wait()); | |
207 | ||
208 | C_SaferCond ctx2; | |
209 | auto aio_comp = io::AioCompletion::create_and_start( | |
210 | &ctx2, m_image_ctx, io::AIO_TYPE_READ); | |
211 | bufferlist bl; | |
212 | io::ReadResult read_result{&bl}; | |
213 | mock_raw_snapshot.read(aio_comp, {{123, 123}}, std::move(read_result), 0, 0, | |
214 | {}); | |
215 | ASSERT_EQ(123, ctx2.wait()); | |
216 | ASSERT_EQ(expect_bl, bl); | |
217 | ||
218 | C_SaferCond ctx3; | |
219 | mock_raw_snapshot.close(&ctx3); | |
220 | ASSERT_EQ(0, ctx3.wait()); | |
221 | } | |
222 | ||
223 | TEST_F(TestMockMigrationRawSnapshot, ListSnap) { | |
224 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
225 | ||
226 | InSequence seq; | |
227 | MockSourceSpecBuilder mock_source_spec_builder; | |
228 | ||
229 | auto mock_stream_interface = new MockStreamInterface(); | |
230 | expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0); | |
231 | ||
232 | expect_stream_open(*mock_stream_interface, 0); | |
233 | expect_stream_get_size(*mock_stream_interface, 0, 0); | |
234 | ||
235 | expect_stream_close(*mock_stream_interface, 0); | |
236 | ||
237 | MockRawSnapshot mock_raw_snapshot(&mock_image_ctx, json_object, | |
238 | &mock_source_spec_builder, 0); | |
239 | ||
240 | C_SaferCond ctx1; | |
241 | mock_raw_snapshot.open(nullptr, &ctx1); | |
242 | ASSERT_EQ(0, ctx1.wait()); | |
243 | ||
244 | C_SaferCond ctx2; | |
245 | io::SparseExtents sparse_extents; | |
246 | mock_raw_snapshot.list_snap({{0, 123}}, 0, &sparse_extents, {}, &ctx2); | |
247 | ASSERT_EQ(0, ctx2.wait()); | |
248 | ||
249 | C_SaferCond ctx3; | |
250 | mock_raw_snapshot.close(&ctx3); | |
251 | ASSERT_EQ(0, ctx3.wait()); | |
252 | } | |
253 | ||
254 | } // namespace migration | |
255 | } // namespace librbd |