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 #include <boost/range/begin.hpp>
23 #include <boost/range/end.hpp>
24 #include <spawn/spawn.hpp>
25 #include <boost/asio/use_future.hpp>
27 #define dout_subsys ceph_subsys_rados
28 #define dout_context g_ceph_context
32 // test fixture for global setup/teardown
33 class AsioRados
: public ::testing::Test
{
34 static constexpr auto poolname
= "ceph_test_rados_api_asio";
37 static librados::Rados rados
;
38 static librados::IoCtx io
;
39 // writes to snapio fail immediately with -EROFS. this is used to test errors
40 // that come from inside the initiating function, rather than passed to the
41 // AioCompletion callback
42 static librados::IoCtx snapio
;
45 static void SetUpTestCase() {
46 ASSERT_EQ(0, rados
.init_with_context(g_ceph_context
));
47 ASSERT_EQ(0, rados
.connect());
48 // open/create test pool
49 int r
= rados
.ioctx_create(poolname
, io
);
51 r
= rados
.pool_create(poolname
);
55 r
= rados
.ioctx_create(poolname
, io
);
59 ASSERT_EQ(0, rados
.ioctx_create(poolname
, snapio
));
60 snapio
.snap_set_read(1);
61 // initialize the "exist" object
64 ASSERT_EQ(0, io
.write_full("exist", bl
));
67 static void TearDownTestCase() {
71 librados::Rados
AsioRados::rados
;
72 librados::IoCtx
AsioRados::io
;
73 librados::IoCtx
AsioRados::snapio
;
75 TEST_F(AsioRados
, AsyncReadCallback
)
77 boost::asio::io_service service
;
79 auto success_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
81 EXPECT_EQ("hello", bl
.to_str());
83 librados::async_read(service
, io
, "exist", 256, 0, success_cb
);
85 auto failure_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
86 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
88 librados::async_read(service
, io
, "noexist", 256, 0, failure_cb
);
93 TEST_F(AsioRados
, AsyncReadFuture
)
95 boost::asio::io_service service
;
97 std::future
<bufferlist
> f1
= librados::async_read(service
, io
, "exist", 256,
98 0, boost::asio::use_future
);
99 std::future
<bufferlist
> f2
= librados::async_read(service
, io
, "noexist", 256,
100 0, boost::asio::use_future
);
106 EXPECT_EQ("hello", bl
.to_str());
108 EXPECT_THROW(f2
.get(), boost::system::system_error
);
111 TEST_F(AsioRados
, AsyncReadYield
)
113 boost::asio::io_service service
;
115 auto success_cr
= [&] (spawn::yield_context yield
) {
116 boost::system::error_code ec
;
117 auto bl
= librados::async_read(service
, io
, "exist", 256, 0, yield
[ec
]);
119 EXPECT_EQ("hello", bl
.to_str());
121 spawn::spawn(service
, success_cr
);
123 auto failure_cr
= [&] (spawn::yield_context yield
) {
124 boost::system::error_code ec
;
125 auto bl
= librados::async_read(service
, io
, "noexist", 256, 0, yield
[ec
]);
126 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
128 spawn::spawn(service
, failure_cr
);
133 TEST_F(AsioRados
, AsyncWriteCallback
)
135 boost::asio::io_service service
;
140 auto success_cb
= [&] (boost::system::error_code ec
) {
143 librados::async_write(service
, io
, "exist", bl
, bl
.length(), 0,
146 auto failure_cb
= [&] (boost::system::error_code ec
) {
147 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
149 librados::async_write(service
, snapio
, "exist", bl
, bl
.length(), 0,
155 TEST_F(AsioRados
, AsyncWriteFuture
)
157 boost::asio::io_service service
;
162 auto f1
= librados::async_write(service
, io
, "exist", bl
, bl
.length(), 0,
163 boost::asio::use_future
);
164 auto f2
= librados::async_write(service
, snapio
, "exist", bl
, bl
.length(), 0,
165 boost::asio::use_future
);
169 EXPECT_NO_THROW(f1
.get());
170 EXPECT_THROW(f2
.get(), boost::system::system_error
);
173 TEST_F(AsioRados
, AsyncWriteYield
)
175 boost::asio::io_service service
;
180 auto success_cr
= [&] (spawn::yield_context yield
) {
181 boost::system::error_code ec
;
182 librados::async_write(service
, io
, "exist", bl
, bl
.length(), 0,
185 EXPECT_EQ("hello", bl
.to_str());
187 spawn::spawn(service
, success_cr
);
189 auto failure_cr
= [&] (spawn::yield_context yield
) {
190 boost::system::error_code ec
;
191 librados::async_write(service
, snapio
, "exist", bl
, bl
.length(), 0,
193 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
195 spawn::spawn(service
, failure_cr
);
200 TEST_F(AsioRados
, AsyncReadOperationCallback
)
202 boost::asio::io_service service
;
204 librados::ObjectReadOperation op
;
205 op
.read(0, 0, nullptr, nullptr);
206 auto success_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
208 EXPECT_EQ("hello", bl
.to_str());
210 librados::async_operate(service
, io
, "exist", &op
, 0, success_cb
);
213 librados::ObjectReadOperation op
;
214 op
.read(0, 0, nullptr, nullptr);
215 auto failure_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
216 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
218 librados::async_operate(service
, io
, "noexist", &op
, 0, failure_cb
);
223 TEST_F(AsioRados
, AsyncReadOperationFuture
)
225 boost::asio::io_service service
;
226 std::future
<bufferlist
> f1
;
228 librados::ObjectReadOperation op
;
229 op
.read(0, 0, nullptr, nullptr);
230 f1
= librados::async_operate(service
, io
, "exist", &op
, 0,
231 boost::asio::use_future
);
233 std::future
<bufferlist
> f2
;
235 librados::ObjectReadOperation op
;
236 op
.read(0, 0, nullptr, nullptr);
237 f2
= librados::async_operate(service
, io
, "noexist", &op
, 0,
238 boost::asio::use_future
);
244 EXPECT_EQ("hello", bl
.to_str());
246 EXPECT_THROW(f2
.get(), boost::system::system_error
);
249 TEST_F(AsioRados
, AsyncReadOperationYield
)
251 boost::asio::io_service service
;
253 auto success_cr
= [&] (spawn::yield_context yield
) {
254 librados::ObjectReadOperation op
;
255 op
.read(0, 0, nullptr, nullptr);
256 boost::system::error_code ec
;
257 auto bl
= librados::async_operate(service
, io
, "exist", &op
, 0,
260 EXPECT_EQ("hello", bl
.to_str());
262 spawn::spawn(service
, success_cr
);
264 auto failure_cr
= [&] (spawn::yield_context yield
) {
265 librados::ObjectReadOperation op
;
266 op
.read(0, 0, nullptr, nullptr);
267 boost::system::error_code ec
;
268 auto bl
= librados::async_operate(service
, io
, "noexist", &op
, 0,
270 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
272 spawn::spawn(service
, failure_cr
);
277 TEST_F(AsioRados
, AsyncWriteOperationCallback
)
279 boost::asio::io_service service
;
285 librados::ObjectWriteOperation op
;
287 auto success_cb
= [&] (boost::system::error_code ec
) {
290 librados::async_operate(service
, io
, "exist", &op
, 0, success_cb
);
293 librados::ObjectWriteOperation op
;
295 auto failure_cb
= [&] (boost::system::error_code ec
) {
296 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
298 librados::async_operate(service
, snapio
, "exist", &op
, 0, failure_cb
);
303 TEST_F(AsioRados
, AsyncWriteOperationFuture
)
305 boost::asio::io_service service
;
310 std::future
<void> f1
;
312 librados::ObjectWriteOperation op
;
314 f1
= librados::async_operate(service
, io
, "exist", &op
, 0,
315 boost::asio::use_future
);
317 std::future
<void> f2
;
319 librados::ObjectWriteOperation op
;
321 f2
= librados::async_operate(service
, snapio
, "exist", &op
, 0,
322 boost::asio::use_future
);
326 EXPECT_NO_THROW(f1
.get());
327 EXPECT_THROW(f2
.get(), boost::system::system_error
);
330 TEST_F(AsioRados
, AsyncWriteOperationYield
)
332 boost::asio::io_service service
;
337 auto success_cr
= [&] (spawn::yield_context yield
) {
338 librados::ObjectWriteOperation op
;
340 boost::system::error_code ec
;
341 librados::async_operate(service
, io
, "exist", &op
, 0, yield
[ec
]);
344 spawn::spawn(service
, success_cr
);
346 auto failure_cr
= [&] (spawn::yield_context yield
) {
347 librados::ObjectWriteOperation op
;
349 boost::system::error_code ec
;
350 librados::async_operate(service
, snapio
, "exist", &op
, 0, yield
[ec
]);
351 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
353 spawn::spawn(service
, failure_cr
);
358 int main(int argc
, char **argv
)
360 auto args
= argv_to_vec(argc
, argv
);
363 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
364 CODE_ENVIRONMENT_UTILITY
, 0);
365 common_init_finish(cct
.get());
367 ::testing::InitGoogleTest(&argc
, argv
);
368 return RUN_ALL_TESTS();