Date: Tue, 5 Mar 2019 21:40:09 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r344824 - projects/fuse2/tests/sys/fs/fuse Message-ID: <201903052140.x25Le9CH044608@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: asomers Date: Tue Mar 5 21:40:08 2019 New Revision: 344824 URL: https://svnweb.freebsd.org/changeset/base/344824 Log: fuse(4): add test cases for FUSE_LINK and FUSE_RENAME Also, add a FUSE_LOOKUP test case for subdirectories, and improve debugging output. Sponsored by: The FreeBSD Foundation Added: projects/fuse2/tests/sys/fs/fuse/link.cc (contents, props changed) projects/fuse2/tests/sys/fs/fuse/rename.cc (contents, props changed) Modified: projects/fuse2/tests/sys/fs/fuse/Makefile projects/fuse2/tests/sys/fs/fuse/access.cc projects/fuse2/tests/sys/fs/fuse/create.cc projects/fuse2/tests/sys/fs/fuse/getattr.cc projects/fuse2/tests/sys/fs/fuse/lookup.cc projects/fuse2/tests/sys/fs/fuse/mkdir.cc projects/fuse2/tests/sys/fs/fuse/mknod.cc projects/fuse2/tests/sys/fs/fuse/mockfs.cc projects/fuse2/tests/sys/fs/fuse/mockfs.hh projects/fuse2/tests/sys/fs/fuse/open.cc projects/fuse2/tests/sys/fs/fuse/readlink.cc projects/fuse2/tests/sys/fs/fuse/setattr.cc projects/fuse2/tests/sys/fs/fuse/symlink.cc projects/fuse2/tests/sys/fs/fuse/utils.hh Modified: projects/fuse2/tests/sys/fs/fuse/Makefile ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/Makefile Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/Makefile Tue Mar 5 21:40:08 2019 (r344824) @@ -7,11 +7,13 @@ TESTSDIR= ${TESTSBASE}/sys/fs/fuse ATF_TESTS_CXX+= access ATF_TESTS_CXX+= create ATF_TESTS_CXX+= getattr +ATF_TESTS_CXX+= link ATF_TESTS_CXX+= lookup ATF_TESTS_CXX+= mkdir ATF_TESTS_CXX+= mknod ATF_TESTS_CXX+= open ATF_TESTS_CXX+= readlink +ATF_TESTS_CXX+= rename ATF_TESTS_CXX+= setattr ATF_TESTS_CXX+= symlink @@ -30,6 +32,11 @@ SRCS.getattr+= getmntopts.c SRCS.getattr+= mockfs.cc SRCS.getattr+= utils.cc +SRCS.link+= getmntopts.c +SRCS.link+= link.cc +SRCS.link+= mockfs.cc +SRCS.link+= utils.cc + SRCS.lookup+= getmntopts.c SRCS.lookup+= lookup.cc SRCS.lookup+= mockfs.cc @@ -54,6 +61,11 @@ SRCS.readlink+= getmntopts.c SRCS.readlink+= mockfs.cc SRCS.readlink+= readlink.cc SRCS.readlink+= utils.cc + +SRCS.rename+= getmntopts.c +SRCS.rename+= mockfs.cc +SRCS.rename+= rename.cc +SRCS.rename+= utils.cc SRCS.setattr+= getmntopts.c SRCS.setattr+= mockfs.cc Modified: projects/fuse2/tests/sys/fs/fuse/access.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/access.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/access.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -51,7 +51,7 @@ TEST_F(Access, DISABLED_eaccess) uint64_t ino = 42; mode_t access_mode = X_OK; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -80,7 +80,7 @@ TEST_F(Access, DISABLED_ok) uint64_t ino = 42; mode_t access_mode = R_OK; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; Modified: projects/fuse2/tests/sys/fs/fuse/create.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/create.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/create.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -51,7 +51,7 @@ TEST_F(Create, DISABLED_attr_cache) uint64_t ino = 42; int fd; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -94,7 +94,7 @@ TEST_F(Create, eexist) const char RELPATH[] = "some_file.txt"; mode_t mode = 0755; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -122,7 +122,7 @@ TEST_F(Create, DISABLED_Enosys) uint64_t ino = 42; int fd; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -197,7 +197,7 @@ TEST_F(Create, DISABLED_entry_cache_negative) int fd; /* create will first do a LOOKUP, adding a negative cache entry */ - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke([=](auto in, auto out) { /* nodeid means ENOENT and cache it */ out->body.entry.nodeid = 0; out->header.unique = in->header.unique; @@ -260,7 +260,7 @@ TEST_F(Create, DISABLED_entry_cache_negative_purge) int fd; /* create will first do a LOOKUP, adding a negative cache entry */ - EXPECT_LOOKUP(RELPATH).Times(1) + EXPECT_LOOKUP(1, RELPATH).Times(1) .WillOnce(Invoke([=](auto in, auto out) { /* nodeid means ENOENT and cache it */ out->body.entry.nodeid = 0; @@ -305,7 +305,7 @@ TEST_F(Create, DISABLED_entry_cache_negative_purge) ASSERT_LE(0, fd) << strerror(errno); /* Finally, a subsequent lookup should query the daemon */ - EXPECT_LOOKUP(RELPATH).Times(1) + EXPECT_LOOKUP(1, RELPATH).Times(1) .WillOnce(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; out->header.error = 0; @@ -328,7 +328,7 @@ TEST_F(Create, eperm) const char RELPATH[] = "some_file.txt"; mode_t mode = 0755; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -351,7 +351,7 @@ TEST_F(Create, ok) uint64_t ino = 42; int fd; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { Modified: projects/fuse2/tests/sys/fs/fuse/getattr.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/getattr.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/getattr.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -47,7 +47,7 @@ TEST_F(Getattr, DISABLED_attr_cache) const uint64_t generation = 13; struct stat sb; - EXPECT_LOOKUP(RELPATH).WillRepeatedly(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -91,7 +91,7 @@ TEST_F(Getattr, attr_cache_timeout) */ long timeout_ns = 250'000'000; - EXPECT_LOOKUP(RELPATH).WillRepeatedly(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -127,7 +127,7 @@ TEST_F(Getattr, enoent) struct stat sb; const uint64_t ino = 42; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; SET_OUT_HEADER_LEN(out, entry); out->body.entry.attr.mode = 0100644; @@ -153,7 +153,7 @@ TEST_F(Getattr, ok) const uint64_t generation = 13; struct stat sb; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; Added: projects/fuse2/tests/sys/fs/fuse/link.cc ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/fuse2/tests/sys/fs/fuse/link.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -0,0 +1,106 @@ +/*- + * 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 <unistd.h> +} + +#include "mockfs.hh" +#include "utils.hh" + +using namespace testing; + +class Link: public FuseTest {}; + +TEST_F(Link, emlink) +{ + const char FULLPATH[] = "mountpoint/lnk"; + const char RELPATH[] = "lnk"; + const char FULLDST[] = "mountpoint/dst"; + const char RELDST[] = "dst"; + uint64_t dst_ino = 42; + + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELDST).WillOnce(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = dst_ino; + SET_OUT_HEADER_LEN(out, entry); + })); + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + const char *name = (const char*)in->body.bytes + + sizeof(struct fuse_link_in); + return (in->header.opcode == FUSE_LINK && + in->body.link.oldnodeid == dst_ino && + (0 == strcmp(name, RELPATH))); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnErrno(EMLINK))); + + EXPECT_EQ(-1, link(FULLDST, FULLPATH)); + EXPECT_EQ(EMLINK, errno); +} + +TEST_F(Link, ok) +{ + const char FULLPATH[] = "mountpoint/src"; + const char RELPATH[] = "src"; + const char FULLDST[] = "mountpoint/dst"; + const char RELDST[] = "dst"; + uint64_t dst_ino = 42; + const uint64_t ino = 42; + + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELDST).WillOnce(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = dst_ino; + SET_OUT_HEADER_LEN(out, entry); + })); + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + const char *name = (const char*)in->body.bytes + + sizeof(struct fuse_link_in); + return (in->header.opcode == FUSE_LINK && + in->body.link.oldnodeid == dst_ino && + (0 == strcmp(name, RELPATH))); + }, 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; + })); + + EXPECT_EQ(0, link(FULLDST, FULLPATH)) << strerror(errno); +} Modified: projects/fuse2/tests/sys/fs/fuse/lookup.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/lookup.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/lookup.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -50,7 +50,7 @@ TEST_F(Lookup, DISABLED_attr_cache) const uint64_t ino = 42; struct stat sb; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; SET_OUT_HEADER_LEN(out, entry); out->body.entry.nodeid = ino; @@ -115,7 +115,7 @@ TEST_F(Lookup, attr_cache_timeout) */ long timeout_ns = 250'000'000; - EXPECT_LOOKUP(RELPATH).WillRepeatedly(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).WillRepeatedly(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; SET_OUT_HEADER_LEN(out, entry); out->body.entry.nodeid = ino; @@ -148,7 +148,7 @@ TEST_F(Lookup, enoent) const char FULLPATH[] = "mountpoint/does_not_exist"; const char RELPATH[] = "does_not_exist"; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_NE(0, access(FULLPATH, F_OK)); EXPECT_EQ(ENOENT, errno); } @@ -162,7 +162,7 @@ TEST_F(Lookup, entry_cache) const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt"; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -181,7 +181,7 @@ TEST_F(Lookup, entry_cache) /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236226 */ TEST_F(Lookup, DISABLED_entry_cache_negative) { - EXPECT_LOOKUP("does_not_exist").Times(1) + EXPECT_LOOKUP(1, "does_not_exist").Times(1) .WillOnce(Invoke([](auto in, auto out) { out->header.unique = in->header.unique; out->header.error = 0; @@ -206,7 +206,7 @@ TEST_F(Lookup, entry_cache_negative_timeout) */ long timeout_ns = 250'000'000; - EXPECT_LOOKUP(RELPATH).Times(2) + EXPECT_LOOKUP(1, RELPATH).Times(2) .WillRepeatedly(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; out->header.error = 0; @@ -239,7 +239,7 @@ TEST_F(Lookup, DISABLED_entry_cache_timeout) */ long timeout_ns = 250'000'000; - EXPECT_LOOKUP(RELPATH).Times(2) + EXPECT_LOOKUP(1, RELPATH).Times(2) .WillRepeatedly(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; SET_OUT_HEADER_LEN(out, entry); @@ -258,7 +258,7 @@ TEST_F(Lookup, ok) const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt"; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -270,3 +270,33 @@ TEST_F(Lookup, ok) */ ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno); } + +// Lookup in a subdirectory of the fuse mount +TEST_F(Lookup, subdir) +{ + const char FULLPATH[] = "mountpoint/some_dir/some_file.txt"; + const char DIRPATH[] = "some_dir"; + const char RELPATH[] = "some_file.txt"; + uint64_t dir_ino = 2; + uint64_t file_ino = 3; + + EXPECT_LOOKUP(1, DIRPATH).WillOnce(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + SET_OUT_HEADER_LEN(out, entry); + out->body.entry.attr.mode = S_IFDIR | 0755; + out->body.entry.nodeid = dir_ino; + })); + EXPECT_LOOKUP(dir_ino, RELPATH).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 = file_ino; + })); + /* + * 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); +} + + Modified: projects/fuse2/tests/sys/fs/fuse/mkdir.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/mkdir.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/mkdir.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -48,7 +48,7 @@ TEST_F(Mkdir, emlink) const char RELPATH[] = "some_dir"; mode_t mode = 0755; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -77,7 +77,7 @@ TEST_F(Mkdir, DISABLED_entry_cache_negative) uint64_t ino = 42; /* mkdir will first do a LOOKUP, adding a negative cache entry */ - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke([=](auto in, auto out) { /* nodeid means ENOENT and cache it */ out->body.entry.nodeid = 0; out->header.unique = in->header.unique; @@ -124,7 +124,7 @@ TEST_F(Mkdir, DISABLED_entry_cache_negative_purge) uint64_t ino = 42; /* mkdir will first do a LOOKUP, adding a negative cache entry */ - EXPECT_LOOKUP(RELPATH).Times(1) + EXPECT_LOOKUP(1, RELPATH).Times(1) .WillOnce(Invoke([=](auto in, auto out) { /* nodeid means ENOENT and cache it */ out->body.entry.nodeid = 0; @@ -155,7 +155,7 @@ TEST_F(Mkdir, DISABLED_entry_cache_negative_purge) ASSERT_EQ(0, mkdir(FULLPATH, mode)) << strerror(errno); /* Finally, a subsequent lookup should query the daemon */ - EXPECT_LOOKUP(RELPATH).Times(1) + EXPECT_LOOKUP(1, RELPATH).Times(1) .WillOnce(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; out->header.error = 0; @@ -174,7 +174,7 @@ TEST_F(Mkdir, ok) mode_t mode = 0755; uint64_t ino = 42; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { Modified: projects/fuse2/tests/sys/fs/fuse/mknod.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/mknod.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/mknod.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -54,7 +54,7 @@ void test_ok(mode_t mode, dev_t dev) { const char RELPATH[] = "some_file.txt"; uint64_t ino = 42; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -108,7 +108,7 @@ TEST_F(Mknod, DISABLED_eperm) const char RELPATH[] = "some_file.txt"; mode_t mode = S_IFIFO | 0755; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { Modified: projects/fuse2/tests/sys/fs/fuse/mockfs.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/mockfs.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/mockfs.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -116,6 +116,20 @@ void sigint_handler(int __unused sig) { quit = 1; } +void debug_fuseop(const mockfs_buf_in *in) +{ + printf("%s ino=%lu", opcode2opname(in->header.opcode), + in->header.nodeid); + switch (in->header.opcode) { + case FUSE_LOOKUP: + printf(" %s", in->body.lookup); + break; + default: + break; + } + printf("\n"); +} + MockFS::MockFS() { struct iovec *iov = NULL; int iovlen = 0; @@ -204,10 +218,8 @@ void MockFS::loop() { read_request(in); if (quit) break; - if (verbosity > 0) { - printf("Got request %s\n", - opcode2opname(in->header.opcode)); - } + if (verbosity > 0) + debug_fuseop(in); if ((pid_t)in->header.pid != m_pid) { /* * Reject any requests from unknown processes. Because Modified: projects/fuse2/tests/sys/fs/fuse/mockfs.hh ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/mockfs.hh Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/mockfs.hh Tue Mar 5 21:40:08 2019 (r344824) @@ -49,10 +49,11 @@ extern "C" { * This must be a macro instead of a method because EXPECT_CALL returns a type * with a deleted constructor. */ -#define EXPECT_LOOKUP(path) \ +#define EXPECT_LOOKUP(parent, path) \ EXPECT_CALL(*m_mock, process( \ ResultOf([=](auto in) { \ return (in->header.opcode == FUSE_LOOKUP && \ + in->header.nodeid == (parent) && \ strcmp(in->body.lookup, (path)) == 0); \ }, Eq(true)), \ _) \ @@ -72,10 +73,12 @@ union fuse_payloads_in { uint8_t bytes[0x21000 - sizeof(struct fuse_in_header)]; fuse_forget_in forget; fuse_init_in init; + fuse_link_in link; char lookup[0]; fuse_mkdir_in mkdir; fuse_mknod_in mknod; fuse_open_in open; + fuse_rename_in rename; fuse_setattr_in setattr; }; Modified: projects/fuse2/tests/sys/fs/fuse/open.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/open.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/open.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -49,7 +49,7 @@ TEST_F(Open, enoent) const char RELPATH[] = "some_file.txt"; uint64_t ino = 42; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -77,7 +77,7 @@ TEST_F(Open, eperm) const char RELPATH[] = "some_file.txt"; uint64_t ino = 42; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -102,7 +102,7 @@ TEST_F(Open, ok) uint64_t ino = 42; int fd; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; Modified: projects/fuse2/tests/sys/fs/fuse/readlink.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/readlink.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/readlink.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -45,7 +45,7 @@ TEST_F(Readlink, eloop) const uint64_t ino = 42; char buf[80]; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; SET_OUT_HEADER_LEN(out, entry); out->body.entry.attr.mode = S_IFLNK | 0777; @@ -72,7 +72,7 @@ TEST_F(Readlink, ok) const uint64_t ino = 42; char buf[80]; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke([=](auto in, auto out) { out->header.unique = in->header.unique; SET_OUT_HEADER_LEN(out, entry); out->body.entry.attr.mode = S_IFLNK | 0777; Added: projects/fuse2/tests/sys/fs/fuse/rename.cc ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/fuse2/tests/sys/fs/fuse/rename.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -0,0 +1,188 @@ +/*- + * 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 <stdlib.h> +#include <unistd.h> +} + +#include "mockfs.hh" +#include "utils.hh" + +using namespace testing; + +class Rename: public FuseTest { + public: + int tmpfd = -1; + char tmpfile[80] = "/tmp/fuse.rename.XXXXXX"; + + virtual void TearDown() { + if (tmpfd >= 0) { + close(tmpfd); + unlink(tmpfile); + } + + FuseTest::TearDown(); + } +}; + +// EINVAL, dst is subdir of src +TEST_F(Rename, einval) +{ + const char FULLDST[] = "mountpoint/src/dst"; + const char RELDST[] = "dst"; + const char FULLSRC[] = "mountpoint/src"; + const char RELSRC[] = "src"; + uint64_t src_ino = 42; + + EXPECT_LOOKUP(1, RELSRC).WillRepeatedly(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + out->body.entry.attr.mode = S_IFDIR | 0755; + out->body.entry.nodeid = src_ino; + SET_OUT_HEADER_LEN(out, entry); + })); + EXPECT_LOOKUP(src_ino, RELDST).WillOnce(Invoke(ReturnErrno(ENOENT))); + + ASSERT_NE(0, rename(FULLSRC, FULLDST)); + ASSERT_EQ(EINVAL, errno); +} + +// source does not exist +TEST_F(Rename, enoent) +{ + const char FULLDST[] = "mountpoint/dst"; + const char FULLSRC[] = "mountpoint/src"; + const char RELSRC[] = "src"; + // FUSE hardcodes the mountpoint to inocde 1 + + EXPECT_LOOKUP(1, RELSRC).WillOnce(Invoke(ReturnErrno(ENOENT))); + + ASSERT_NE(0, rename(FULLSRC, FULLDST)); + ASSERT_EQ(ENOENT, errno); +} + +TEST_F(Rename, exdev) +{ + const char FULLB[] = "mountpoint/src"; + const char RELB[] = "src"; + // FUSE hardcodes the mountpoint to inocde 1 + uint64_t b_ino = 42; + + tmpfd = mkstemp(tmpfile); + ASSERT_LE(0, tmpfd) << strerror(errno); + + EXPECT_LOOKUP(1, RELB).WillRepeatedly(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = b_ino; + SET_OUT_HEADER_LEN(out, entry); + })); + + ASSERT_NE(0, rename(tmpfile, FULLB)); + ASSERT_EQ(EXDEV, errno); + + ASSERT_NE(0, rename(FULLB, tmpfile)); + ASSERT_EQ(EXDEV, errno); +} + +TEST_F(Rename, ok) +{ + const char FULLDST[] = "mountpoint/dst"; + const char RELDST[] = "dst"; + const char FULLSRC[] = "mountpoint/src"; + const char RELSRC[] = "src"; + // FUSE hardcodes the mountpoint to inocde 1 + uint64_t dst_dir_ino = 1; + uint64_t ino = 42; + + EXPECT_LOOKUP(1, RELSRC).WillOnce(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = ino; + SET_OUT_HEADER_LEN(out, entry); + })); + EXPECT_LOOKUP(1, RELDST).WillOnce(Invoke(ReturnErrno(ENOENT))); + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + const char *src = (const char*)in->body.bytes + + sizeof(fuse_rename_in); + const char *dst = src + strlen(src) + 1; + return (in->header.opcode == FUSE_RENAME && + in->body.rename.newdir == dst_dir_ino && + (0 == strcmp(RELDST, dst)) && + (0 == strcmp(RELSRC, src))); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnErrno(0))); + + ASSERT_EQ(0, rename(FULLSRC, FULLDST)) << strerror(errno); +} + +// Rename overwrites an existing destination file +TEST_F(Rename, overwrite) +{ + const char FULLDST[] = "mountpoint/dst"; + const char RELDST[] = "dst"; + const char FULLSRC[] = "mountpoint/src"; + const char RELSRC[] = "src"; + // The inode of the already-existing destination file + uint64_t dst_ino = 2; + // FUSE hardcodes the mountpoint to inocde 1 + uint64_t dst_dir_ino = 1; + uint64_t ino = 42; + + EXPECT_LOOKUP(1, RELSRC).WillOnce(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = ino; + SET_OUT_HEADER_LEN(out, entry); + })); + EXPECT_LOOKUP(1, RELDST).WillOnce(Invoke([=](auto in, auto out) { + out->header.unique = in->header.unique; + out->body.entry.attr.mode = S_IFREG | 0644; + out->body.entry.nodeid = dst_ino; + SET_OUT_HEADER_LEN(out, entry); + })); + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + const char *src = (const char*)in->body.bytes + + sizeof(fuse_rename_in); + const char *dst = src + strlen(src) + 1; + return (in->header.opcode == FUSE_RENAME && + in->body.rename.newdir == dst_dir_ino && + (0 == strcmp(RELDST, dst)) && + (0 == strcmp(RELSRC, src))); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnErrno(0))); + + ASSERT_EQ(0, rename(FULLSRC, FULLDST)) << strerror(errno); +} Modified: projects/fuse2/tests/sys/fs/fuse/setattr.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/setattr.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/setattr.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -50,7 +50,7 @@ TEST_F(Setattr, chmod) const mode_t oldmode = 0755; const mode_t newmode = 0644; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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 | oldmode; @@ -88,7 +88,7 @@ TEST_F(Setattr, chown) const uid_t olduser = 33; const uid_t newuser = 44; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -132,7 +132,7 @@ TEST_F(Setattr, eperm) const char RELPATH[] = "some_file.txt"; const uint64_t ino = 42; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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 | 0777; @@ -162,7 +162,7 @@ TEST_F(Setattr, fchmod) const mode_t oldmode = 0755; const mode_t newmode = 0644; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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 | oldmode; @@ -230,7 +230,7 @@ TEST_F(Setattr, ftruncate) const off_t oldsize = 99; const off_t newsize = 12345; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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 | 0755; @@ -299,7 +299,7 @@ TEST_F(Setattr, truncate) { const uint64_t oldsize = 100'000'000; const uint64_t newsize = 20'000'000; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -341,7 +341,7 @@ TEST_F(Setattr, utimensat) { {.tv_sec = 7, .tv_nsec = 8}, }; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; @@ -417,7 +417,7 @@ TEST_F(Setattr, utimensat_mtime_only) { {.tv_sec = 7, .tv_nsec = 8}, }; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke([=](auto in, auto out) { + EXPECT_LOOKUP(1, RELPATH).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; Modified: projects/fuse2/tests/sys/fs/fuse/symlink.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/symlink.cc Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/symlink.cc Tue Mar 5 21:40:08 2019 (r344824) @@ -44,7 +44,7 @@ TEST_F(Symlink, enospc) const char RELPATH[] = "lnk"; const char dst[] = "dst"; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -55,13 +55,8 @@ TEST_F(Symlink, enospc) (0 == strcmp(name, RELPATH))); }, Eq(true)), _) - ).WillOnce(Invoke([=](auto in, auto out) { - out->header.unique = in->header.unique; - out->header.error = -ENOSPC; - out->header.len = sizeof(out->header); - })); + ).WillOnce(Invoke(ReturnErrno(ENOSPC))); - EXPECT_EQ(-1, symlink(dst, FULLPATH)); EXPECT_EQ(ENOSPC, errno); } @@ -73,7 +68,7 @@ TEST_F(Symlink, ok) const char dst[] = "dst"; const uint64_t ino = 42; - EXPECT_LOOKUP(RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); + EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { Modified: projects/fuse2/tests/sys/fs/fuse/utils.hh ============================================================================== --- projects/fuse2/tests/sys/fs/fuse/utils.hh Tue Mar 5 19:45:37 2019 (r344823) +++ projects/fuse2/tests/sys/fs/fuse/utils.hh Tue Mar 5 21:40:08 2019 (r344824) @@ -40,7 +40,7 @@ class FuseTest : public ::testing::Test { } } - void TearDown() { + virtual void TearDown() { if (m_mock) delete m_mock; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903052140.x25Le9CH044608>