]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/migration/test_mock_S3Stream.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / test / librbd / migration / test_mock_S3Stream.cc
CommitLineData
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
16namespace librbd {
17namespace {
18
19struct MockTestImageCtx : public MockImageCtx {
20 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
21 }
22};
23
24} // anonymous namespace
25
26namespace migration {
27
28template <>
29struct 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
54HttpClient<MockTestImageCtx>* HttpClient<MockTestImageCtx>::s_instance = nullptr;
55
56} // namespace migration
57} // namespace librbd
58
59#include "librbd/migration/S3Stream.cc"
60
61namespace librbd {
62namespace migration {
63
64using ::testing::_;
65using ::testing::Invoke;
66using ::testing::InSequence;
67using ::testing::WithArgs;
68
69class TestMockMigrationS3Stream : public TestMockFixture {
70public:
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
123TEST_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
144TEST_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
173TEST_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
204TEST_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