2 * Permission is hereby granted, free of charge, to any person obtaining a
3 * copy of this software and associated documentation files (the "Software"),
4 * to deal in the Software without restriction, including without limitation
5 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
6 * and/or sell copies of the Software, and to permit persons to whom the
7 * Software is furnished to do so, subject to the following conditions:
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 * DEALINGS IN THE SOFTWARE.
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.net.InetAddress;
26 import java.util.UUID;
28 import static org.junit.Assert.*;
30 import com.ceph.crush.Bucket;
34 * - Everything is covered in at least success cases.
35 * - l[set,get,remove]xattr are not working
38 public class CephMountTest {
40 private static CephMount mount;
41 private static String basedir = null;
44 public static void setup() throws Exception {
45 mount = new CephMount("admin");
47 String conf_file = System.getProperty("CEPH_CONF_FILE");
48 if (conf_file != null)
49 mount.conf_read_file(conf_file);
50 mount.conf_set("client_permissions", "0");
54 basedir = "/libcephfs_junit_" + UUID.randomUUID();
55 mount.mkdir(basedir, 0777);
59 public static void destroy() throws Exception {
60 String[] list = mount.listdir(basedir);
62 System.out.println(l);
68 * Helper function to construct a unique path.
70 public String makePath() {
71 String path = basedir + "/" + UUID.randomUUID();
76 * Helper to learn the data pool name, by reading it
77 * from the '/' dir inode.
79 public String getRootPoolName() throws Exception
81 int fd = mount.open("/", CephMount.O_DIRECTORY, 0600);
82 String pool = mount.get_file_pool_name(fd);
88 * Helper function to create a file with the given path and size. The file
89 * is filled with size bytes and the file descriptor is returned.
91 public int createFile(String path, int size) throws Exception {
92 int fd = mount.open(path, CephMount.O_RDWR|CephMount.O_CREAT, 0600);
93 byte[] buf = new byte[4096];
96 size = Math.min(buf.length, left);
97 long ret = mount.write(fd, buf, size, -1);
104 * Helper function to create a unique file and fill it with size bytes. The
105 * file descriptor is returned.
107 public int createFile(int size) throws Exception {
108 return createFile(makePath(), size);
111 @Test(expected=FileNotFoundException.class)
112 public void test_mount_dne() throws Exception {
113 CephMount mount2 = new CephMount("admin");
114 String conf_file = System.getProperty("CEPH_CONF_FILE");
115 if (conf_file != null)
116 mount2.conf_read_file(conf_file);
117 mount2.mount("/wlfkjwlekfjwlejfwe");
122 * Test loading of conf file that doesn't exist.
125 * Ceph returns -ENOSYS rather than -ENOENT. Correct?
127 //@Test(expected=FileNotFoundException.class)
129 public void test_conf_read_file_dne() throws Exception {
130 //mount.conf_read_file("/this_file_does_not_exist");
134 * Test loading of conf file that isn't valid
139 public void test_conf_read_file_invalid() throws Exception {
142 @Test(expected=NullPointerException.class)
143 public void test_conf_read_file_null() throws Exception {
144 mount.conf_read_file(null);
151 @Test(expected=NullPointerException.class)
152 public void test_conf_set_null_opt() throws Exception {
153 mount.conf_set(null, "value");
156 @Test(expected=NullPointerException.class)
157 public void test_conf_set_null_val() throws Exception {
158 mount.conf_set("option", null);
161 @Test(expected=NullPointerException.class)
162 public void test_conf_get_null_opt() throws Exception {
163 mount.conf_get(null);
167 public void test_conf() throws Exception {
168 String opt = "log to stderr";
169 String val1, val2, val3;
171 /* get the current value */
172 val1 = mount.conf_get(opt);
175 * flip the value. this may make some debug information be dumped to the
176 * console when the value becomes true. TODO: find a better config option
179 if (val1.compareTo("true") == 0)
183 mount.conf_set(opt, val2);
185 /* verify the change */
186 val3 = mount.conf_get(opt);
187 assertTrue(val3.compareTo(val2) == 0);
189 /* reset to original value */
190 mount.conf_set(opt, val1);
191 val3 = mount.conf_get(opt);
192 assertTrue(val3.compareTo(val1) == 0);
200 public void test_statfs() throws Exception {
201 CephStatVFS st1 = new CephStatVFS();
202 mount.statfs("/", st1);
205 * FIXME: a better test here is to see if changes to the file system are
206 * reflected through statfs (e.g. increasing number of files). However, it
207 * appears that the updates aren't immediately visible.
209 assertTrue(st1.bsize > 0);
210 assertTrue(st1.frsize > 0);
211 assertTrue(st1.blocks > 0);
212 assertTrue(st1.bavail > 0);
213 assertTrue(st1.namemax > 0);
221 public void test_getcwd() throws Exception {
222 mount.chdir(basedir);
223 String cwd = mount.getcwd();
224 assertTrue(cwd.compareTo(basedir) == 0);
226 /* Make sure to reset cwd to root */
228 cwd = mount.getcwd();
229 assertTrue(cwd.compareTo("/") == 0);
232 @Test(expected=NullPointerException.class)
233 public void test_chdir_null() throws Exception {
237 @Test(expected=FileNotFoundException.class)
238 public void test_chdir_dne() throws Exception {
239 mount.chdir("/this/path/does/not/exist/");
243 * FIXME: this test should throw an error (but does not)?
245 //@Test(expected=IOException.class)
247 public void test_chdir_not_dir() throws Exception {
248 String path = makePath();
249 int fd = createFile(path, 1);
251 //mount.chdir(path); shouldn't be able to do this?
255 * Switch back. Other tests seem to be sensitive to the current directory
256 * being something other than "/". This shouldn't happen once this tests
257 * passes and the call to chdir fails anyway.
266 @Test(expected=NullPointerException.class)
267 public void test_listdir_null() throws Exception {
271 @Test(expected=FileNotFoundException.class)
272 public void test_listdir_dne() throws Exception {
273 mount.listdir("/this/path/does/not/exist/");
276 @Test(expected=IOException.class)
277 public void test_listdir_not_dir() throws Exception {
278 String path = makePath();
279 int fd = createFile(path, 1);
289 public void test_listdir() throws Exception {
290 String dir = makePath();
291 mount.mkdir(dir, 0777);
292 /* test that new directory is empty */
293 String[] list = mount.listdir(dir);
294 assertTrue(list.length == 0);
295 /* test that new directories are seen */
296 for (int i = 0; i < 3; i++)
297 mount.mkdir(dir + "/" + i, 777);
298 list = mount.listdir(dir);
299 assertTrue(list.length == 3);
300 /* test that more new directories are seen */
301 for (int i = 0; i < 30; i++)
302 mount.mkdir(dir + "/x" + i, 777);
303 list = mount.listdir(dir);
304 assertTrue(list.length == 33);
307 for (int i = 0; i < 30; i++)
308 mount.rmdir(dir + "/x" + i);
309 for (int i = 0; i < 3; i++)
310 mount.rmdir(dir + "/" + i);
325 @Test(expected=NullPointerException.class)
326 public void test_rename_null_from() throws Exception {
327 mount.rename(null, "to");
330 @Test(expected=NullPointerException.class)
331 public void test_rename_null_to() throws Exception {
332 mount.rename("from", null);
335 @Test(expected=FileNotFoundException.class)
336 public void test_rename_dne() throws Exception {
337 mount.rename("/this/doesnt/exist", "/this/neither");
341 public void test_rename() throws Exception {
343 String path = makePath();
344 int fd = createFile(path, 1);
347 /* move it to a new name */
348 String newpath = makePath();
349 mount.rename(path, newpath);
351 /* verfiy the sizes are the same */
352 CephStat st = new CephStat();
353 mount.lstat(newpath, st);
354 assertTrue(st.size == 1);
356 /* remove the file */
357 mount.unlink(newpath);
364 @Test(expected=IOException.class)
365 public void test_mkdir_exists() throws Exception {
366 String path = makePath();
367 mount.mkdir(path, 0777);
369 mount.mkdir(path, 0777);
375 @Test(expected=IOException.class)
376 public void test_mkdirs_exists() throws Exception {
377 String path = makePath();
378 mount.mkdirs(path, 0777);
380 mount.mkdirs(path, 0777);
387 public void test_mkdir() throws Exception {
388 String path = makePath();
389 mount.mkdir(path, 0777);
390 CephStat st = new CephStat();
391 mount.lstat(path, st);
392 assertTrue(st.isDir());
397 public void test_mkdirs() throws Exception {
398 String path = makePath();
399 mount.mkdirs(path + "/x/y", 0777);
401 CephStat st = new CephStat();
402 mount.lstat(path, st);
403 assertTrue(st.isDir());
405 mount.lstat(path + "/x", st);
406 assertTrue(st.isDir());
408 mount.lstat(path + "/x/y", st);
409 assertTrue(st.isDir());
411 mount.rmdir(path + "/x/y");
412 mount.rmdir(path + "/x");
416 @Test(expected=FileNotFoundException.class)
417 public void test_rmdir() throws Exception {
418 /* make a new directory */
419 String path = makePath();
420 mount.mkdir(path, 0777);
421 CephStat st = new CephStat();
422 mount.lstat(path, st);
423 assertTrue(st.isDir());
426 /* should not exist now */
427 mount.lstat(path, st);
435 public void test_symlink() throws Exception {
436 String oldpath = makePath();
437 String newpath = makePath();
439 mount.symlink(oldpath, newpath);
440 CephStat stat = new CephStat();
441 mount.lstat(newpath, stat);
442 assertTrue(stat.isSymlink());
444 String symlink = mount.readlink(newpath);
445 assertTrue(symlink.compareTo(oldpath) == 0);
447 mount.unlink(newpath);
454 @Test(expected=NullPointerException.class)
455 public void test_lstat_null_path() throws Exception {
456 mount.lstat(null, new CephStat());
459 @Test(expected=NullPointerException.class)
460 public void test_lstat_null_stat() throws Exception {
461 mount.lstat("/path", null);
464 @Test(expected=FileNotFoundException.class)
465 public void test_lstat_null_dne() throws Exception {
466 mount.lstat("/path/does/not/exist", new CephStat());
470 * test_stat covers lstat and fstat and stat.
472 * TODO: create test that for lstat vs stat with symlink follow/nofollow.
476 public void test_stat() throws Exception {
477 /* create a new file */
478 String path = makePath();
480 int fd = createFile(path, size);
483 /* test some basic info about the new file */
484 CephStat orig_st = new CephStat();
485 mount.lstat(path, orig_st);
486 assertTrue(orig_st.size == size);
487 assertTrue(orig_st.blksize > 0);
488 assertTrue(orig_st.blocks > 0);
491 CephStat stat_st = new CephStat();
492 mount.stat(path, stat_st);
495 CephStat other_st = new CephStat();
496 fd = mount.open(path, CephMount.O_RDWR, 0);
497 mount.fstat(fd, other_st);
502 /* compare to fstat results */
503 assertTrue(orig_st.mode == other_st.mode);
504 assertTrue(orig_st.uid == other_st.uid);
505 assertTrue(orig_st.gid == other_st.gid);
506 assertTrue(orig_st.size == other_st.size);
507 assertTrue(orig_st.blksize == other_st.blksize);
508 assertTrue(orig_st.blocks == other_st.blocks);
510 /* compare to stat results */
511 assertTrue(orig_st.mode == stat_st.mode);
512 assertTrue(orig_st.uid == stat_st.uid);
513 assertTrue(orig_st.gid == stat_st.gid);
514 assertTrue(orig_st.size == stat_st.size);
515 assertTrue(orig_st.blksize == stat_st.blksize);
516 assertTrue(orig_st.blocks == stat_st.blocks);
523 @Test(expected=NullPointerException.class)
524 public void test_stat_null_path() throws Exception {
525 mount.stat(null, new CephStat());
528 @Test(expected=NullPointerException.class)
529 public void test_stat_null_stat() throws Exception {
530 mount.stat("/path", null);
533 @Test(expected=FileNotFoundException.class)
534 public void test_stat_null_dne() throws Exception {
535 mount.stat("/path/does/not/exist", new CephStat());
538 @Test(expected=CephNotDirectoryException.class)
539 public void test_enotdir() throws Exception {
540 String path = makePath();
541 int fd = createFile(path, 1);
545 CephStat stat = new CephStat();
546 mount.lstat(path + "/blah", stat);
556 @Test(expected=NullPointerException.class)
557 public void test_setattr_null_path() throws Exception {
558 mount.setattr(null, new CephStat(), 0);
561 @Test(expected=NullPointerException.class)
562 public void test_setattr_null_stat() throws Exception {
563 mount.setattr("/path", null, 0);
566 @Test(expected=FileNotFoundException.class)
567 public void test_setattr_dne() throws Exception {
568 mount.setattr("/path/does/not/exist", new CephStat(), 0);
572 public void test_setattr() throws Exception {
574 String path = makePath();
575 int fd = createFile(path, 1);
578 CephStat st1 = new CephStat();
579 mount.lstat(path, st1);
583 mount.setattr(path, st1, mount.SETATTR_UID|mount.SETATTR_GID);
585 CephStat st2 = new CephStat();
586 mount.lstat(path, st2);
588 assertTrue(st2.uid == st1.uid);
589 assertTrue(st2.gid == st1.gid);
591 /* remove the file */
599 @Test(expected=NullPointerException.class)
600 public void test_chmod_null_path() throws Exception {
601 mount.chmod(null, 0);
604 @Test(expected=FileNotFoundException.class)
605 public void test_chmod_dne() throws Exception {
606 mount.chmod("/path/does/not/exist", 0);
610 public void test_chmod() throws Exception {
612 String path = makePath();
613 int fd = createFile(path, 1);
616 CephStat st = new CephStat();
617 mount.lstat(path, st);
626 mount.chmod(path, mode);
627 CephStat st2 = new CephStat();
628 mount.lstat(path, st2);
629 assertTrue(st2.mode == mode);
639 public void test_fchmod() throws Exception {
641 String path = makePath();
642 int fd = createFile(path, 1);
644 CephStat st = new CephStat();
645 mount.lstat(path, st);
654 mount.fchmod(fd, mode);
657 CephStat st2 = new CephStat();
658 mount.lstat(path, st2);
659 assertTrue(st2.mode == mode);
668 @Test(expected=FileNotFoundException.class)
669 public void test_truncate_dne() throws Exception {
670 mount.truncate("/path/does/not/exist", 0);
673 @Test(expected=NullPointerException.class)
674 public void test_truncate_null_path() throws Exception {
675 mount.truncate(null, 0);
679 public void test_truncate() throws Exception {
681 String path = makePath();
682 int orig_size = 1398331;
683 int fd = createFile(path, orig_size);
687 CephStat st = new CephStat();
688 mount.lstat(path, st);
689 assertTrue(st.size == orig_size);
691 // truncate and check
692 int crop_size = 333333;
693 mount.truncate(path, crop_size);
694 mount.lstat(path, st);
695 assertTrue(st.size == crop_size);
697 // check after re-open
698 fd = mount.open(path, CephMount.O_RDWR, 0);
700 assertTrue(st.size == crop_size);
707 public void test_open_layout() throws Exception {
708 String path = makePath();
709 int fd = mount.open(path, CephMount.O_WRONLY|CephMount.O_CREAT, 0,
710 (1<<20), 1, (1<<20), null);
719 @Test(expected=FileNotFoundException.class)
720 public void test_open_dne() throws Exception {
721 mount.open("/path/doesnt/exist", 0, 0);
729 public void test_lseek() throws Exception {
730 /* create a new file */
731 String path = makePath();
733 int fd = createFile(path, size);
736 /* open and check size */
737 fd = mount.open(path, CephMount.O_RDWR, 0);
738 long end = mount.lseek(fd, 0, CephMount.SEEK_END);
743 assertTrue(size == (int)end);
751 public void test_read() throws Exception {
752 String path = makePath();
753 int fd = createFile(path, 1500);
754 byte[] buf = new byte[1500];
755 long ret = mount.read(fd, buf, 1500, 0);
756 assertTrue(ret == 1500);
765 public void test_ftruncate() throws Exception {
767 String path = makePath();
768 int orig_size = 1398331;
769 int fd = createFile(path, orig_size);
772 CephStat st = new CephStat();
774 assertTrue(st.size == orig_size);
776 // truncate and check
777 int crop_size = 333333;
778 mount.ftruncate(fd, crop_size);
780 if (st.size != crop_size) {
781 System.err.println("ftruncate error: st.size=" + st.size + " crop_size=" + crop_size);
784 assertTrue(st.size == crop_size);
787 // check after re-open
788 fd = mount.open(path, CephMount.O_RDWR, 0);
790 assertTrue(st.size == crop_size);
801 public void test_fsync() throws Exception {
802 String path = makePath();
803 int fd = createFile(path, 123);
804 mount.fsync(fd, false);
805 mount.fsync(fd, true);
815 public void test_flock() throws Exception {
816 String path = makePath();
817 int fd = createFile(path, 123);
818 mount.flock(fd, CephMount.LOCK_SH | CephMount.LOCK_NB, 42);
819 mount.flock(fd, CephMount.LOCK_SH | CephMount.LOCK_NB, 43);
820 mount.flock(fd, CephMount.LOCK_UN, 42);
821 mount.flock(fd, CephMount.LOCK_UN, 43);
822 mount.flock(fd, CephMount.LOCK_EX | CephMount.LOCK_NB, 42);
824 mount.flock(fd, CephMount.LOCK_SH | CephMount.LOCK_NB, 43);
826 } catch(IOException io) {}
828 mount.flock(fd, CephMount.LOCK_EX | CephMount.LOCK_NB, 43);
830 } catch(IOException io) {}
831 mount.flock(fd, CephMount.LOCK_SH, 42); // downgrade
832 mount.flock(fd, CephMount.LOCK_SH, 43);
833 mount.flock(fd, CephMount.LOCK_UN, 42);
834 mount.flock(fd, CephMount.LOCK_UN, 43);
842 * success case is handled in test_stat along with lstat.
850 public void test_sync_fs() throws Exception {
855 * get/set/list/remove xattr
859 public void test_xattr() throws Exception {
861 String path = makePath();
862 int fd = createFile(path, 123);
866 String val1 = "This is a new xattr";
867 String val2 = "This is a different xattr";
868 byte[] buf1 = val1.getBytes();
869 byte[] buf2 = val2.getBytes();
870 mount.setxattr(path, "user.attr1", buf1, buf1.length, mount.XATTR_CREATE);
871 mount.setxattr(path, "user.attr2", buf2, buf2.length, mount.XATTR_CREATE);
874 String[] xattrs = mount.listxattr(path);
875 assertTrue(xattrs.length == 2);
877 for (String xattr : xattrs) {
878 if (xattr.compareTo("user.attr1") == 0) {
882 if (xattr.compareTo("user.attr2") == 0) {
886 System.out.println("found unwanted xattr: " + xattr);
888 assertTrue(found == 2);
890 /* get first xattr by looking up length */
891 long attr1_len = mount.getxattr(path, "user.attr1", null);
892 byte[] out = new byte[(int)attr1_len];
893 mount.getxattr(path, "user.attr1", out);
894 String outStr = new String(out);
895 assertTrue(outStr.compareTo(val1) == 0);
897 /* get second xattr assuming original length */
898 out = new byte[buf2.length];
899 mount.getxattr(path, "user.attr2", out);
900 outStr = new String(out);
901 assertTrue(outStr.compareTo(val2) == 0);
903 /* remove the attributes */
904 /* FIXME: the MDS returns ENODATA for removexattr */
906 mount.removexattr(path, "attr1");
907 xattrs = mount.listxattr(path);
908 assertTrue(xattrs.length == 1);
909 mount.removexattr(path, "attr2");
910 xattrs = mount.listxattr(path);
911 assertTrue(xattrs.length == 0);
918 * get/set/list/remove symlink xattr
920 * Currently not working. Code is the same as for regular xattrs, so there
921 * might be a deeper issue.
925 public void test_get_stripe_unit() throws Exception {
926 String path = makePath();
927 int fd = createFile(path, 1);
928 assertTrue(mount.get_file_stripe_unit(fd) > 0);
934 public void test_get_repl() throws Exception {
935 String path = makePath();
936 int fd = createFile(path, 1);
937 assertTrue(mount.get_file_replication(fd) > 0);
943 * stripe unit granularity
947 public void test_get_stripe_unit_gran() throws Exception {
948 assertTrue(mount.get_stripe_unit_granularity() > 0);
952 public void test_get_pool_id() throws Exception {
953 String data_pool_name = getRootPoolName();
954 /* returns valid pool id */
955 assertTrue(mount.get_pool_id(data_pool_name) >= 0);
957 /* test non-existent pool name */
959 mount.get_pool_id("asdlfkjlsejflkjef");
961 } catch (CephPoolException e) {}
965 public void test_get_pool_replication() throws Exception {
966 /* test invalid pool id */
968 mount.get_pool_replication(-1);
970 } catch (CephPoolException e) {}
972 /* test valid pool id */
973 String data_pool_name = getRootPoolName();
974 int poolid = mount.get_pool_id(data_pool_name);
975 assertTrue(poolid >= 0);
976 assertTrue(mount.get_pool_replication(poolid) > 0);
980 public void test_get_file_pool_name() throws Exception {
981 String data_pool_name = getRootPoolName();
982 String path = makePath();
983 int fd = createFile(path, 1);
984 String pool = mount.get_file_pool_name(fd);
986 assertTrue(pool != null);
987 /* assumes using default data pool */
988 assertTrue(pool.compareTo(data_pool_name) == 0);
992 @Test(expected=IOException.class)
993 public void test_get_file_pool_name_ebadf() throws Exception {
994 String pool = mount.get_file_pool_name(-40);
998 public void test_get_file_extent() throws Exception {
999 int stripe_unit = 1<<18;
1000 String path = makePath();
1001 int fd = mount.open(path, CephMount.O_WRONLY|CephMount.O_CREAT, 0,
1002 stripe_unit, 2, stripe_unit*2, null);
1004 CephFileExtent e = mount.get_file_extent(fd, 0);
1005 assertTrue(e.getOSDs().length > 0);
1007 assertTrue(e.getOffset() == 0);
1008 assertTrue(e.getLength() == stripe_unit);
1010 e = mount.get_file_extent(fd, stripe_unit/2);
1011 assertTrue(e.getOffset() == stripe_unit/2);
1012 assertTrue(e.getLength() == stripe_unit/2);
1014 e = mount.get_file_extent(fd, 3*stripe_unit/2-1);
1015 assertTrue(e.getOffset() == 3*stripe_unit/2-1);
1016 assertTrue(e.getLength() == stripe_unit/2+1);
1018 e = mount.get_file_extent(fd, 3*stripe_unit/2+1);
1019 assertTrue(e.getLength() == stripe_unit/2-1);
1026 public void test_get_osd_crush_location() throws Exception {
1027 Bucket[] path = mount.get_osd_crush_location(0);
1028 assertTrue(path.length > 0);
1029 for (Bucket b : path) {
1030 assertTrue(b.getType().length() > 0);
1031 assertTrue(b.getName().length() > 0);
1036 public void test_get_osd_address() throws Exception {
1037 InetAddress addr = mount.get_osd_address(0);
1038 assertTrue(addr.getHostAddress().length() > 0);