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) 2015 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.
21 #include <boost/algorithm/string.hpp>
24 #include "include/rados/librgw.h"
25 #include "include/rados/rgw_file.h"
28 #include "gtest/gtest.h"
29 #include "common/ceph_argparse.h"
30 #include "common/errno.h"
31 #include "common/debug.h"
32 #include "global/global_init.h"
33 #include "include/ceph_assert.h"
35 #define dout_context g_ceph_context
36 #define dout_subsys ceph_subsys_rgw
44 string
uid("testuser");
45 string
access_key("");
46 string
secret_key("");
48 librgw_t rgw_h
= nullptr;
49 struct rgw_fs
*fs
= nullptr;
51 uint32_t owner_uid
= 867;
52 uint32_t owner_gid
= 5309;
53 uint32_t create_mask
= RGW_SETATTR_UID
| RGW_SETATTR_GID
| RGW_SETATTR_MODE
;
55 string bucket_name
{"v4recov"};
56 string object_path
{"node0/clientids"};
59 string val1
{"metallic"};
61 struct rgw_file_handle
*bucket_fh
= nullptr;
62 struct rgw_file_handle
*object_fh
= nullptr;
64 typedef std::tuple
<string
,uint64_t, struct rgw_file_handle
*> fid_type
;
65 std::vector
<fid_type
> fids
;
71 struct rgw_file_handle
* fh
;
72 struct rgw_file_handle
* parent_fh
;
73 RGWFileHandle
* rgw_fh
; // alias into fh
77 state() : readdir(false) {}
80 obj_rec(string _name
, struct rgw_file_handle
* _fh
,
81 struct rgw_file_handle
* _parent_fh
, RGWFileHandle
* _rgw_fh
)
82 : name(std::move(_name
)), fh(_fh
), parent_fh(_parent_fh
),
92 rgw_fh
= get_rgwfh(fh
);
95 friend ostream
& operator<<(ostream
& os
, const obj_rec
& rec
);
98 [[maybe_unused
]] ostream
& operator<<(ostream
& os
, const obj_rec
& rec
)
100 RGWFileHandle
* rgw_fh
= rec
.rgw_fh
;
102 const char* type
= rgw_fh
->is_dir() ? "DIR " : "FILE ";
103 os
<< rec
.rgw_fh
->full_object_name()
104 << " (" << rec
.rgw_fh
->object_name() << "): "
110 typedef std::vector
<obj_rec
> obj_vec
;
113 bool do_stat
= false;
114 bool do_create
= false;
115 bool do_delete
= false;
116 bool do_hexdump
= false;
117 bool verbose
= false;
126 int ret
= librgw_create(&rgw_h
, saved_args
.argc
, saved_args
.argv
);
128 ASSERT_NE(rgw_h
, nullptr);
131 TEST(LibRGW
, MOUNT
) {
132 int ret
= rgw_mount(rgw_h
, uid
.c_str(), access_key
.c_str(),
133 secret_key
.c_str(), &fs
, RGW_MOUNT_FLAG_NONE
);
135 ASSERT_NE(fs
, nullptr);
138 TEST(LibRGW
, LOOKUP_BUCKET
) {
139 int ret
= rgw_lookup(fs
, fs
->root_fh
, bucket_name
.c_str(), &bucket_fh
,
140 nullptr, 0, RGW_LOOKUP_FLAG_NONE
);
144 TEST(LibRGW
, CREATE_BUCKET
) {
145 if ((! bucket_fh
) && do_create
) {
148 st
.st_uid
= owner_uid
;
149 st
.st_gid
= owner_gid
;
152 int ret
= rgw_mkdir(fs
, fs
->root_fh
, bucket_name
.c_str(), &st
, create_mask
,
153 &bucket_fh
, RGW_MKDIR_FLAG_NONE
);
158 TEST(LibRGW
, CREATE_PATH
) {
164 boost::split(segs
, object_path
, boost::is_any_of("/"));
167 st
.st_uid
= owner_uid
;
168 st
.st_gid
= owner_gid
;
171 int ix
, ret
, sz
= segs
.size();
172 for (ix
= 0; ix
< sz
; ++ix
) {
173 auto& seg
= segs
[ix
];
174 struct rgw_file_handle
* parent_fh
= (ix
> 0) ? ovec
[ix
-1].fh
: bucket_fh
;
175 obj_rec dir
{seg
, nullptr, parent_fh
, nullptr};
177 ret
= rgw_mkdir(fs
, dir
.parent_fh
, dir
.name
.c_str(), &st
, create_mask
,
178 &dir
.fh
, RGW_MKDIR_FLAG_NONE
);
180 ret
= rgw_lookup(fs
, dir
.parent_fh
, dir
.name
.c_str(), &dir
.fh
,
181 nullptr, 0, RGW_LOOKUP_FLAG_NONE
);
187 std::cout
<< "create: " << dir
.name
<< std::endl
;
192 TEST(LibRGW
, CHECK_PATH_REFS
) {
197 int ix
, sz
= ovec
.size();
198 for (ix
= 0; ix
< sz
; ++ix
) {
199 auto& dir
= ovec
[ix
];
201 std::cout
<< "name: " << dir
.name
202 << " refcnt: " << dir
.rgw_fh
->get_refcnt()
206 // sentinel, +1 parent, +1 path
207 ASSERT_EQ(dir
.rgw_fh
->get_refcnt(), 3U);
211 ASSERT_EQ(dir
.rgw_fh
->get_refcnt(), 2U);
216 TEST(LibRGW
, SETXATTR1
) {
221 auto& dir
= ovec
[ovec
.size()-1];
222 rgw_xattrstr xattr_k
= { const_cast<char*>(key1
.c_str()),
223 uint32_t(key1
.length()) };
224 rgw_xattrstr xattr_v
= { const_cast<char*>(val1
.c_str()),
225 uint32_t(val1
.length()) };
227 rgw_xattr xattr
= { xattr_k
, xattr_v
};
228 rgw_xattrlist xattrlist
= { &xattr
, 1 };
230 int ret
= rgw_setxattrs(fs
, dir
.fh
, &xattrlist
, RGW_SETXATTR_FLAG_NONE
);
235 static int getattr_cb(rgw_xattrlist
*attrs
, void *arg
, uint32_t flags
)
238 *(static_cast<std::map
<std::string
, std::string
>*>(arg
));
239 for (uint32_t ix
= 0; ix
< attrs
->xattr_cnt
; ++ix
) {
240 auto& xattr
= attrs
->xattrs
[ix
];
241 string k
{xattr
.key
.val
, xattr
.key
.len
};
242 string v
{xattr
.val
.val
, xattr
.val
.len
};
244 std::cout
<< __func__
245 << " attr k: " << k
<< " v: " << v
248 attrmap
.insert(std::map
<std::string
, std::string
>::value_type(k
, v
));
254 TEST(LibRGW
, GETXATTR1
) {
260 auto& dir
= ovec
[ovec
.size()-1];
262 rgw_xattrstr xattr_k1
=
263 {const_cast<char*>(key1
.c_str()), uint32_t(key1
.length())};
264 rgw_xattrstr xattr_v1
= {nullptr, 0};
266 std::string key2
= "user.rgw.etag";
267 rgw_xattrstr xattr_k2
=
268 {const_cast<char*>(key2
.c_str()), uint32_t(key2
.length())};
269 rgw_xattrstr xattr_v2
= {nullptr, 0};
271 rgw_xattr xattrs
[2] = {{xattr_k1
, xattr_v1
},
272 {xattr_k2
, xattr_v2
}};
274 /* XXX gcc won't accept static_cast here, don't see why */
275 rgw_xattrlist xattrlist
= {reinterpret_cast<rgw_xattr
*>(&xattrs
), 2};
277 std::map
<std::string
, std::string
> out_attrmap
;
279 int ret
= rgw_getxattrs(fs
, dir
.fh
, &xattrlist
, getattr_cb
, &out_attrmap
,
280 RGW_GETXATTR_FLAG_NONE
);
282 /* check exposed attrs */
283 ASSERT_TRUE(out_attrmap
.find("user.rgw.etag") != out_attrmap
.end());
284 /* check our user attr */
285 ASSERT_TRUE(out_attrmap
.find(key1
) != out_attrmap
.end());
288 TEST(LibRGW
, LSXATTR1
) {
294 auto& dir
= ovec
[ovec
.size()-1];
296 rgw_xattrstr filter_prefix
= { nullptr, 0}; // XXX ignored, for now
298 std::map
<std::string
, std::string
> out_attrmap
;
300 int ret
= rgw_lsxattrs(fs
, dir
.fh
, &filter_prefix
, getattr_cb
,
301 &out_attrmap
, RGW_LSXATTR_FLAG_NONE
);
304 /* check exposed attrs */
305 ASSERT_TRUE(out_attrmap
.find("user.rgw.etag") != out_attrmap
.end());
308 TEST(LibRGW
, RMXATTR1
) {
314 auto& dir
= ovec
[ovec
.size()-1];
316 rgw_xattrstr xattr_k
= { const_cast<char*>(key1
.c_str()),
317 uint32_t(key1
.length()) };
318 rgw_xattrstr xattr_v
= { nullptr, 0 };
320 rgw_xattr xattr
= { xattr_k
, xattr_v
};
321 rgw_xattrlist xattrlist
= { &xattr
, 1 };
323 int ret
= rgw_rmxattrs(fs
, dir
.fh
, &xattrlist
, RGW_RMXATTR_FLAG_NONE
);
327 TEST(LibRGW
, LSXATTR2
) {
333 auto& dir
= ovec
[ovec
.size()-1];
335 rgw_xattrstr filter_prefix
= { nullptr, 0 }; // XXX ignored, for now
337 std::map
<std::string
, std::string
> out_attrmap
;
339 int ret
= rgw_lsxattrs(fs
, dir
.fh
, &filter_prefix
, getattr_cb
,
340 &out_attrmap
, RGW_LSXATTR_FLAG_NONE
);
342 /* check exposed attrs */
343 ASSERT_TRUE(out_attrmap
.find("user.rgw.etag") != out_attrmap
.end());
344 /* verify deletion */
345 ASSERT_TRUE(out_attrmap
.find(key1
) == out_attrmap
.end());
348 TEST(LibRGW
, CLEANUP
) {
351 ret
= rgw_fh_rele(fs
, object_fh
, 0 /* flags */);
355 ret
= rgw_fh_rele(fs
, bucket_fh
, 0 /* flags */);
360 TEST(LibRGW
, UMOUNT
) {
364 int ret
= rgw_umount(fs
, RGW_UMOUNT_FLAG_NONE
);
368 TEST(LibRGW
, SHUTDOWN
) {
369 librgw_shutdown(rgw_h
);
372 int main(int argc
, char *argv
[])
374 auto args
= argv_to_vec(argc
, argv
);
377 char* v
= getenv("AWS_ACCESS_KEY_ID");
382 v
= getenv("AWS_SECRET_ACCESS_KEY");
388 for (auto arg_iter
= args
.begin(); arg_iter
!= args
.end();) {
389 if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--access",
392 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--secret",
395 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--uid",
398 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--bn",
401 } else if (ceph_argparse_flag(args
, arg_iter
, "--stat",
404 } else if (ceph_argparse_flag(args
, arg_iter
, "--create",
407 } else if (ceph_argparse_flag(args
, arg_iter
, "--delete",
410 } else if (ceph_argparse_flag(args
, arg_iter
, "--hexdump",
413 } else if (ceph_argparse_flag(args
, arg_iter
, "--verbose",
421 /* dont accidentally run as anonymous */
422 if ((access_key
== "") ||
423 (secret_key
== "")) {
424 std::cout
<< argv
[0] << " no AWS credentials, exiting" << std::endl
;
428 saved_args
.argc
= argc
;
429 saved_args
.argv
= argv
;
431 ::testing::InitGoogleTest(&argc
, argv
);
432 return RUN_ALL_TESTS();