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) 2017 Red Hat, Inc.
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.
14 #include "librados/librados_asio.h"
15 #include <gtest/gtest.h>
17 #include "common/ceph_argparse.h"
18 #include "common/debug.h"
19 #include "common/errno.h"
20 #include "global/global_init.h"
22 #define BOOST_COROUTINES_NO_DEPRECATION_WARNING
23 #include <boost/range/begin.hpp>
24 #include <boost/range/end.hpp>
25 #include <boost/asio/spawn.hpp>
26 #include <boost/asio/use_future.hpp>
28 #define dout_subsys ceph_subsys_rados
29 #define dout_context g_ceph_context
33 // test fixture for global setup/teardown
34 class AsioRados
: public ::testing::Test
{
35 static constexpr auto poolname
= "ceph_test_rados_api_asio";
38 static librados::Rados rados
;
39 static librados::IoCtx io
;
40 // writes to snapio fail immediately with -EROFS. this is used to test errors
41 // that come from inside the initiating function, rather than passed to the
42 // AioCompletion callback
43 static librados::IoCtx snapio
;
46 static void SetUpTestCase() {
47 ASSERT_EQ(0, rados
.init_with_context(g_ceph_context
));
48 ASSERT_EQ(0, rados
.connect());
49 // open/create test pool
50 int r
= rados
.ioctx_create(poolname
, io
);
52 r
= rados
.pool_create(poolname
);
56 r
= rados
.ioctx_create(poolname
, io
);
60 ASSERT_EQ(0, rados
.ioctx_create(poolname
, snapio
));
61 snapio
.snap_set_read(1);
62 // initialize the "exist" object
65 ASSERT_EQ(0, io
.write_full("exist", bl
));
68 static void TearDownTestCase() {
72 librados::Rados
AsioRados::rados
;
73 librados::IoCtx
AsioRados::io
;
74 librados::IoCtx
AsioRados::snapio
;
76 TEST_F(AsioRados
, AsyncReadCallback
)
78 boost::asio::io_service service
;
80 auto success_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
82 EXPECT_EQ("hello", bl
.to_str());
84 librados::async_read(service
, io
, "exist", 256, 0, success_cb
);
86 auto failure_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
87 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
89 librados::async_read(service
, io
, "noexist", 256, 0, failure_cb
);
94 TEST_F(AsioRados
, AsyncReadFuture
)
96 boost::asio::io_service service
;
98 std::future
<bufferlist
> f1
= librados::async_read(service
, io
, "exist", 256,
99 0, boost::asio::use_future
);
100 std::future
<bufferlist
> f2
= librados::async_read(service
, io
, "noexist", 256,
101 0, boost::asio::use_future
);
107 EXPECT_EQ("hello", bl
.to_str());
109 EXPECT_THROW(f2
.get(), boost::system::system_error
);
112 TEST_F(AsioRados
, AsyncReadYield
)
114 boost::asio::io_service service
;
116 auto success_cr
= [&] (boost::asio::yield_context yield
) {
117 boost::system::error_code ec
;
118 auto bl
= librados::async_read(service
, io
, "exist", 256, 0, yield
[ec
]);
120 EXPECT_EQ("hello", bl
.to_str());
122 boost::asio::spawn(service
, success_cr
);
124 auto failure_cr
= [&] (boost::asio::yield_context yield
) {
125 boost::system::error_code ec
;
126 auto bl
= librados::async_read(service
, io
, "noexist", 256, 0, yield
[ec
]);
127 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
129 boost::asio::spawn(service
, failure_cr
);
134 TEST_F(AsioRados
, AsyncWriteCallback
)
136 boost::asio::io_service service
;
141 auto success_cb
= [&] (boost::system::error_code ec
) {
144 librados::async_write(service
, io
, "exist", bl
, bl
.length(), 0,
147 auto failure_cb
= [&] (boost::system::error_code ec
) {
148 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
150 librados::async_write(service
, snapio
, "exist", bl
, bl
.length(), 0,
156 TEST_F(AsioRados
, AsyncWriteFuture
)
158 boost::asio::io_service service
;
163 auto f1
= librados::async_write(service
, io
, "exist", bl
, bl
.length(), 0,
164 boost::asio::use_future
);
165 auto f2
= librados::async_write(service
, snapio
, "exist", bl
, bl
.length(), 0,
166 boost::asio::use_future
);
170 EXPECT_NO_THROW(f1
.get());
171 EXPECT_THROW(f2
.get(), boost::system::system_error
);
174 TEST_F(AsioRados
, AsyncWriteYield
)
176 boost::asio::io_service service
;
181 auto success_cr
= [&] (boost::asio::yield_context yield
) {
182 boost::system::error_code ec
;
183 librados::async_write(service
, io
, "exist", bl
, bl
.length(), 0,
186 EXPECT_EQ("hello", bl
.to_str());
188 boost::asio::spawn(service
, success_cr
);
190 auto failure_cr
= [&] (boost::asio::yield_context yield
) {
191 boost::system::error_code ec
;
192 librados::async_write(service
, snapio
, "exist", bl
, bl
.length(), 0,
194 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
196 boost::asio::spawn(service
, failure_cr
);
201 TEST_F(AsioRados
, AsyncReadOperationCallback
)
203 boost::asio::io_service service
;
205 librados::ObjectReadOperation op
;
206 op
.read(0, 0, nullptr, nullptr);
207 auto success_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
209 EXPECT_EQ("hello", bl
.to_str());
211 librados::async_operate(service
, io
, "exist", &op
, 0, success_cb
);
214 librados::ObjectReadOperation op
;
215 op
.read(0, 0, nullptr, nullptr);
216 auto failure_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
217 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
219 librados::async_operate(service
, io
, "noexist", &op
, 0, failure_cb
);
224 TEST_F(AsioRados
, AsyncReadOperationFuture
)
226 boost::asio::io_service service
;
227 std::future
<bufferlist
> f1
;
229 librados::ObjectReadOperation op
;
230 op
.read(0, 0, nullptr, nullptr);
231 f1
= librados::async_operate(service
, io
, "exist", &op
, 0,
232 boost::asio::use_future
);
234 std::future
<bufferlist
> f2
;
236 librados::ObjectReadOperation op
;
237 op
.read(0, 0, nullptr, nullptr);
238 f2
= librados::async_operate(service
, io
, "noexist", &op
, 0,
239 boost::asio::use_future
);
245 EXPECT_EQ("hello", bl
.to_str());
247 EXPECT_THROW(f2
.get(), boost::system::system_error
);
250 TEST_F(AsioRados
, AsyncReadOperationYield
)
252 boost::asio::io_service service
;
254 auto success_cr
= [&] (boost::asio::yield_context yield
) {
255 librados::ObjectReadOperation op
;
256 op
.read(0, 0, nullptr, nullptr);
257 boost::system::error_code ec
;
258 auto bl
= librados::async_operate(service
, io
, "exist", &op
, 0,
261 EXPECT_EQ("hello", bl
.to_str());
263 boost::asio::spawn(service
, success_cr
);
265 auto failure_cr
= [&] (boost::asio::yield_context yield
) {
266 librados::ObjectReadOperation op
;
267 op
.read(0, 0, nullptr, nullptr);
268 boost::system::error_code ec
;
269 auto bl
= librados::async_operate(service
, io
, "noexist", &op
, 0,
271 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
273 boost::asio::spawn(service
, failure_cr
);
278 TEST_F(AsioRados
, AsyncWriteOperationCallback
)
280 boost::asio::io_service service
;
286 librados::ObjectWriteOperation op
;
288 auto success_cb
= [&] (boost::system::error_code ec
) {
291 librados::async_operate(service
, io
, "exist", &op
, 0, success_cb
);
294 librados::ObjectWriteOperation op
;
296 auto failure_cb
= [&] (boost::system::error_code ec
) {
297 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
299 librados::async_operate(service
, snapio
, "exist", &op
, 0, failure_cb
);
304 TEST_F(AsioRados
, AsyncWriteOperationFuture
)
306 boost::asio::io_service service
;
311 std::future
<void> f1
;
313 librados::ObjectWriteOperation op
;
315 f1
= librados::async_operate(service
, io
, "exist", &op
, 0,
316 boost::asio::use_future
);
318 std::future
<void> f2
;
320 librados::ObjectWriteOperation op
;
322 f2
= librados::async_operate(service
, snapio
, "exist", &op
, 0,
323 boost::asio::use_future
);
327 EXPECT_NO_THROW(f1
.get());
328 EXPECT_THROW(f2
.get(), boost::system::system_error
);
331 TEST_F(AsioRados
, AsyncWriteOperationYield
)
333 boost::asio::io_service service
;
338 auto success_cr
= [&] (boost::asio::yield_context yield
) {
339 librados::ObjectWriteOperation op
;
341 boost::system::error_code ec
;
342 librados::async_operate(service
, io
, "exist", &op
, 0, yield
[ec
]);
345 boost::asio::spawn(service
, success_cr
);
347 auto failure_cr
= [&] (boost::asio::yield_context yield
) {
348 librados::ObjectWriteOperation op
;
350 boost::system::error_code ec
;
351 librados::async_operate(service
, snapio
, "exist", &op
, 0, yield
[ec
]);
352 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
354 boost::asio::spawn(service
, failure_cr
);
359 int main(int argc
, char **argv
)
361 auto args
= argv_to_vec(argc
, argv
);
364 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
365 CODE_ENVIRONMENT_UTILITY
, 0);
366 common_init_finish(cct
.get());
368 ::testing::InitGoogleTest(&argc
, argv
);
369 return RUN_ALL_TESTS();