]>
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 "include/rbd_types.h" | |
7 | #include "common/ceph_mutex.h" | |
8 | #include "librbd/migration/HttpClient.h" | |
9 | #include "librbd/migration/S3Stream.h" | |
10 | #include "gtest/gtest.h" | |
11 | #include "gmock/gmock.h" | |
12 | #include "json_spirit/json_spirit.h" | |
13 | #include <boost/algorithm/string/predicate.hpp> | |
14 | #include <boost/beast/http.hpp> | |
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 HttpClient<MockTestImageCtx> { | |
30 | static HttpClient* s_instance; | |
31 | static HttpClient* create(MockTestImageCtx*, const std::string&) { | |
32 | ceph_assert(s_instance != nullptr); | |
33 | return s_instance; | |
34 | } | |
35 | ||
36 | HttpProcessorInterface* http_processor = nullptr; | |
37 | void set_http_processor(HttpProcessorInterface* http_processor) { | |
38 | this->http_processor = http_processor; | |
39 | } | |
40 | ||
41 | MOCK_METHOD1(open, void(Context*)); | |
42 | MOCK_METHOD1(close, void(Context*)); | |
43 | MOCK_METHOD2(get_size, void(uint64_t*, Context*)); | |
44 | MOCK_METHOD3(do_read, void(const io::Extents&, bufferlist*, Context*)); | |
45 | void read(io::Extents&& extents, bufferlist* bl, Context* ctx) { | |
46 | do_read(extents, bl, ctx); | |
47 | } | |
48 | ||
49 | HttpClient() { | |
50 | s_instance = this; | |
51 | } | |
52 | }; | |
53 | ||
54 | HttpClient<MockTestImageCtx>* HttpClient<MockTestImageCtx>::s_instance = nullptr; | |
55 | ||
56 | } // namespace migration | |
57 | } // namespace librbd | |
58 | ||
59 | #include "librbd/migration/S3Stream.cc" | |
60 | ||
61 | namespace librbd { | |
62 | namespace migration { | |
63 | ||
64 | using ::testing::_; | |
65 | using ::testing::Invoke; | |
66 | using ::testing::InSequence; | |
67 | using ::testing::WithArgs; | |
68 | ||
69 | class TestMockMigrationS3Stream : public TestMockFixture { | |
70 | public: | |
71 | typedef S3Stream<MockTestImageCtx> MockS3Stream; | |
72 | typedef HttpClient<MockTestImageCtx> MockHttpClient; | |
73 | ||
74 | using EmptyBody = boost::beast::http::empty_body; | |
75 | using EmptyRequest = boost::beast::http::request<EmptyBody>; | |
76 | ||
77 | librbd::ImageCtx *m_image_ctx; | |
78 | ||
79 | void SetUp() override { | |
80 | TestMockFixture::SetUp(); | |
81 | ||
82 | ASSERT_EQ(0, open_image(m_image_name, &m_image_ctx)); | |
83 | json_object["url"] = "http://some.site/bucket/file"; | |
84 | json_object["access_key"] = "0555b35654ad1656d804"; | |
85 | json_object["secret_key"] = "h7GhxuBLTrlhVUyxSPUKUV8r/2EI4ngqJxD7iBdBYLhwluN30JaT3Q=="; | |
86 | } | |
87 | ||
88 | void expect_open(MockHttpClient& mock_http_client, int r) { | |
89 | EXPECT_CALL(mock_http_client, open(_)) | |
90 | .WillOnce(Invoke([r](Context* ctx) { ctx->complete(r); })); | |
91 | } | |
92 | ||
93 | void expect_close(MockHttpClient& mock_http_client, int r) { | |
94 | EXPECT_CALL(mock_http_client, close(_)) | |
95 | .WillOnce(Invoke([r](Context* ctx) { ctx->complete(r); })); | |
96 | } | |
97 | ||
98 | void expect_get_size(MockHttpClient& mock_http_client, uint64_t size, int r) { | |
99 | EXPECT_CALL(mock_http_client, get_size(_, _)) | |
100 | .WillOnce(Invoke([size, r](uint64_t* out_size, Context* ctx) { | |
101 | *out_size = size; | |
102 | ctx->complete(r); | |
103 | })); | |
104 | } | |
105 | ||
106 | void expect_read(MockHttpClient& mock_http_client, io::Extents byte_extents, | |
107 | const bufferlist& bl, int r) { | |
108 | uint64_t len = 0; | |
109 | for (auto [_, byte_len] : byte_extents) { | |
110 | len += byte_len; | |
111 | } | |
112 | EXPECT_CALL(mock_http_client, do_read(byte_extents, _, _)) | |
113 | .WillOnce(WithArgs<1, 2>(Invoke( | |
114 | [len, bl, r](bufferlist* out_bl, Context* ctx) { | |
115 | *out_bl = bl; | |
116 | ctx->complete(r < 0 ? r : len); | |
117 | }))); | |
118 | } | |
119 | ||
120 | json_spirit::mObject json_object; | |
121 | }; | |
122 | ||
123 | TEST_F(TestMockMigrationS3Stream, OpenClose) { | |
124 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
125 | ||
126 | InSequence seq; | |
127 | ||
128 | auto mock_http_client = new MockHttpClient(); | |
129 | expect_open(*mock_http_client, 0); | |
130 | ||
131 | expect_close(*mock_http_client, 0); | |
132 | ||
133 | MockS3Stream mock_http_stream(&mock_image_ctx, json_object); | |
134 | ||
135 | C_SaferCond ctx1; | |
136 | mock_http_stream.open(&ctx1); | |
137 | ASSERT_EQ(0, ctx1.wait()); | |
138 | ||
139 | C_SaferCond ctx2; | |
140 | mock_http_stream.close(&ctx2); | |
141 | ASSERT_EQ(0, ctx2.wait()); | |
142 | } | |
143 | ||
144 | TEST_F(TestMockMigrationS3Stream, GetSize) { | |
145 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
146 | ||
147 | InSequence seq; | |
148 | ||
149 | auto mock_http_client = new MockHttpClient(); | |
150 | expect_open(*mock_http_client, 0); | |
151 | ||
152 | expect_get_size(*mock_http_client, 128, 0); | |
153 | ||
154 | expect_close(*mock_http_client, 0); | |
155 | ||
156 | MockS3Stream mock_http_stream(&mock_image_ctx, json_object); | |
157 | ||
158 | C_SaferCond ctx1; | |
159 | mock_http_stream.open(&ctx1); | |
160 | ASSERT_EQ(0, ctx1.wait()); | |
161 | ||
162 | C_SaferCond ctx2; | |
163 | uint64_t size; | |
164 | mock_http_stream.get_size(&size, &ctx2); | |
165 | ASSERT_EQ(0, ctx2.wait()); | |
166 | ASSERT_EQ(128, size); | |
167 | ||
168 | C_SaferCond ctx3; | |
169 | mock_http_stream.close(&ctx3); | |
170 | ASSERT_EQ(0, ctx3.wait()); | |
171 | } | |
172 | ||
173 | TEST_F(TestMockMigrationS3Stream, Read) { | |
174 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
175 | ||
176 | InSequence seq; | |
177 | ||
178 | auto mock_http_client = new MockHttpClient(); | |
179 | expect_open(*mock_http_client, 0); | |
180 | ||
181 | bufferlist expect_bl; | |
182 | expect_bl.append(std::string(192, '1')); | |
183 | expect_read(*mock_http_client, {{0, 128}, {256, 64}}, expect_bl, 0); | |
184 | ||
185 | expect_close(*mock_http_client, 0); | |
186 | ||
187 | MockS3Stream mock_http_stream(&mock_image_ctx, json_object); | |
188 | ||
189 | C_SaferCond ctx1; | |
190 | mock_http_stream.open(&ctx1); | |
191 | ASSERT_EQ(0, ctx1.wait()); | |
192 | ||
193 | C_SaferCond ctx2; | |
194 | bufferlist bl; | |
195 | mock_http_stream.read({{0, 128}, {256, 64}}, &bl, &ctx2); | |
196 | ASSERT_EQ(192, ctx2.wait()); | |
197 | ASSERT_EQ(expect_bl, bl); | |
198 | ||
199 | C_SaferCond ctx3; | |
200 | mock_http_stream.close(&ctx3); | |
201 | ASSERT_EQ(0, ctx3.wait()); | |
202 | } | |
203 | ||
204 | TEST_F(TestMockMigrationS3Stream, ProcessRequest) { | |
205 | MockTestImageCtx mock_image_ctx(*m_image_ctx); | |
206 | ||
207 | InSequence seq; | |
208 | ||
209 | auto mock_http_client = new MockHttpClient(); | |
210 | expect_open(*mock_http_client, 0); | |
211 | ||
212 | expect_close(*mock_http_client, 0); | |
213 | ||
214 | MockS3Stream mock_http_stream(&mock_image_ctx, json_object); | |
215 | ||
216 | C_SaferCond ctx1; | |
217 | mock_http_stream.open(&ctx1); | |
218 | ASSERT_EQ(0, ctx1.wait()); | |
219 | ||
220 | EmptyRequest request; | |
221 | request.method(boost::beast::http::verb::get); | |
222 | request.target("/bucket/resource"); | |
223 | mock_http_client->http_processor->process_request(request); | |
224 | ||
225 | // basic test for date and known portion of authorization | |
226 | ASSERT_EQ(1U, request.count(boost::beast::http::field::date)); | |
227 | ASSERT_EQ(1U, request.count(boost::beast::http::field::authorization)); | |
228 | ASSERT_TRUE(boost::algorithm::starts_with( | |
229 | request[boost::beast::http::field::authorization], | |
230 | "AWS 0555b35654ad1656d804:")); | |
231 | ||
232 | C_SaferCond ctx2; | |
233 | mock_http_stream.close(&ctx2); | |
234 | ASSERT_EQ(0, ctx2.wait()); | |
235 | } | |
236 | ||
237 | } // namespace migration | |
238 | } // namespace librbd |