Index: projects/fuse2/etc/mtree/BSD.tests.dist =================================================================== --- projects/fuse2/etc/mtree/BSD.tests.dist (revision 344714) +++ projects/fuse2/etc/mtree/BSD.tests.dist (revision 344715) @@ -1,1060 +1,1062 @@ # $FreeBSD$ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin cat .. chflags .. chmod .. date .. dd .. echo .. expr .. ln .. ls .. mkdir .. mv .. pax .. pkill .. pwait .. rm .. rmdir .. sh builtins .. errors .. execution .. expansion .. invocation .. parameters .. parser .. set-e .. .. sleep .. test .. .. cddl lib .. sbin .. usr.bin ctfconvert .. ztest .. .. usr.sbin dtrace common aggs .. arithmetic .. arrays .. assocs .. begin .. bitfields .. buffering .. builtinvar .. cg .. clauses .. cpc .. decls .. drops .. dtraceUtil .. end .. env .. enum .. error .. exit .. fbtprovider .. funcs .. grammar .. include .. inline .. io .. ip .. java_api .. json .. lexer .. llquantize .. mdb .. mib .. misc .. multiaggs .. offsetof .. operators .. pid .. plockstat .. pointers .. pragma .. predicates .. preprocessor .. print .. printa .. printf .. privs .. probes .. proc .. profile-n .. providers .. raise .. rates .. safety .. scalars .. sched .. scripting .. sdt .. sizeof .. speculation .. stability .. stack .. stackdepth .. stop .. strlen .. strtoll .. struct .. sugar .. syscall .. sysevent .. tick-n .. trace .. tracemem .. translators .. typedef .. types .. uctf .. union .. usdt .. ustack .. vars .. version .. .. .. zfsd .. .. .. etc rc.d .. .. games .. gnu lib .. usr.bin diff .. .. .. lib atf libatf-c detail .. .. libatf-c++ detail .. .. test-programs .. .. csu dynamic .. dynamiclib .. static .. .. libarchive .. libc c063 .. db .. gen execve .. posix_spawn .. .. hash data .. .. iconv .. inet .. locale .. net getaddrinfo data .. .. .. nss .. regex data .. .. resolv .. rpc .. ssp .. setjmp .. stdio .. stdlib .. string .. sys .. time .. tls dso .. .. termios .. ttyio .. .. libcam .. libcasper services cap_dns .. cap_grp .. cap_pwd .. cap_sysctl .. .. .. libcrypt .. libdevdctl .. libkvm .. libmp .. libnv .. libproc .. libregex data .. .. librt .. libsbuf .. libthr dlopen .. .. libutil .. libxo .. msun .. .. libexec atf atf-check .. atf-sh .. .. rtld-elf .. tftpd .. .. sbin bectl .. dhclient .. devd .. growfs .. ifconfig .. mdconfig .. pfctl files .. .. .. secure lib .. libexec .. usr.bin .. usr.sbin .. .. share examples tests atf .. plain .. tap .. .. .. zoneinfo .. .. sys acl .. aio .. audit .. auditpipe .. capsicum .. cddl zfs bin .. include .. tests acl cifs .. nontrivial .. trivial .. .. atime .. bootfs .. cache .. cachefile .. clean_mirror .. cli_root zfs_upgrade .. zfs_promote .. zfs_clone .. zfs_property .. zfs_destroy .. zpool_create .. zpool_history .. zpool_expand .. zpool_remove .. zfs_mount .. zfs_unshare .. zdb .. zpool_online .. zpool_get .. zpool_export .. zfs_copies .. zfs_get .. zfs .. zpool_clear .. zpool_import blockfiles .. .. zpool .. zpool_offline .. zpool_replace .. zfs_rollback .. zpool_set .. zfs_send .. zfs_set .. zpool_detach .. zfs_diff .. zpool_scrub .. zfs_inherit .. zfs_snapshot .. zfs_share .. zpool_destroy .. zpool_status .. zfs_unmount .. zfs_receive .. zfs_create .. zpool_upgrade blockfiles .. .. zpool_add .. zfs_rename .. zpool_attach .. zfs_reservation .. .. cli_user misc .. zfs_list .. zpool_iostat .. zpool_list .. .. compression .. ctime .. delegate .. devices .. exec .. grow_pool .. grow_replicas .. history .. hotplug .. hotspare .. inheritance .. interop .. inuse .. iscsi .. large_files .. largest_pool .. link_count .. migration .. mmap .. mount .. mv_files .. nestedfs .. no_space .. online_offline .. pool_names .. poolversion .. quota .. redundancy .. refquota .. refreserv .. rename_dirs .. replacement .. reservation .. rootpool .. rsend .. scrub_mirror .. slog .. snapshot .. snapused .. sparse .. threadsappend .. truncate .. txg_integrity .. userquota .. utils_test .. write_dirs .. xattr .. zfsd .. zil .. zinject .. zones .. zvol zvol_ENOSPC .. zvol_cli .. zvol_misc .. zvol_swap .. .. zvol_thrash .. .. .. .. dtrace .. fifo .. file .. fs + fuse + .. tmpfs .. .. geom class concat .. eli .. gate .. gpt .. mirror .. nop .. part .. raid3 .. shsec .. stripe .. uzip etalon .. .. .. .. kern acct .. execve .. pipe .. .. kqueue libkqueue .. .. mac bsdextended .. portacl .. .. mqueue .. net .. netinet .. netipsec tunnel .. .. netmap .. netpfil pf ioctl .. .. .. opencrypto .. pjdfstest chflags .. chmod .. chown .. ftruncate .. granular .. link .. mkdir .. mkfifo .. mknod .. open .. rename .. rmdir .. symlink .. truncate .. unlink .. utimensat .. .. posixshm .. sys .. vfs .. vm .. .. usr.bin apply .. awk .. basename .. bmake archives fmt_44bsd .. fmt_44bsd_mod .. fmt_oldbsd .. .. basic t0 .. t1 .. t2 .. t3 .. .. execution ellipsis .. empty .. joberr .. plus .. .. shell builtin .. meta .. path .. path_select .. replace .. select .. .. suffixes basic .. src_wild1 .. src_wild2 .. .. syntax directive-t0 .. enl .. funny-targets .. semi .. .. sysmk t0 2 1 .. .. mk .. .. t1 2 1 .. .. mk .. .. t2 2 1 .. .. mk .. .. .. variables modifier_M .. modifier_t .. opt_V .. t0 .. .. .. bsdcat .. calendar .. cmp .. compress .. cpio .. col .. comm .. csplit .. cut .. dc .. diff .. dirname .. du .. file2c .. find .. fold .. getconf .. grep .. gzip .. head .. hexdump .. ident .. indent .. join .. jot .. lastcomm .. limits .. m4 .. mkimg .. ncal .. opensm .. pr .. printf .. procstat .. rs .. sdiff .. sed regress.multitest.out .. .. seq .. soelim .. stat .. tail .. tar .. timeout .. tr .. truncate .. units .. uudecode .. uuencode .. uniq .. vmstat .. xargs .. xinstall .. xo .. yacc yacc .. .. .. usr.sbin chown .. etcupdate .. extattr .. fstyp .. makefs .. newsyslog .. nmtree .. praudit .. pw .. rpcbind .. sa .. .. .. # vim: set expandtab ts=4 sw=4: Index: projects/fuse2/tests/sys/fs/Makefile =================================================================== --- projects/fuse2/tests/sys/fs/Makefile (revision 344714) +++ projects/fuse2/tests/sys/fs/Makefile (revision 344715) @@ -1,23 +1,24 @@ # $FreeBSD$ PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/fs TESTSRC= ${SRCTOP}/contrib/netbsd-tests/fs #TESTS_SUBDIRS+= nullfs # XXX: needs rump +TESTS_SUBDIRS+= fuse TESTS_SUBDIRS+= tmpfs ${PACKAGE}FILES+= h_funcs.subr ${PACKAGE}FILESDIR= ${TESTSDIR} CLEANFILES+= h_funcs.subr CLEANFILES+= h_funcs.subr.tmp h_funcs.subr: ${TESTSRC}/h_funcs.subr cat ${.ALLSRC} | \ sed -e '/atf_require_prog mount_$${name}/d' >>${.TARGET}.tmp mv ${.TARGET}.tmp ${.TARGET} .include Index: projects/fuse2/tests/sys/fs/fuse/Makefile =================================================================== --- projects/fuse2/tests/sys/fs/fuse/Makefile (nonexistent) +++ projects/fuse2/tests/sys/fs/fuse/Makefile (revision 344715) @@ -0,0 +1,47 @@ +# $FreeBSD$ + +PACKAGE= tests + +TESTSDIR= ${TESTSBASE}/sys/fs/fuse + +ATF_TESTS_CXX+= getattr +ATF_TESTS_CXX+= lookup + +SRCS.getattr+= getattr.cc +SRCS.getattr+= getmntopts.c +SRCS.getattr+= mockfs.cc +SRCS.getattr+= utils.cc + +SRCS.lookup+= lookup.cc +SRCS.lookup+= getmntopts.c +SRCS.lookup+= mockfs.cc +SRCS.lookup+= utils.cc + +TEST_METADATA+= timeout=10 +TEST_METADATA+= required_user=root + +FUSEFS= ${.CURDIR:H:H:H:H}/sys/fs/fuse +MOUNT= ${.CURDIR:H:H:H:H}/sbin/mount +CFLAGS+= -I${.CURDIR:H:H:H} +CFLAGS+= -I${FUSEFS} +CFLAGS+= -I${MOUNT} +.PATH: ${MOUNT} + +LIBADD+= pthread +WARNS?= 6 +NO_WTHREAD_SAFETY= # GoogleTest fails Clang's thread safety check + +# Use googlemock from ports until after the import-googletest-1.8.1 branch +# merges to head. +CXXFLAGS+= -I/usr/local/include +CXXFLAGS+= -DGTEST_HAS_POSIX_RE=1 +CXXFLAGS+= -DGTEST_HAS_PTHREAD=1 +CXXFLAGS+= -DGTEST_HAS_STREAM_REDIRECTION=1 +CXXFLAGS+= -frtti +CXXFLAGS+= -std=c++14 +LDADD+= ${LOCALBASE}/lib/libgmock.a +LDADD+= ${LOCALBASE}/lib/libgtest.a +# Without -lpthread, gtest fails at _runtime_ with the error pthread_key_create(&key, &DeleteThreadLocalValue)failed with error 78 +LIBADD+= pthread + +.include Property changes on: projects/fuse2/tests/sys/fs/fuse/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/fuse2/tests/sys/fs/fuse/getattr.cc =================================================================== --- projects/fuse2/tests/sys/fs/fuse/getattr.cc (nonexistent) +++ projects/fuse2/tests/sys/fs/fuse/getattr.cc (revision 344715) @@ -0,0 +1,241 @@ +/*- + * Copyright (c) 2019 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by BFF Storage Systems, LLC under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mockfs.hh" +#include "utils.hh" + +using namespace testing; + +class Getattr : public FuseTest {}; + +/* + * If getattr returns a non-zero cache timeout, then subsequent VOP_GETATTRs + * should use the cached attributes, rather than query the daemon + */ +/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235775 */ +TEST_F(Getattr, DISABLED_attr_cache) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const uint64_t ino = 42; + const uint64_t generation = 13; + struct stat sb; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillRepeatedly(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = ino; + out->body.entry.generation = generation; + })); + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in->header.opcode == FUSE_GETATTR && + in->header.nodeid == ino); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, attr); + out->body.attr.attr_valid = UINT64_MAX; + out->body.attr.attr.ino = ino; // Must match nodeid + out->body.attr.attr.mode = S_IFREG | 0644; + })); + EXPECT_EQ(0, stat(FULLPATH, &sb)); + /* The second stat(2) should use cached attributes */ + EXPECT_EQ(0, stat(FULLPATH, &sb)); +} + +/* + * If getattr returns a finite but non-zero cache timeout, then we should + * discard the cached attributes and requery the daemon after the timeout + * period passes. + */ +/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235773 */ +TEST_F(Getattr, attr_cache_timeout) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const uint64_t ino = 42; + const uint64_t generation = 13; + struct stat sb; + /* + * The timeout should be longer than the longest plausible time the + * daemon would take to complete a write(2) to /dev/fuse, but no longer. + */ + long timeout_ns = 250'000'000; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillRepeatedly(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.entry_valid = UINT64_MAX; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = ino; + out->body.entry.generation = generation; + })); + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in->header.opcode == FUSE_GETATTR && + in->header.nodeid == ino); + }, Eq(true)), + _) + ).Times(2) + .WillRepeatedly(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, attr); + out->body.attr.attr_valid_nsec = timeout_ns; + out->body.attr.attr_valid = UINT64_MAX; + out->body.attr.attr.ino = ino; // Must match nodeid + out->body.attr.attr.mode = S_IFREG | 0644; + })); + EXPECT_EQ(0, stat(FULLPATH, &sb)); + usleep(2 * timeout_ns / 1000); + /* Timeout has expire. stat(2) should requery the daemon */ + EXPECT_EQ(0, stat(FULLPATH, &sb)); +} + +TEST_F(Getattr, enoent) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + struct stat sb; + const uint64_t ino = 42; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.attr.mode = 0100644; + out->body.entry.nodeid = ino; + })); + + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in->header.opcode == FUSE_GETATTR && + in->header.nodeid == ino); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + out->header.error = -ENOENT; + out->header.len = sizeof(out->header); + })); + EXPECT_NE(0, stat(FULLPATH, &sb)); + EXPECT_EQ(ENOENT, errno); +} + +TEST_F(Getattr, ok) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const uint64_t ino = 42; + const uint64_t generation = 13; + struct stat sb; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = ino; + out->body.entry.generation = generation; + })); + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in->header.opcode == FUSE_GETATTR && + in->header.nodeid == ino); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, attr); + out->body.attr.attr.ino = ino; // Must match nodeid + out->body.attr.attr.mode = S_IFREG | 0644; + out->body.attr.attr.size = 1; + out->body.attr.attr.blocks = 2; + out->body.attr.attr.atime = 3; + out->body.attr.attr.mtime = 4; + out->body.attr.attr.ctime = 5; + out->body.attr.attr.atimensec = 6; + out->body.attr.attr.mtimensec = 7; + out->body.attr.attr.ctimensec = 8; + out->body.attr.attr.nlink = 9; + out->body.attr.attr.uid = 10; + out->body.attr.attr.gid = 11; + out->body.attr.attr.rdev = 12; + })); + + ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); + EXPECT_EQ(1, sb.st_size); + EXPECT_EQ(2, sb.st_blocks); + EXPECT_EQ(3, sb.st_atim.tv_sec); + EXPECT_EQ(6, sb.st_atim.tv_nsec); + EXPECT_EQ(4, sb.st_mtim.tv_sec); + EXPECT_EQ(7, sb.st_mtim.tv_nsec); + EXPECT_EQ(5, sb.st_ctim.tv_sec); + EXPECT_EQ(8, sb.st_ctim.tv_nsec); + EXPECT_EQ(9ull, sb.st_nlink); + EXPECT_EQ(10ul, sb.st_uid); + EXPECT_EQ(11ul, sb.st_gid); + EXPECT_EQ(12ul, sb.st_rdev); + EXPECT_EQ(ino, sb.st_ino); + EXPECT_EQ(S_IFREG | 0644, sb.st_mode); + + // fuse(4) does not _yet_ support inode generations + //EXPECT_EQ(generation, sb.st_gen); + + //st_birthtim and st_flags are not supported by protocol 7.8. They're + //only supported as OS-specific extensions to OSX. + //EXPECT_EQ(, sb.st_birthtim); + //EXPECT_EQ(, sb.st_flags); + + //FUSE can't set st_blksize until protocol 7.9 +} Property changes on: projects/fuse2/tests/sys/fs/fuse/getattr.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/fuse2/tests/sys/fs/fuse/lookup.cc =================================================================== --- projects/fuse2/tests/sys/fs/fuse/lookup.cc (nonexistent) +++ projects/fuse2/tests/sys/fs/fuse/lookup.cc (revision 344715) @@ -0,0 +1,258 @@ +/*- + * Copyright (c) 2019 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by BFF Storage Systems, LLC under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +extern "C" { +#include +} + +#include "mockfs.hh" +#include "utils.hh" + +using namespace testing; + +class Lookup: public FuseTest {}; + +/* + * If lookup returns a non-zero cache timeout, then subsequent VOP_GETATTRs + * should use the cached attributes, rather than query the daemon + */ +/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235775 */ +TEST_F(Lookup, DISABLED_attr_cache) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const uint64_t ino = 42; + struct stat sb; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.nodeid = ino; + out->body.entry.attr_valid = UINT64_MAX; + out->body.entry.attr.ino = ino; // Must match nodeid + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.attr.size = 1; + out->body.entry.attr.blocks = 2; + out->body.entry.attr.atime = 3; + out->body.entry.attr.mtime = 4; + out->body.entry.attr.ctime = 5; + out->body.entry.attr.atimensec = 6; + out->body.entry.attr.mtimensec = 7; + out->body.entry.attr.ctimensec = 8; + out->body.entry.attr.nlink = 9; + out->body.entry.attr.uid = 10; + out->body.entry.attr.gid = 11; + out->body.entry.attr.rdev = 12; + })); + /* stat(2) issues a VOP_LOOKUP followed by a VOP_GETATTR */ + ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); + EXPECT_EQ(1, sb.st_size); + EXPECT_EQ(2, sb.st_blocks); + EXPECT_EQ(3, sb.st_atim.tv_sec); + EXPECT_EQ(6, sb.st_atim.tv_nsec); + EXPECT_EQ(4, sb.st_mtim.tv_sec); + EXPECT_EQ(7, sb.st_mtim.tv_nsec); + EXPECT_EQ(5, sb.st_ctim.tv_sec); + EXPECT_EQ(8, sb.st_ctim.tv_nsec); + EXPECT_EQ(9ull, sb.st_nlink); + EXPECT_EQ(10ul, sb.st_uid); + EXPECT_EQ(11ul, sb.st_gid); + EXPECT_EQ(12ul, sb.st_rdev); + EXPECT_EQ(ino, sb.st_ino); + EXPECT_EQ(S_IFREG | 0644, sb.st_mode); + + // fuse(4) does not _yet_ support inode generations + //EXPECT_EQ(generation, sb.st_gen); + + //st_birthtim and st_flags are not supported by protocol 7.8. They're + //only supported as OS-specific extensions to OSX. + //EXPECT_EQ(, sb.st_birthtim); + //EXPECT_EQ(, sb.st_flags); + + //FUSE can't set st_blksize until protocol 7.9 +} + +/* + * If lookup returns a finite but non-zero cache timeout, then we should discard + * the cached attributes and requery the daemon. + */ +/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235773 */ +TEST_F(Lookup, attr_cache_timeout) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const uint64_t ino = 42; + struct stat sb; + /* + * The timeout should be longer than the longest plausible time the + * daemon would take to complete a write(2) to /dev/fuse, but no longer. + */ + long timeout_ns = 250'000'000; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillRepeatedly(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.nodeid = ino; + out->body.entry.attr_valid_nsec = timeout_ns; + out->body.entry.attr.ino = ino; // Must match nodeid + out->body.entry.attr.mode = S_IFREG | 0644; + })); + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in->header.opcode == FUSE_GETATTR && + in->header.nodeid == ino); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, attr); + out->body.attr.attr.ino = ino; // Must match nodeid + out->body.attr.attr.mode = S_IFREG | 0644; + })); + + /* access(2) will issue a VOP_LOOKUP but not a VOP_GETATTR */ + ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno); + usleep(2 * timeout_ns / 1000); + /* The cache has timed out; VOP_GETATTR should query the daemon*/ + ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); +} + +TEST_F(Lookup, enoent) +{ + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in->header.opcode == FUSE_LOOKUP); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + out->header.error = -ENOENT; + out->header.len = sizeof(out->header); + })); + EXPECT_NE(0, access("mountpoint/does_not_exist", F_OK)); + EXPECT_EQ(ENOENT, errno); +} + +/* + * If lookup returns a non-zero entry timeout, then subsequent VOP_LOOKUPs + * should use the cached inode rather than requery the daemon + */ +TEST_F(Lookup, entry_cache) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.entry_valid = UINT64_MAX; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = 14; + })); + ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno); + /* The second access(2) should use the cache */ + ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno); +} + +/* + * If lookup returns a finite but non-zero entry cache timeout, then we should + * discard the cached inode and requery the daemon + */ +/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235773 */ +TEST_F(Lookup, DISABLED_entry_cache_timeout) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + /* + * The timeout should be longer than the longest plausible time the + * daemon would take to complete a write(2) to /dev/fuse, but no longer. + */ + long timeout_ns = 250'000'000; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).Times(2) + .WillRepeatedly(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.entry_valid_nsec = timeout_ns; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = 14; + })); + ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno); + usleep(2 * timeout_ns / 1000); + /* The cache has timed out; VOP_LOOKUP should query the daemon*/ + ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno); +} + +TEST_F(Lookup, ok) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_LOOKUP && + strcmp(in->body.lookup, RELPATH) == 0); + }, Eq(true)), + _) + ).WillOnce(Invoke([](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = 14; + })); + /* + * access(2) is one of the few syscalls that will not (always) follow + * up a successful VOP_LOOKUP with another VOP. + */ + ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno); +} Property changes on: projects/fuse2/tests/sys/fs/fuse/lookup.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/fuse2/tests/sys/fs/fuse/mockfs.cc =================================================================== --- projects/fuse2/tests/sys/fs/fuse/mockfs.cc (nonexistent) +++ projects/fuse2/tests/sys/fs/fuse/mockfs.cc (revision 344715) @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 2019 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by BFF Storage Systems, LLC under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +extern "C" { +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mntopts.h" // for build_iovec +} + +#include + +#include "mockfs.hh" + +using namespace testing; + +int verbosity = 0; +static sig_atomic_t quit = 0; + +const char* opcode2opname(uint32_t opcode) +{ + const int NUM_OPS = 39; + const char* table[NUM_OPS] = { + "Unknown (opcode 0)", + "FUSE_LOOKUP", + "FUSE_FORGET", + "FUSE_GETATTR", + "FUSE_SETATTR", + "FUSE_READLINK", + "FUSE_SYMLINK", + "Unknown (opcode 7)", + "FUSE_MKNOD", + "FUSE_MKDIR", + "FUSE_UNLINK", + "FUSE_RMDIR", + "FUSE_RENAME", + "FUSE_LINK", + "FUSE_OPEN", + "FUSE_READ", + "FUSE_WRITE", + "FUSE_STATFS", + "FUSE_RELEASE", + "Unknown (opcode 19)", + "FUSE_FSYNC", + "FUSE_SETXATTR", + "FUSE_GETXATTR", + "FUSE_LISTXATTR", + "FUSE_REMOVEXATTR", + "FUSE_FLUSH", + "FUSE_INIT", + "FUSE_OPENDIR", + "FUSE_READDIR", + "FUSE_RELEASEDIR", + "FUSE_FSYNCDIR", + "FUSE_GETLK", + "FUSE_SETLK", + "FUSE_SETLKW", + "FUSE_ACCESS", + "FUSE_CREATE", + "FUSE_INTERRUPT", + "FUSE_BMAP", + "FUSE_DESTROY" + }; + if (opcode >= NUM_OPS) + return ("Unknown (opcode > max)"); + else + return (table[opcode]); +} + +void sigint_handler(int __unused sig) { + quit = 1; +} + +MockFS::MockFS() { + struct iovec *iov = NULL; + int iovlen = 0; + char fdstr[15]; + + /* + * Kyua sets pwd to a testcase-unique tempdir; no need to use + * mkdtemp + */ + /* + * googletest doesn't allow ASSERT_ in constructors, so we must throw + * instead. + */ + if (mkdir("mountpoint" , 0644) && errno != EEXIST) + throw(std::system_error(errno, std::system_category(), + "Couldn't make mountpoint directory")); + + m_fuse_fd = open("/dev/fuse", O_RDWR); + if (m_fuse_fd < 0) + throw(std::system_error(errno, std::system_category(), + "Couldn't open /dev/fuse")); + sprintf(fdstr, "%d", m_fuse_fd); + + m_pid = getpid(); + + build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1); + build_iovec(&iov, &iovlen, "fspath", + __DECONST(void *, "mountpoint"), -1); + build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1); + build_iovec(&iov, &iovlen, "fd", fdstr, -1); + if (nmount(iov, iovlen, 0)) + throw(std::system_error(errno, std::system_category(), + "Couldn't mount filesystem")); + + // Setup default handler + ON_CALL(*this, process(_, _)) + .WillByDefault(Invoke(this, &MockFS::process_default)); + + init(); + if (pthread_create(&m_thr, NULL, service, (void*)this)) + throw(std::system_error(errno, std::system_category(), + "Couldn't Couldn't start fuse thread")); +} + +MockFS::~MockFS() { + pthread_kill(m_daemon_id, SIGUSR1); + // Closing the /dev/fuse file descriptor first allows unmount to + // succeed even if the daemon doesn't correctly respond to commands + // during the unmount sequence. + close(m_fuse_fd); + pthread_join(m_daemon_id, NULL); + ::unmount("mountpoint", MNT_FORCE); + rmdir("mountpoint"); +} + +void MockFS::init() { + mockfs_buf_in *in; + mockfs_buf_out out; + + in = (mockfs_buf_in*) malloc(sizeof(*in)); + ASSERT_TRUE(in != NULL); + + read_request(in); + ASSERT_EQ(FUSE_INIT, in->header.opcode); + + memset(&out, 0, sizeof(out)); + out.header.unique = in->header.unique; + out.header.error = 0; + out.body.init.major = FUSE_KERNEL_VERSION; + out.body.init.minor = FUSE_KERNEL_MINOR_VERSION; + SET_OUT_HEADER_LEN(&out, init); + write(m_fuse_fd, &out, out.header.len); + + free(in); +} + +void MockFS::loop() { + mockfs_buf_in *in; + mockfs_buf_out out; + + in = (mockfs_buf_in*) malloc(sizeof(*in)); + ASSERT_TRUE(in != NULL); + while (!quit) { + bzero(in, sizeof(*in)); + bzero(&out, sizeof(out)); + read_request(in); + if (quit) + break; + if (verbosity > 0) { + printf("Got request %s\n", + opcode2opname(in->header.opcode)); + } + if ((pid_t)in->header.pid != m_pid) { + /* + * Reject any requests from unknown processes. Because + * we actually do mount a filesystem, plenty of + * unrelated system daemons may try to access it. + */ + process_default(in, &out); + } else { + process(in, &out); + } + if (in->header.opcode == FUSE_FORGET) { + /*Alone among the opcodes, FORGET expects no response*/ + continue; + } + ASSERT_TRUE(write(m_fuse_fd, &out, out.header.len) > 0 || + errno == EAGAIN) + << strerror(errno); + } + free(in); +} + +void MockFS::process_default(const mockfs_buf_in *in, mockfs_buf_out* out) { + out->header.unique = in->header.unique; + out->header.error = -EOPNOTSUPP; + out->header.len = sizeof(out->header); +} + +void MockFS::read_request(mockfs_buf_in *in) { + ssize_t res; + + res = read(m_fuse_fd, in, sizeof(*in)); + if (res < 0 && !quit) + perror("read"); + ASSERT_TRUE(res >= (ssize_t)sizeof(in->header) || quit); +} + +void* MockFS::service(void *pthr_data) { + MockFS *mock_fs = (MockFS*)pthr_data; + mock_fs->m_daemon_id = pthread_self(); + + quit = 0; + signal(SIGUSR1, sigint_handler); + + mock_fs->loop(); + + return (NULL); +} + +void MockFS::unmount() { + ::unmount("mountpoint", 0); +} Property changes on: projects/fuse2/tests/sys/fs/fuse/mockfs.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/fuse2/tests/sys/fs/fuse/mockfs.hh =================================================================== --- projects/fuse2/tests/sys/fs/fuse/mockfs.hh (nonexistent) +++ projects/fuse2/tests/sys/fs/fuse/mockfs.hh (revision 344715) @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 2019 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by BFF Storage Systems, LLC under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +extern "C" { +#include + +#include + +#include "fuse_kernel.h" +} + +#include + +#define SET_OUT_HEADER_LEN(out, variant) { \ + (out)->header.len = (sizeof((out)->header) + \ + sizeof((out)->body.variant)); \ +} + +extern int verbosity; + +union fuse_payloads_in { + fuse_forget_in forget; + fuse_init_in init; + char lookup[0]; + /* value is from fuse_kern_chan.c in fusefs-libs */ + uint8_t bytes[0x21000 - sizeof(struct fuse_in_header)]; +}; + +struct mockfs_buf_in { + fuse_in_header header; + union fuse_payloads_in body; +}; + +union fuse_payloads_out { + fuse_init_out init; + fuse_entry_out entry; + fuse_attr_out attr; +}; + +struct mockfs_buf_out { + fuse_out_header header; + union fuse_payloads_out body; +}; + +/* + * Fake FUSE filesystem + * + * "Mounts" a filesystem to a temporary directory and services requests + * according to the programmed expectations. + * + * Operates directly on the fuse(4) kernel API, not the libfuse(3) user api. + */ +class MockFS { + public: + /* thread id of the fuse daemon thread */ + pthread_t m_daemon_id; + + private: + /* file descriptor of /dev/fuse control device */ + int m_fuse_fd; + + /* pid of the test process */ + pid_t m_pid; + + /* + * Thread that's running the mockfs daemon. + * + * It must run in a separate thread so it doesn't deadlock with the + * client test code. + */ + pthread_t m_thr; + + /* Initialize a session after mounting */ + void init(); + + /* Default request handler */ + void process_default(const mockfs_buf_in*, mockfs_buf_out*); + + /* Entry point for the daemon thread */ + static void* service(void*); + + /* Read, but do not process, a single request from the kernel */ + void read_request(mockfs_buf_in*); + + public: + /* Create a new mockfs and mount it to a tempdir */ + MockFS(); + virtual ~MockFS(); + + /* Process FUSE requests endlessly */ + void loop(); + + /* + * Request handler + * + * This method is expected to provide the response to each FUSE + * operation. Responses must be immediate (so this method can't be used + * for testing a daemon with queue depth > 1). Test cases must define + * each response using Googlemock expectations + */ + MOCK_METHOD2(process, void(const mockfs_buf_in*, mockfs_buf_out*)); + + /* Gracefully unmount */ + void unmount(); +}; Index: projects/fuse2/tests/sys/fs/fuse/utils.cc =================================================================== --- projects/fuse2/tests/sys/fs/fuse/utils.cc (nonexistent) +++ projects/fuse2/tests/sys/fs/fuse/utils.cc (revision 344715) @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2019 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by BFF Storage Systems, LLC under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "mockfs.hh" + +static void usage(char* progname) { + fprintf(stderr, "Usage: %s [-v]\n\t-v increase verbosity\n", progname); + exit(2); +} + +int main(int argc, char **argv) { + int ch; + + ::testing::InitGoogleTest(&argc, argv); + + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'v': + verbosity++; + break; + default: + usage(argv[0]); + break; + } + } + + return (RUN_ALL_TESTS()); +} Property changes on: projects/fuse2/tests/sys/fs/fuse/utils.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/fuse2/tests/sys/fs/fuse/utils.hh =================================================================== --- projects/fuse2/tests/sys/fs/fuse/utils.hh (nonexistent) +++ projects/fuse2/tests/sys/fs/fuse/utils.hh (revision 344715) @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2019 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by BFF Storage Systems, LLC under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#define GTEST_REQUIRE_KERNEL_MODULE(_mod_name) do { \ + if (modfind(_mod_name) == -1) { \ + printf("module %s could not be resolved: %s\n", \ + _mod_name, strerror(errno)); \ + /* + * TODO: enable GTEST_SKIP once GoogleTest 1.8.2 merges + * GTEST_SKIP() + */ \ + FAIL() << "Module " << _mod_name << " could not be resolved\n";\ + } \ +} while(0) + +class FuseTest : public ::testing::Test { + protected: + MockFS *m_mock = NULL; + + public: + void SetUp() { + GTEST_REQUIRE_KERNEL_MODULE("fuse"); + try { + m_mock = new MockFS{}; + } catch (std::system_error err) { + FAIL() << err.what(); + } + } + + void TearDown() { + if (m_mock) + delete m_mock; + } +};