]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/librgw_file_nfsns.cc
1731491ba720226d2bf28c684e508100b004797b
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 "include/rados/librgw.h"
22 #include "include/rados/rgw_file.h"
23 #include "rgw/rgw_file.h"
24 #include "rgw/rgw_lib_frontend.h" // direct requests
26 #include "gtest/gtest.h"
27 #include "common/ceph_argparse.h"
28 #include "common/debug.h"
29 #include "global/global_init.h"
30 #include "include/assert.h"
32 #define dout_subsys ceph_subsys_rgw
40 librgw_t rgw_h
= nullptr;
41 string
userid("testuser");
42 string
access_key("");
43 string
secret_key("");
44 struct rgw_fs
*fs
= nullptr;
45 CephContext
* cct
= nullptr;
47 uint32_t owner_uid
= 867;
48 uint32_t owner_gid
= 5309;
50 uint32_t magic_uid
= 1701;
51 uint32_t magic_gid
= 9876;
53 uint32_t create_mask
= RGW_SETATTR_UID
| RGW_SETATTR_GID
| RGW_SETATTR_MODE
;
55 string
bucket_name("nfsroot");
56 string
dirs1_bucket_name("bdirs1");
57 string
readf_name("toyland");
58 string
readf_out_name("rgwlib_readf.out");
59 std::string writef_name
{"bigbird"};
68 struct rgw_file_handle
* fh
;
69 struct rgw_file_handle
* parent_fh
;
70 RGWFileHandle
* rgw_fh
; // alias into fh
74 state() : readdir(false) {}
77 obj_rec(string _name
, struct rgw_file_handle
* _fh
,
78 struct rgw_file_handle
* _parent_fh
, RGWFileHandle
* _rgw_fh
)
79 : name(std::move(_name
)), fh(_fh
), parent_fh(_parent_fh
),
89 rgw_fh
= get_rgwfh(fh
);
92 friend ostream
& operator<<(ostream
& os
, const obj_rec
& rec
);
95 ostream
& operator<<(ostream
& os
, const obj_rec
& rec
)
97 RGWFileHandle
* rgw_fh
= rec
.rgw_fh
;
99 const char* type
= rgw_fh
->is_dir() ? "DIR " : "FILE ";
100 os
<< rec
.rgw_fh
->full_object_name()
101 << " (" << rec
.rgw_fh
->object_name() << "): "
107 std::stack
<obj_rec
> obj_stack
;
108 std::deque
<obj_rec
> cleanup_queue
;
110 typedef std::vector
<obj_rec
> obj_vec
;
111 typedef std::tuple
<obj_rec
, obj_vec
> dirs1_rec
;
112 typedef std::vector
<dirs1_rec
> dirs1_vec
;
119 const struct stat
& st
;
121 obj_rec_st(const obj_rec
& _obj
, const struct stat
& _st
)
122 : obj(_obj
), st(_st
) {}
125 ostream
& operator<<(ostream
& os
, const obj_rec_st
& rec
)
127 RGWFileHandle
* rgw_fh
= rec
.obj
.rgw_fh
;
129 const char* type
= rgw_fh
->is_dir() ? "DIR " : "FILE ";
130 os
<< rgw_fh
->full_object_name()
131 << " (" << rgw_fh
->object_name() << "): "
133 const struct stat
& st
= rec
.st
;
134 switch(uint8_t(rgw_fh
->is_dir())) {
136 os
<< " mode: " << st
.st_mode
;
137 os
<< " nlinks: " << st
.st_nlink
;
141 os
<< " mode: " << st
.st_mode
;
142 os
<< " size: " << st
.st_size
;
150 bool do_hier1
= false;
151 bool do_dirs1
= false;
152 bool do_readf
= false;
153 bool do_writef
= false;
154 bool do_marker1
= false;
155 bool do_create
= false;
156 bool do_delete
= false;
157 bool do_rename
= false;
158 bool do_setattr
= false;
159 bool verbose
= false;
161 string
marker_dir("nfs_marker");
162 struct rgw_file_handle
*bucket_fh
= nullptr;
163 struct rgw_file_handle
*marker_fh
;
164 static constexpr int marker_nobjs
= 2*1024;
165 std::deque
<obj_rec
> marker_objs
;
167 using dirent_t
= std::tuple
<std::string
, uint64_t>;
170 std::vector
<dirent_t
> obj_names
;
172 dirent_vec() : count(0) {}
175 obj_rec dirs1_b
{dirs1_bucket_name
, nullptr, nullptr, nullptr};
177 dirs1_vec renames_vec
;
186 int ret
= librgw_create(&rgw_h
, saved_args
.argc
, saved_args
.argv
);
188 ASSERT_NE(rgw_h
, nullptr);
191 TEST(LibRGW
, MOUNT
) {
192 int ret
= rgw_mount(rgw_h
, userid
.c_str(), access_key
.c_str(),
193 secret_key
.c_str(), &fs
, RGW_MOUNT_FLAG_NONE
);
195 ASSERT_NE(fs
, nullptr);
197 cct
= static_cast<RGWLibFS
*>(fs
->fs_private
)->get_context();
200 TEST(LibRGW
, SETUP_HIER1
)
203 (void) rgw_lookup(fs
, fs
->root_fh
, bucket_name
.c_str(), &bucket_fh
,
204 RGW_LOOKUP_FLAG_NONE
);
209 st
.st_uid
= owner_uid
;
210 st
.st_gid
= owner_gid
;
213 int rc
= rgw_mkdir(fs
, fs
->root_fh
, bucket_name
.c_str(), &st
,
214 create_mask
, &bucket_fh
, RGW_MKDIR_FLAG_NONE
);
219 ASSERT_NE(bucket_fh
, nullptr);
222 /* create objects directly */
223 std::vector
<std::string
> obj_names
=
229 "foo/bar/baz/hungry",
230 "foo/bar/baz/hungry/",
233 "foo/bar/baz/sasquatch",
234 "foo/bar/baz/sasquatch/",
235 "foo/bar/baz/frobozz"};
237 buffer::list bl
; // empty object
238 RGWLibFS
*fs_private
= static_cast<RGWLibFS
*>(fs
->fs_private
);
240 for (const auto& obj_name
: obj_names
) {
242 std::cout
<< "creating: " << bucket_name
<< ":" << obj_name
245 RGWPutObjRequest
req(cct
, fs_private
->get_user(), bucket_name
, obj_name
,
247 int rc
= rgwlib
.get_fe()->execute_req(&req
);
248 int rc2
= req
.get_ret();
256 TEST(LibRGW
, SETUP_DIRS1
) {
261 st
.st_uid
= owner_uid
;
262 st
.st_gid
= owner_gid
;
265 dirs1_b
.parent_fh
= fs
->root_fh
;
267 (void) rgw_lookup(fs
, dirs1_b
.parent_fh
, dirs1_bucket_name
.c_str(),
268 &dirs1_b
.fh
, RGW_LOOKUP_FLAG_NONE
);
272 rc
= rgw_mkdir(fs
, dirs1_b
.parent_fh
, dirs1_b
.name
.c_str(), &st
,
273 create_mask
, &dirs1_b
.fh
, RGW_MKDIR_FLAG_NONE
);
276 /* no top-level dir and can't create it--skip remaining tests */
282 /* make top-level dirs */
285 for (d_ix
= 0; d_ix
< n_dirs1_dirs
; ++d_ix
) {
286 std::string dname
{"dir_"};
287 dname
+= to_string(d_ix
);
288 obj_rec dir
{dname
, nullptr, dirs1_b
.fh
, nullptr};
291 (void) rgw_lookup(fs
, dir
.parent_fh
, dir
.name
.c_str(), &dir
.fh
,
292 RGW_LOOKUP_FLAG_NONE
);
295 rc
= rgw_mkdir(fs
, dir
.parent_fh
, dir
.name
.c_str(), &st
, create_mask
,
296 &dir
.fh
, RGW_MKDIR_FLAG_NONE
);
301 ASSERT_NE(dir
.fh
, nullptr);
303 ASSERT_NE(dir
.rgw_fh
, nullptr);
304 ASSERT_TRUE(dir
.rgw_fh
->is_dir());
307 for (f_ix
= 0; f_ix
< n_dirs1_objs
; ++f_ix
) {
309 std::string sdname
{"sdir_"};
310 sdname
+= to_string(f_ix
);
311 obj_rec sdir
{sdname
, nullptr, dir
.fh
, nullptr};
313 (void) rgw_lookup(fs
, sdir
.parent_fh
, sdir
.name
.c_str(), &sdir
.fh
,
314 RGW_LOOKUP_FLAG_NONE
);
318 rc
= rgw_mkdir(fs
, sdir
.parent_fh
, sdir
.name
.c_str(), &st
,
319 create_mask
, &sdir
.fh
, RGW_MKDIR_FLAG_NONE
);
324 ASSERT_NE(sdir
.fh
, nullptr); // suppress !lookup && !create case
327 ASSERT_TRUE(sdir
.rgw_fh
->is_dir());
328 ovec
.push_back(sdir
);
331 std::string sfname
{"sfile_"};
333 sfname
+= to_string(f_ix
);
334 obj_rec sf
{sfname
, nullptr, dir
.fh
, nullptr};
336 (void) rgw_lookup(fs
, sf
.parent_fh
, sf
.name
.c_str(), &sf
.fh
,
337 RGW_LOOKUP_FLAG_NONE
);
341 /* make a new file object (the hard way) */
342 rc
= rgw_lookup(fs
, sf
.parent_fh
, sf
.name
.c_str(), &sf
.fh
,
343 RGW_LOOKUP_FLAG_CREATE
);
346 ASSERT_TRUE(sf
.rgw_fh
->is_file());
348 /* because we made it the hard way, fixup attributes */
350 st
.st_uid
= owner_uid
;
351 st
.st_gid
= owner_gid
;
353 sf
.rgw_fh
->create_stat(&st
, create_mask
);
356 rc
= rgw_open(fs
, sf
.fh
, 0 /* posix flags */, 0 /* flags */);
358 ASSERT_TRUE(sf
.rgw_fh
->is_open());
359 /* stage seq write */
361 string data
= "data for " + sf
.name
;
362 rc
= rgw_write(fs
, sf
.fh
, 0, data
.length(), &nbytes
,
363 (void*) data
.c_str(), RGW_WRITE_FLAG_NONE
);
365 ASSERT_EQ(nbytes
, data
.length());
366 /* commit write transaction */
367 rc
= rgw_close(fs
, sf
.fh
, 0 /* flags */);
372 ASSERT_TRUE(sf
.rgw_fh
->is_file());
378 dirs_vec
.push_back(dirs1_rec
{dir
, ovec
});
380 } /* dirs1 top-level !exist */
383 TEST(LibRGW
, SETATTR
) {
390 st
.st_uid
= owner_uid
;
391 st
.st_gid
= owner_gid
;
394 std::string dname
{"dir_0"};
395 obj_rec dir
{dname
, nullptr, dirs1_b
.fh
, nullptr};
397 /* dir_0 MUST exist and MUST be resident */
398 (void) rgw_lookup(fs
, dir
.parent_fh
, dir
.name
.c_str(), &dir
.fh
,
399 RGW_LOOKUP_FLAG_NONE
);
401 ASSERT_NE(dir
.fh
, nullptr);
403 ASSERT_NE(dir
.rgw_fh
, nullptr);
404 ASSERT_TRUE(dir
.rgw_fh
->is_dir());
407 std::string sfname
{"setattr_file_0"};
408 obj_rec sf
{sfname
, nullptr, dir
.fh
, nullptr};
410 (void) rgw_lookup(fs
, sf
.parent_fh
, sf
.name
.c_str(), &sf
.fh
,
411 RGW_LOOKUP_FLAG_NONE
);
414 /* make a new file object (the hard way) */
415 rc
= rgw_lookup(fs
, sf
.parent_fh
, sf
.name
.c_str(), &sf
.fh
,
416 RGW_LOOKUP_FLAG_CREATE
);
419 ASSERT_TRUE(sf
.rgw_fh
->is_file());
421 /* because we made it the hard way, fixup attributes */
422 st
.st_uid
= owner_uid
;
423 st
.st_gid
= owner_gid
;
425 sf
.rgw_fh
->create_stat(&st
, create_mask
);
428 rc
= rgw_open(fs
, sf
.fh
, 0 /* posix flags */, 0 /* flags */);
430 ASSERT_TRUE(sf
.rgw_fh
->is_open());
431 /* stage seq write */
433 string data
= "data for " + sf
.name
;
434 rc
= rgw_write(fs
, sf
.fh
, 0, data
.length(), &nbytes
,
435 (void*) data
.c_str(), RGW_WRITE_FLAG_NONE
);
437 ASSERT_EQ(nbytes
, data
.length());
438 /* commit write transaction */
439 rc
= rgw_close(fs
, sf
.fh
, 0 /* flags */);
443 ASSERT_TRUE(sf
.rgw_fh
->is_file());
446 /* sf MUST now be materialized--now change it's attributes */
447 st
.st_uid
= magic_uid
;
448 st
.st_gid
= magic_gid
;
450 rc
= rgw_setattr(fs
, sf
.fh
, &st
, create_mask
, RGW_SETATTR_FLAG_NONE
);
453 /* force evict--subsequent lookups must reload */
454 static_cast<RGWLibFS
*>(fs
->fs_private
)->release_evict(sf
.rgw_fh
);
458 /* revalidate -- expect magic uid and gid */
459 (void) rgw_lookup(fs
, sf
.parent_fh
, sf
.name
.c_str(), &sf
.fh
,
460 RGW_LOOKUP_FLAG_NONE
);
462 ASSERT_NE(sf
.fh
, nullptr);
464 memset(&st
, 0, sizeof(struct stat
)); /* nothing up my sleeve... */
466 rc
= rgw_getattr(fs
, sf
.fh
, &st
, RGW_GETATTR_FLAG_NONE
);
469 ASSERT_EQ(st
.st_uid
, magic_uid
);
470 ASSERT_EQ(st
.st_gid
, magic_gid
);
472 /* release 1 ref on sf */
473 rgw_fh_rele(fs
, sf
.fh
, RGW_FH_RELE_FLAG_NONE
);
475 /* release 1 ref on dir */
476 rgw_fh_rele(fs
, dir
.fh
, RGW_FH_RELE_FLAG_NONE
);
481 TEST(LibRGW
, RGW_CREATE_DIRS1
) {
482 /* verify rgw_create (create [empty] file objects the easy way) */
488 st
.st_uid
= owner_uid
;
489 st
.st_gid
= owner_gid
;
492 for (auto& dirs_rec
: dirs_vec
) {
493 /* create 1 more file in each sdir */
494 obj_rec
& dir
= get
<0>(dirs_rec
);
495 std::string sfname
{"sfile_" + to_string(n_dirs1_objs
)};
496 obj_rec sf
{sfname
, nullptr, dir
.fh
, nullptr};
497 (void) rgw_lookup(fs
, sf
.parent_fh
, sf
.name
.c_str(), &sf
.fh
,
498 RGW_LOOKUP_FLAG_NONE
);
500 rc
= rgw_create(fs
, sf
.parent_fh
, sf
.name
.c_str(), &st
, create_mask
,
501 &sf
.fh
, 0 /* posix flags */, RGW_CREATE_FLAG_NONE
);
511 TEST(LibRGW
, RGW_SETUP_RENAME1
) {
512 /* verify rgw_create (create [empty] file objects the easy way) */
518 st
.st_uid
= owner_uid
;
519 st
.st_gid
= owner_gid
;
522 for (int b_ix
: {0, 1}) {
523 std::string bname
{"brename_" + to_string(b_ix
)};
524 obj_rec brec
{bname
, nullptr, nullptr, nullptr};
525 (void) rgw_lookup(fs
, fs
->root_fh
, brec
.name
.c_str(), &brec
.fh
,
526 RGW_LOOKUP_FLAG_NONE
);
530 int rc
= rgw_mkdir(fs
, fs
->root_fh
, brec
.name
.c_str(), &st
,
531 create_mask
, &brec
.fh
, RGW_MKDIR_FLAG_NONE
);
535 ASSERT_NE(brec
.fh
, nullptr);
538 st
.st_mode
= 644; /* file mask */
540 for (int f_ix
: {0, 1}) {
541 std::string rfname
{"rfile_"};
542 rfname
+= to_string(f_ix
);
543 obj_rec rf
{rfname
, nullptr, brec
.fh
, nullptr};
544 (void) rgw_lookup(fs
, rf
.parent_fh
, rf
.name
.c_str(), &rf
.fh
,
545 RGW_LOOKUP_FLAG_NONE
);
547 rc
= rgw_create(fs
, rf
.parent_fh
, rf
.name
.c_str(), &st
, create_mask
,
548 &rf
.fh
, 0 /* posix flags */, RGW_CREATE_FLAG_NONE
);
554 renames_vec
.push_back(dirs1_rec
{brec
, ovec
});
560 TEST(LibRGW
, RGW_INTRABUCKET_RENAME1
) {
561 /* rgw_rename a file within a bucket */
564 obj_rec
& bdir0
= get
<0>(renames_vec
[0]);
565 obj_rec
& src_obj
= get
<1>(renames_vec
[0])[0];
566 std::string rfname
{"rfile_r0"};
568 std::cout
<< "rename file " << src_obj
.name
<< " to "
569 << rfname
<< " (bucket " << bdir0
.name
<< ")"
572 rc
= rgw_rename(fs
, bdir0
.fh
, src_obj
.name
.c_str(), bdir0
.fh
,
573 rfname
.c_str(), RGW_RENAME_FLAG_NONE
);
578 TEST(LibRGW
, RGW_CROSSBUCKET_RENAME1
) {
579 /* rgw_rename a file within a bucket */
582 obj_rec
& bdir0
= get
<0>(renames_vec
[0]);
583 obj_rec
& bdir1
= get
<0>(renames_vec
[1]);
584 obj_rec
& src_obj
= get
<1>(renames_vec
[0])[1];
585 std::string rfname
{"rfile_rhilldog"};
587 std::cout
<< "rename file " << src_obj
.name
588 << " (bucket " << bdir0
.name
<< ") to "
589 << rfname
<< " (bucket " << bdir1
.name
<< ")"
592 rc
= rgw_rename(fs
, bdir0
.fh
, src_obj
.name
.c_str(), bdir1
.fh
,
593 rfname
.c_str(), RGW_RENAME_FLAG_NONE
);
598 TEST(LibRGW
, BAD_DELETES_DIRS1
) {
602 if (dirs_vec
.size() == 0) {
608 /* try to unlink a non-empty directory (bucket) */
609 rc
= rgw_unlink(fs
, dirs1_b
.parent_fh
, dirs1_b
.name
.c_str(),
610 RGW_UNLINK_FLAG_NONE
);
613 /* try to unlink a non-empty directory (non-bucket) */
614 obj_rec
& sdir_0
= get
<1>(dirs_vec
[0])[0];
615 ASSERT_EQ(sdir_0
.name
, "sdir_0");
616 ASSERT_TRUE(sdir_0
.rgw_fh
->is_dir());
617 /* XXX we can't enforce this currently */
619 ASSERT_EQ(sdir_0
.name
, "sdir_0");
620 ASSERT_TRUE(sdir_0
.rgw_fh
->is_dir());
621 rc
= rgw_unlink(fs
, sdir_0
.parent_fh
, sdir_0
.name
.c_str(),
622 RGW_UNLINK_FLAG_NONE
);
628 TEST(LibRGW
, GETATTR_DIRS1
)
633 for (auto& dirs_rec
: dirs_vec
) {
634 obj_rec
& dir
= get
<0>(dirs_rec
);
636 std::cout
<< "scanning objects in "
637 << dir
.rgw_fh
->full_object_name()
640 for (auto& sobj
: get
<1>(dirs_rec
)) {
641 rc
= rgw_getattr(fs
, sobj
.fh
, &st
, RGW_GETATTR_FLAG_NONE
);
643 /* validate, pretty-print */
644 if (sobj
.rgw_fh
->object_name().find("sfile") != std::string::npos
) {
645 ASSERT_TRUE(sobj
.rgw_fh
->is_file());
646 ASSERT_TRUE(S_ISREG(st
.st_mode
));
648 if (sobj
.rgw_fh
->object_name().find("sdir") != std::string::npos
) {
649 ASSERT_TRUE(sobj
.rgw_fh
->is_dir());
650 ASSERT_TRUE(S_ISDIR(st
.st_mode
));
652 /* validate Unix owners */
653 ASSERT_EQ(st
.st_uid
, owner_uid
);
654 ASSERT_EQ(st
.st_gid
, owner_gid
);
656 obj_rec_st rec_st
{sobj
, st
};
666 TEST(LibRGW
, READ_DIRS1
)
672 for (auto& dirs_rec
: dirs_vec
) {
673 obj_rec
& dir
= get
<0>(dirs_rec
);
675 std::cout
<< "read back objects in "
676 << dir
.rgw_fh
->full_object_name()
679 for (auto& sobj
: get
<1>(dirs_rec
)) {
680 /* only the first 2 file objects have data */
681 if ((sobj
.rgw_fh
->object_name().find("sfile_0")
682 != std::string::npos
) ||
683 (sobj
.rgw_fh
->object_name().find("sfile_1")
684 != std::string::npos
)) {
685 ASSERT_TRUE(sobj
.rgw_fh
->is_file());
686 ASSERT_EQ(sobj
.rgw_fh
->get_size(), 16UL);
690 std::cout
<< "reading 0,256 " << sobj
.rgw_fh
->relative_object_name()
693 rc
= rgw_read(fs
, sobj
.fh
, 0, 256, &nread
, buf
, RGW_READ_FLAG_NONE
);
696 std::cout
<< "\tread back from " << sobj
.name
697 << " : \"" << buf
<< "\""
706 TEST(LibRGW
, READF_SETUP1
)
711 if ((! stat(readf_out_name
.c_str(), &st
)) &&
712 (S_ISREG(st
.st_mode
)) &&
713 (st
.st_size
== 6291456))
716 of
.open(readf_out_name
, ios::out
|ios::app
|ios::binary
);
717 for (int ix1
= 0; ix1
< 6; ++ix1
) {
718 for (int ix2
= 0; ix2
< 1024*1024; ++ix2
) {
726 TEST(LibRGW
, READF_DIRS1
) {
729 obj_rec fobj
{readf_name
, nullptr, dirs1_b
.fh
, nullptr};
731 int rc
= rgw_lookup(fs
, dirs1_b
.fh
, fobj
.name
.c_str(), &fobj
.fh
,
732 RGW_LOOKUP_FLAG_NONE
);
734 ASSERT_NE(fobj
.fh
, nullptr);
738 of
.open(readf_out_name
, ios::out
|ios::app
|ios::binary
);
739 int bufsz
= 1024 * 1024 * sizeof(char);
740 char *buffer
= (char*) malloc(bufsz
);
743 uint64_t length
= bufsz
;
744 for (int ix
= 0; ix
< 6; ++ix
) {
746 memset(buffer
, 0, length
); // XXX
747 rc
= rgw_read(fs
, fobj
.fh
, offset
, length
, &nread
, buffer
,
750 ASSERT_EQ(nread
, length
);
751 of
.write(buffer
, length
);
756 rgw_fh_rele(fs
, fobj
.fh
, 0 /* flags */);
761 TEST(LibRGW
, WRITEF_DIRS1
) {
766 ifs
.open(readf_out_name
, ios::out
|ios::app
|ios::binary
);
767 ASSERT_TRUE(ifs
.is_open());
769 obj_rec fobj
{writef_name
, nullptr, dirs1_b
.fh
, nullptr};
771 (void) rgw_lookup(fs
, fobj
.parent_fh
, fobj
.name
.c_str(), &fobj
.fh
,
772 RGW_LOOKUP_FLAG_NONE
);
775 /* make a new file object (the hard way) */
776 rc
= rgw_lookup(fs
, fobj
.parent_fh
, fobj
.name
.c_str(), &fobj
.fh
,
777 RGW_LOOKUP_FLAG_CREATE
);
781 ASSERT_NE(fobj
.fh
, nullptr);
784 /* begin write transaction */
785 rc
= rgw_open(fs
, fobj
.fh
, 0 /* posix flags */, 0 /* flags */);
787 ASSERT_TRUE(fobj
.rgw_fh
->is_open());
789 int bufsz
= 1024 * 1024 * sizeof(char);
790 char *buffer
= (char*) malloc(bufsz
);
793 uint64_t length
= bufsz
;
794 for (int ix
= 0; ix
< 6; ++ix
) {
795 ASSERT_TRUE(ifs
.good());
796 ifs
.read(buffer
, bufsz
);
799 str
.assign(buffer
, 4);
801 std::cout
<< "read and writing " << length
<< " bytes"
802 << " from " << readf_out_name
803 << " at offset " << offset
804 << " (" << str
<< "... [first 4 chars])"
807 char* leakbuf
= (char*) malloc(bufsz
);
808 memcpy(leakbuf
, buffer
, length
);
809 rc
= rgw_write(fs
, fobj
.fh
, offset
, length
, &nwritten
, leakbuf
,
810 RGW_WRITE_FLAG_NONE
);
812 ASSERT_EQ(nwritten
, length
);
816 /* commit write transaction */
817 rc
= rgw_close(fs
, fobj
.fh
, RGW_CLOSE_FLAG_NONE
);
822 rgw_fh_rele(fs
, fobj
.fh
, 0 /* flags */);
827 TEST(LibRGW
, RELEASE_DIRS1
) {
829 /* force release of handles for children of dirs1--force subsequent
830 * checks to reload them from the cluster.
832 * while doing this, verify handle cleanup and correct LRU state
836 for (auto& dirs_rec
: dirs_vec
) {
837 for (auto& obj
: get
<1>(dirs_rec
)) {
839 std::cout
<< "release " << obj
.name
840 << " type: " << obj
.rgw_fh
->stype()
841 << " refs: " << obj
.rgw_fh
->get_refcnt()
844 ASSERT_EQ(obj
.rgw_fh
->get_refcnt(), 2UL);
845 rc
= rgw_fh_rele(fs
, obj
.fh
, 0 /* flags */);
847 ASSERT_EQ(obj
.rgw_fh
->get_refcnt(), 1UL);
848 /* try-discard handle */
849 /* clear obj_rec vec */
856 static bool r1_cb(const char* name
, void *arg
, uint64_t offset
,
858 struct rgw_file_handle
* parent_fh
859 = static_cast<struct rgw_file_handle
*>(arg
);
860 RGWFileHandle
* rgw_fh
= get_rgwfh(parent_fh
);
861 lsubdout(cct
, rgw
, 10) << __func__
862 << " bucket=" << rgw_fh
->bucket_name()
863 << " dir=" << rgw_fh
->full_object_name()
864 << " called back name=" << name
865 << " flags=" << flags
867 string name_str
{name
};
868 if (! ((name_str
== ".") ||
869 (name_str
== ".."))) {
871 obj_rec
{std::move(name_str
), nullptr, parent_fh
, nullptr});
873 return true; /* XXX */
877 TEST(LibRGW
, HIER1
) {
881 obj_rec
{bucket_name
, nullptr, nullptr, nullptr});
882 while (! obj_stack
.empty()) {
883 auto& elt
= obj_stack
.top();
885 struct rgw_file_handle
* parent_fh
= elt
.parent_fh
886 ? elt
.parent_fh
: fs
->root_fh
;
887 RGWFileHandle
* pfh
= get_rgwfh(parent_fh
);
889 lsubdout(cct
, rgw
, 10)
891 << " parent object_name()=" << pfh
->object_name()
892 << " parent full_object_name()=" << pfh
->full_object_name()
893 << " elt.name=" << elt
.name
895 rc
= rgw_lookup(fs
, parent_fh
, elt
.name
.c_str(), &elt
.fh
,
896 RGW_LOOKUP_FLAG_NONE
);
899 RGWFileHandle
* efh
= get_rgwfh(elt
.fh
);
901 lsubdout(cct
, rgw
, 10)
902 << "rgw_lookup result:"
903 << " elt object_name()=" << efh
->object_name()
904 << " elt full_object_name()=" << efh
->full_object_name()
905 << " elt.name=" << elt
.name
908 ASSERT_NE(elt
.fh
, nullptr);
909 elt
.rgw_fh
= get_rgwfh(elt
.fh
);
910 elt
.parent_fh
= elt
.rgw_fh
->get_parent()->get_fh();
911 ASSERT_EQ(elt
.parent_fh
, parent_fh
);
914 // we have a handle in some state in top position
915 switch(elt
.fh
->fh_type
) {
916 case RGW_FS_TYPE_DIRECTORY
:
917 if (! elt
.state
.readdir
) {
921 lsubdout(cct
, rgw
, 10)
923 << " bucket: " << elt
.rgw_fh
->bucket_name()
924 << " object_name: " << elt
.rgw_fh
->object_name()
925 << " full_name: " << elt
.rgw_fh
->full_object_name()
927 rc
= rgw_readdir(fs
, elt
.fh
, &offset
, r1_cb
, elt
.fh
, &eof
,
928 RGW_READDIR_FLAG_DOTDOT
);
929 elt
.state
.readdir
= true;
931 // ASSERT_TRUE(eof); // XXXX working incorrectly w/single readdir
934 std::cout
<< elt
<< std::endl
;
935 cleanup_queue
.push_back(elt
);
939 case RGW_FS_TYPE_FILE
:
941 std::cout
<< elt
<< std::endl
;
942 cleanup_queue
.push_back(elt
);
953 TEST(LibRGW
, MARKER1_SETUP_BUCKET
) {
954 /* "large" directory enumeration test. this one deals only with
960 st
.st_uid
= owner_uid
;
961 st
.st_gid
= owner_gid
;
965 ret
= rgw_mkdir(fs
, bucket_fh
, marker_dir
.c_str(), &st
, create_mask
,
966 &marker_fh
, RGW_MKDIR_FLAG_NONE
);
968 ret
= rgw_lookup(fs
, bucket_fh
, marker_dir
.c_str(), &marker_fh
,
969 RGW_LOOKUP_FLAG_NONE
);
975 TEST(LibRGW
, MARKER1_SETUP_OBJECTS
)
977 /* "large" directory enumeration test. this one deals only with
979 if (do_marker1
&& do_create
) {
982 for (int ix
= 0; ix
< marker_nobjs
; ++ix
) {
983 std::string
object_name("f_");
984 object_name
+= to_string(ix
);
985 obj_rec obj
{object_name
, nullptr, marker_fh
, nullptr};
986 // lookup object--all operations are by handle
987 ret
= rgw_lookup(fs
, marker_fh
, obj
.name
.c_str(), &obj
.fh
,
988 RGW_LOOKUP_FLAG_CREATE
);
990 obj
.rgw_fh
= get_rgwfh(obj
.fh
);
991 // open object--open transaction
992 ret
= rgw_open(fs
, obj
.fh
, 0 /* posix flags */, RGW_OPEN_FLAG_NONE
);
994 ASSERT_TRUE(obj
.rgw_fh
->is_open());
995 // unstable write data
997 string
data("data for ");
999 int ret
= rgw_write(fs
, obj
.fh
, 0, data
.length(), &nbytes
,
1000 (void*) data
.c_str(), RGW_WRITE_FLAG_NONE
);
1002 ASSERT_EQ(nbytes
, data
.length());
1003 // commit transaction (write on close)
1004 ret
= rgw_close(fs
, obj
.fh
, 0 /* flags */);
1007 marker_objs
.push_back(obj
);
1013 static bool r2_cb(const char* name
, void *arg
, uint64_t offset
,
1016 *(static_cast<dirent_vec
*>(arg
));
1017 lsubdout(cct
, rgw
, 10) << __func__
1018 << " bucket=" << bucket_name
1019 << " dir=" << marker_dir
1020 << " iv count=" << dvec
.count
1021 << " called back name=" << name
1022 << " flags=" << flags
1024 string name_str
{name
};
1025 if (! ((name_str
== ".") ||
1026 (name_str
== ".."))) {
1027 dvec
.obj_names
.push_back(dirent_t
{std::move(name_str
), offset
});
1029 return true; /* XXX */
1033 TEST(LibRGW
, MARKER1_READDIR
)
1039 uint64_t offset
= 0;
1042 /* because RGWReaddirRequest::default_max is 1000 (XXX make
1043 * configurable?) and marker_nobjs is 5*1024, the number
1044 * of required rgw_readdir operations N should be
1045 * marker_nobjs/1000 < N < marker_nobjs/1000+1, i.e., 6 when
1046 * marker_nobjs==5*1024 */
1047 uint32_t max_iterations
= marker_nobjs
/1000+1;
1050 ASSERT_TRUE(dvec
.count
<= max_iterations
);
1051 int ret
= rgw_readdir(fs
, marker_fh
, &offset
, r2_cb
, &dvec
, &eof
,
1052 RGW_READDIR_FLAG_DOTDOT
);
1054 ASSERT_EQ(offset
, get
<1>(dvec
.obj_names
.back())); // cookie check
1057 std::cout
<< "Read " << dvec
.obj_names
.size() << " objects in "
1058 << marker_dir
.c_str() << std::endl
;
1062 TEST(LibRGW
, MARKER1_OBJ_CLEANUP
)
1065 for (auto& obj
: marker_objs
) {
1069 std::cout
<< "unlinking: " << bucket_name
<< ":" << obj
.name
1072 rc
= rgw_unlink(fs
, marker_fh
, obj
.name
.c_str(), RGW_UNLINK_FLAG_NONE
);
1074 rc
= rgw_fh_rele(fs
, obj
.fh
, 0 /* flags */);
1078 marker_objs
.clear();
1081 TEST(LibRGW
, CLEANUP
) {
1085 cleanup_queue
.push_back(
1086 obj_rec
{bucket_name
, bucket_fh
, fs
->root_fh
, get_rgwfh(fs
->root_fh
)});
1089 for (auto& elt
: cleanup_queue
) {
1091 rc
= rgw_fh_rele(fs
, elt
.fh
, 0 /* flags */);
1095 cleanup_queue
.clear();
1098 TEST(LibRGW
, UMOUNT
) {
1102 int ret
= rgw_umount(fs
, RGW_UMOUNT_FLAG_NONE
);
1106 TEST(LibRGW
, SHUTDOWN
) {
1107 librgw_shutdown(rgw_h
);
1110 int main(int argc
, char *argv
[])
1114 vector
<const char*> args
;
1116 argv_to_vec(argc
, const_cast<const char**>(argv
), args
);
1119 v
= getenv("AWS_ACCESS_KEY_ID");
1124 v
= getenv("AWS_SECRET_ACCESS_KEY");
1129 for (auto arg_iter
= args
.begin(); arg_iter
!= args
.end();) {
1130 if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--access",
1133 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--secret",
1136 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--userid",
1139 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--bn",
1142 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--uid",
1144 owner_uid
= std::stoi(val
);
1145 } else if (ceph_argparse_witharg(args
, arg_iter
, &val
, "--gid",
1147 owner_gid
= std::stoi(val
);
1148 } else if (ceph_argparse_flag(args
, arg_iter
, "--hier1",
1151 } else if (ceph_argparse_flag(args
, arg_iter
, "--dirs1",
1154 } else if (ceph_argparse_flag(args
, arg_iter
, "--marker1",
1157 } else if (ceph_argparse_flag(args
, arg_iter
, "--setattr",
1160 } else if (ceph_argparse_flag(args
, arg_iter
, "--create",
1163 } else if (ceph_argparse_flag(args
, arg_iter
, "--delete",
1166 } else if (ceph_argparse_flag(args
, arg_iter
, "--rename",
1169 } else if (ceph_argparse_flag(args
, arg_iter
, "--readf",
1172 } else if (ceph_argparse_flag(args
, arg_iter
, "--writef",
1175 } else if (ceph_argparse_flag(args
, arg_iter
, "--verbose",
1183 /* dont accidentally run as anonymous */
1184 if ((access_key
== "") ||
1185 (secret_key
== "")) {
1186 std::cout
<< argv
[0] << " no AWS credentials, exiting" << std::endl
;
1190 saved_args
.argc
= argc
;
1191 saved_args
.argv
= argv
;
1193 ::testing::InitGoogleTest(&argc
, argv
);
1194 return RUN_ALL_TESTS();