fuse(4): combine common code in the tests
Combine a bunch of mostly similar expect_* methods into utils.cc, and only define FH in a single place. Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
bed5b48ade
commit
f496adcf86
@ -39,7 +39,13 @@ extern "C" {
|
||||
|
||||
using namespace testing;
|
||||
|
||||
class Access: public FuseTest {};
|
||||
class Access: public FuseTest {
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
};
|
||||
|
||||
/* TODO: test methods for the default_permissions mount option */
|
||||
|
||||
@ -52,12 +58,7 @@ TEST_F(Access, DISABLED_eaccess)
|
||||
uint64_t ino = 42;
|
||||
mode_t access_mode = X_OK;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_ACCESS &&
|
||||
@ -81,12 +82,7 @@ TEST_F(Access, DISABLED_ok)
|
||||
uint64_t ino = 42;
|
||||
mode_t access_mode = R_OK;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_ACCESS &&
|
||||
|
@ -295,14 +295,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(1, RELPATH).Times(1)
|
||||
.WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.error = 0;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.mode = S_IFREG | mode;
|
||||
SET_OUT_HEADER_LEN(out, entry);
|
||||
}));
|
||||
expect_lookup(RELPATH, ino, S_IFREG | mode, 1);
|
||||
|
||||
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
|
||||
/* Deliberately leak fd. close(2) will be tested in release.cc */
|
||||
|
@ -40,8 +40,6 @@ using namespace testing;
|
||||
|
||||
class Flush: public FuseTest {
|
||||
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
|
||||
public:
|
||||
void expect_flush(uint64_t ino, int times, ProcessMockerT r)
|
||||
{
|
||||
@ -49,58 +47,16 @@ void expect_flush(uint64_t ino, int times, ProcessMockerT r)
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_FLUSH &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.flush.fh == Flush::FH);
|
||||
in->body.flush.fh == FH);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke(r));
|
||||
}
|
||||
|
||||
void expect_getattr(uint64_t ino)
|
||||
{
|
||||
/* Until the attr cache is working, we may send an additional GETATTR */
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(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;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_open(uint64_t ino, int times)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke([](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = Flush::FH;
|
||||
}));
|
||||
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -130,8 +86,8 @@ TEST_F(Flush, DISABLED_dup)
|
||||
int fd, fd2;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 1);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_flush(ino, 2, ReturnErrno(0));
|
||||
expect_release();
|
||||
|
||||
@ -161,8 +117,8 @@ TEST_F(Flush, DISABLED_eio)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 1);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_flush(ino, 1, ReturnErrno(EIO));
|
||||
expect_release();
|
||||
|
||||
@ -182,8 +138,8 @@ TEST_F(Flush, DISABLED_flush)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 1);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_flush(ino, 1, ReturnErrno(0));
|
||||
expect_release();
|
||||
|
||||
|
@ -50,7 +50,6 @@ using namespace testing;
|
||||
|
||||
class Fsync: public FuseTest {
|
||||
public:
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
void expect_fsync(uint64_t ino, uint32_t flags, int error)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
@ -65,79 +64,14 @@ void expect_fsync(uint64_t ino, uint32_t flags, int error)
|
||||
).WillOnce(Invoke(ReturnErrno(error)));
|
||||
}
|
||||
|
||||
void expect_getattr(uint64_t ino)
|
||||
{
|
||||
/* Until the attr cache is working, we may send an additional GETATTR */
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(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_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_open(uint64_t ino)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = FH;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_release(uint64_t ino)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_RELEASE &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke(ReturnErrno(0)));
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
|
||||
void expect_write(uint64_t ino, uint64_t size, const void *contents)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
const char *buf = (const char*)in->body.bytes +
|
||||
sizeof(struct fuse_write_in);
|
||||
|
||||
return (in->header.opcode == FUSE_WRITE &&
|
||||
in->header.nodeid == ino &&
|
||||
0 == bcmp(buf, contents, size));
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
SET_OUT_HEADER_LEN(out, write);
|
||||
out->body.write.size = size;
|
||||
}));
|
||||
FuseTest::expect_write(ino, 0, size, size, 0, contents);
|
||||
}
|
||||
|
||||
};
|
||||
@ -156,8 +90,8 @@ TEST_F(Fsync, DISABLED_aio_fsync)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_write(ino, bufsize, CONTENTS);
|
||||
expect_fsync(ino, 0, 0);
|
||||
|
||||
@ -190,8 +124,8 @@ TEST_F(Fsync, close)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_write(ino, bufsize, CONTENTS);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
@ -209,7 +143,7 @@ TEST_F(Fsync, close)
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(0);
|
||||
expect_release(ino);
|
||||
expect_release(ino, 1, 0);
|
||||
|
||||
fd = open(FULLPATH, O_RDWR);
|
||||
ASSERT_LE(0, fd) << strerror(errno);
|
||||
@ -228,8 +162,8 @@ TEST_F(Fsync, DISABLED_eio)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_write(ino, bufsize, CONTENTS);
|
||||
expect_fsync(ino, FUSE_FSYNC_FDATASYNC, EIO);
|
||||
|
||||
@ -253,8 +187,8 @@ TEST_F(Fsync, DISABLED_fdatasync)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_write(ino, bufsize, CONTENTS);
|
||||
expect_fsync(ino, FUSE_FSYNC_FDATASYNC, 0);
|
||||
|
||||
@ -278,8 +212,8 @@ TEST_F(Fsync, DISABLED_fsync)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_write(ino, bufsize, CONTENTS);
|
||||
expect_fsync(ino, 0, 0);
|
||||
|
||||
@ -303,8 +237,8 @@ TEST_F(Fsync, DISABLED_fsync_metadata_only)
|
||||
mode_t mode = 0755;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_SETATTR);
|
||||
@ -335,8 +269,8 @@ TEST_F(Fsync, nop)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
|
||||
fd = open(FULLPATH, O_WRONLY);
|
||||
ASSERT_LE(0, fd) << strerror(errno);
|
||||
@ -346,4 +280,4 @@ TEST_F(Fsync, nop)
|
||||
/* Deliberately leak fd. close(2) will be tested in release.cc */
|
||||
}
|
||||
|
||||
|
||||
// TODO: ENOSYS test
|
||||
|
@ -50,7 +50,6 @@ using namespace testing;
|
||||
|
||||
class FsyncDir: public FuseTest {
|
||||
public:
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
void expect_fsyncdir(uint64_t ino, uint32_t flags, int error)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
@ -67,29 +66,7 @@ void expect_fsyncdir(uint64_t ino, uint32_t flags, int error)
|
||||
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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_IFDIR | 0755;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_opendir(uint64_t ino)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPENDIR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = FH;
|
||||
}));
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 1);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -45,7 +45,6 @@ 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_LOOKUP(1, RELPATH).WillRepeatedly(Invoke([=](auto in, auto out) {
|
||||
@ -53,7 +52,6 @@ TEST_F(Getattr, DISABLED_attr_cache)
|
||||
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) {
|
||||
@ -84,7 +82,6 @@ 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
|
||||
@ -92,14 +89,7 @@ TEST_F(Getattr, attr_cache_timeout)
|
||||
*/
|
||||
long timeout_ns = 250'000'000;
|
||||
|
||||
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;
|
||||
out->body.entry.attr.mode = S_IFREG | 0644;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.generation = generation;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino, S_IFREG | 0644, 2);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
@ -128,13 +118,7 @@ TEST_F(Getattr, enoent)
|
||||
struct stat sb;
|
||||
const uint64_t ino = 42;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
}));
|
||||
|
||||
expect_lookup(RELPATH, ino, S_IFREG | 0644, 1);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
@ -151,16 +135,9 @@ 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_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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.generation = generation;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino, S_IFREG | 0644, 1);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
@ -202,9 +179,6 @@ TEST_F(Getattr, ok)
|
||||
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);
|
||||
|
@ -37,7 +37,13 @@ extern "C" {
|
||||
|
||||
using namespace testing;
|
||||
|
||||
class Link: public FuseTest {};
|
||||
class Link: public FuseTest {
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Link, emlink)
|
||||
{
|
||||
@ -48,12 +54,7 @@ TEST_F(Link, emlink)
|
||||
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_lookup(RELDST, dst_ino);
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
@ -80,12 +81,7 @@ TEST_F(Link, ok)
|
||||
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_lookup(RELDST, dst_ino);
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
|
@ -43,51 +43,10 @@ using namespace testing;
|
||||
/* For testing filesystems without posix locking support */
|
||||
class Fallback: public FuseTest {
|
||||
public:
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
|
||||
void expect_getattr(uint64_t ino)
|
||||
{
|
||||
/* Until the attr cache is working, we may send an additional GETATTR */
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(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_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_open(uint64_t ino)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = FH;
|
||||
}));
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
|
||||
};
|
||||
@ -120,8 +79,8 @@ TEST_F(GetlkFallback, local)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
|
||||
fd = open(FULLPATH, O_RDWR);
|
||||
ASSERT_LE(0, fd) << strerror(errno);
|
||||
@ -150,8 +109,8 @@ TEST_F(Getlk, DISABLED_no_locks)
|
||||
pid_t pid = 1234;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETLK &&
|
||||
@ -197,8 +156,8 @@ TEST_F(Getlk, DISABLED_lock_exists)
|
||||
pid_t pid2 = 1234;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETLK &&
|
||||
@ -251,8 +210,8 @@ TEST_F(SetlkFallback, local)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
|
||||
fd = open(FULLPATH, O_RDWR);
|
||||
ASSERT_LE(0, fd) << strerror(errno);
|
||||
@ -278,8 +237,8 @@ TEST_F(Setlk, DISABLED_set)
|
||||
pid_t pid = 1234;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_SETLK &&
|
||||
@ -323,8 +282,8 @@ TEST_F(Setlk, DISABLED_set_eof)
|
||||
pid_t pid = 1234;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_SETLK &&
|
||||
@ -368,8 +327,8 @@ TEST_F(Setlk, DISABLED_eagain)
|
||||
pid_t pid = 1234;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_SETLK &&
|
||||
@ -410,8 +369,8 @@ TEST_F(SetlkwFallback, local)
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
|
||||
fd = open(FULLPATH, O_RDWR);
|
||||
ASSERT_LE(0, fd) << strerror(errno);
|
||||
@ -441,8 +400,8 @@ TEST_F(Setlkw, DISABLED_set)
|
||||
pid_t pid = 1234;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino);
|
||||
expect_getattr(ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_SETLK &&
|
||||
|
@ -49,6 +49,7 @@ TEST_F(Lookup, 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_LOOKUP(1, RELPATH).WillOnce(Invoke([=](auto in, auto out) {
|
||||
@ -70,6 +71,7 @@ TEST_F(Lookup, DISABLED_attr_cache)
|
||||
out->body.entry.attr.uid = 10;
|
||||
out->body.entry.attr.gid = 11;
|
||||
out->body.entry.attr.rdev = 12;
|
||||
out->body.entry.generation = generation;
|
||||
}));
|
||||
/* stat(2) issues a VOP_LOOKUP followed by a VOP_GETATTR */
|
||||
ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno);
|
||||
@ -124,18 +126,7 @@ TEST_F(Lookup, attr_cache_timeout)
|
||||
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;
|
||||
}));
|
||||
expect_getattr(ino, 0);
|
||||
|
||||
/* access(2) will issue a VOP_LOOKUP but not a VOP_GETATTR */
|
||||
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
|
||||
@ -246,6 +237,12 @@ TEST_F(Lookup, DISABLED_entry_cache_timeout)
|
||||
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
|
||||
}
|
||||
|
||||
// TODO: export_support
|
||||
// After upgrading the protocol to 7.10, check that the kernel will only
|
||||
// attempt to lookup "." and ".." if the filesystem sets FUSE_EXPORT_SUPPORT in
|
||||
// the init flags. If not, then all lookups for those entries will return
|
||||
// ESTALE.
|
||||
|
||||
TEST_F(Lookup, ok)
|
||||
{
|
||||
const char FULLPATH[] = "mountpoint/some_file.txt";
|
||||
|
@ -145,14 +145,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(1, RELPATH).Times(1)
|
||||
.WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.error = 0;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.mode = S_IFDIR | mode;
|
||||
SET_OUT_HEADER_LEN(out, entry);
|
||||
}));
|
||||
expect_lookup(RELPATH, ino, S_IFDIR | mode, 1);
|
||||
|
||||
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
|
||||
}
|
||||
|
@ -48,14 +48,7 @@ void test_ok(int os_flags, int fuse_flags) {
|
||||
uint64_t ino = 42;
|
||||
int fd;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
|
||||
FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, 1);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
@ -101,13 +94,7 @@ TEST_F(Open, enoent)
|
||||
const char RELPATH[] = "some_file.txt";
|
||||
uint64_t ino = 42;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
}));
|
||||
|
||||
expect_lookup(RELPATH, ino, S_IFREG | 0644, 1);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
@ -129,13 +116,7 @@ TEST_F(Open, eperm)
|
||||
const char RELPATH[] = "some_file.txt";
|
||||
uint64_t ino = 42;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
}));
|
||||
|
||||
expect_lookup(RELPATH, ino, S_IFREG | 0644, 1);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
|
@ -42,13 +42,7 @@ class Opendir: public FuseTest {
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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_IFDIR | 0755;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -48,72 +48,9 @@ using namespace testing;
|
||||
class Read: public FuseTest {
|
||||
|
||||
public:
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
void expect_getattr(uint64_t ino, uint64_t size)
|
||||
{
|
||||
/* Until the attr cache is working, we may send an additional GETATTR */
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(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 = size;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_open(uint64_t ino, uint32_t flags, int times)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = Read::FH;
|
||||
out->body.open.open_flags = flags;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_read(uint64_t ino, uint64_t offset, uint64_t isize, uint64_t osize,
|
||||
const void *contents)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_READ &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.read.fh == Read::FH &&
|
||||
in->body.read.offset == offset &&
|
||||
in->body.read.size == isize);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(struct fuse_out_header) + osize;
|
||||
memmove(out->body.bytes, contents, osize);
|
||||
})).RetiresOnSaturation();
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -40,43 +40,10 @@ using namespace testing;
|
||||
using namespace std;
|
||||
|
||||
class Readdir: public FuseTest {
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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_IFDIR | 0755;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_opendir(uint64_t ino)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([](auto in) {
|
||||
return (in->header.opcode == FUSE_STATFS);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
SET_OUT_HEADER_LEN(out, statfs);
|
||||
}));
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPENDIR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = FH;
|
||||
}));
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 1);
|
||||
}
|
||||
|
||||
void expect_readdir(uint64_t ino, uint64_t off, vector<struct dirent> &ents)
|
||||
|
@ -37,7 +37,13 @@ extern "C" {
|
||||
|
||||
using namespace testing;
|
||||
|
||||
class Readlink: public FuseTest {};
|
||||
class Readlink: public FuseTest {
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFLNK | 0777, 1);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Readlink, eloop)
|
||||
{
|
||||
@ -46,12 +52,7 @@ TEST_F(Readlink, eloop)
|
||||
const uint64_t ino = 42;
|
||||
char buf[80];
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
@ -73,12 +74,7 @@ TEST_F(Readlink, ok)
|
||||
const uint64_t ino = 42;
|
||||
char buf[80];
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
|
@ -40,67 +40,10 @@ using namespace testing;
|
||||
|
||||
class Release: public FuseTest {
|
||||
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
|
||||
public:
|
||||
void expect_getattr(uint64_t ino)
|
||||
void expect_lookup(const char *relpath, uint64_t ino, int times)
|
||||
{
|
||||
/* Until the attr cache is working, we may send an additional GETATTR */
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(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;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_open(uint64_t ino, int times)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke([](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = Release::FH;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
void expect_release(uint64_t ino, int times, ProcessMockerT r)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_RELEASE &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.release.fh == Release::FH);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke(r));
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, times);
|
||||
}
|
||||
};
|
||||
|
||||
@ -114,10 +57,10 @@ TEST_F(Release, dup)
|
||||
uint64_t ino = 42;
|
||||
int fd, fd2;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 1);
|
||||
expect_getattr(ino);
|
||||
expect_release(ino, 1, ReturnErrno(0));
|
||||
expect_lookup(RELPATH, ino, 1);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_release(ino, 1, 0);
|
||||
|
||||
fd = open(FULLPATH, O_RDONLY);
|
||||
EXPECT_LE(0, fd) << strerror(errno);
|
||||
@ -143,10 +86,10 @@ TEST_F(Release, eio)
|
||||
uint64_t ino = 42;
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 1);
|
||||
expect_getattr(ino);
|
||||
expect_release(ino, 1, ReturnErrno(EIO));
|
||||
expect_lookup(RELPATH, ino, 1);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_release(ino, 1, EIO);
|
||||
|
||||
fd = open(FULLPATH, O_WRONLY);
|
||||
EXPECT_LE(0, fd) << strerror(errno);
|
||||
@ -166,10 +109,10 @@ TEST_F(Release, multiple_opens)
|
||||
uint64_t ino = 42;
|
||||
int fd, fd2;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 2);
|
||||
expect_getattr(ino);
|
||||
expect_release(ino, 2, ReturnErrno(0));
|
||||
expect_lookup(RELPATH, ino, 2);
|
||||
expect_open(ino, 0, 2);
|
||||
expect_getattr(ino, 0);
|
||||
expect_release(ino, 2, 0);
|
||||
|
||||
fd = open(FULLPATH, O_RDONLY);
|
||||
EXPECT_LE(0, fd) << strerror(errno);
|
||||
@ -188,10 +131,10 @@ TEST_F(Release, ok)
|
||||
uint64_t ino = 42;
|
||||
int fd;
|
||||
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 1);
|
||||
expect_getattr(ino);
|
||||
expect_release(ino, 1, ReturnErrno(0));
|
||||
expect_lookup(RELPATH, ino, 1);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_release(ino, 1, 0);
|
||||
|
||||
fd = open(FULLPATH, O_RDONLY);
|
||||
EXPECT_LE(0, fd) << strerror(errno);
|
||||
|
@ -39,44 +39,10 @@ using namespace testing;
|
||||
|
||||
class ReleaseDir: public FuseTest {
|
||||
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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_IFDIR | 0755;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_opendir(uint64_t ino)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([](auto in) {
|
||||
return (in->header.opcode == FUSE_STATFS);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
SET_OUT_HEADER_LEN(out, statfs);
|
||||
}));
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPENDIR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = FH;
|
||||
}));
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 1);
|
||||
}
|
||||
|
||||
void expect_releasedir(uint64_t ino, ProcessMockerT r)
|
||||
|
@ -62,12 +62,7 @@ TEST_F(Rename, einval)
|
||||
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(RELSRC, src_ino, S_IFDIR | 0755, 2);
|
||||
EXPECT_LOOKUP(src_ino, RELDST).WillOnce(Invoke(ReturnErrno(ENOENT)));
|
||||
|
||||
ASSERT_NE(0, rename(FULLSRC, FULLDST));
|
||||
@ -80,7 +75,7 @@ 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
|
||||
// FUSE hardcodes the mountpoint to inode 1
|
||||
|
||||
EXPECT_LOOKUP(1, RELSRC).WillOnce(Invoke(ReturnErrno(ENOENT)));
|
||||
|
||||
@ -98,7 +93,7 @@ TEST_F(Rename, DISABLED_entry_cache_negative)
|
||||
const char RELDST[] = "dst";
|
||||
const char FULLSRC[] = "mountpoint/src";
|
||||
const char RELSRC[] = "src";
|
||||
// FUSE hardcodes the mountpoint to inocde 1
|
||||
// FUSE hardcodes the mountpoint to inode 1
|
||||
uint64_t dst_dir_ino = 1;
|
||||
uint64_t ino = 42;
|
||||
/*
|
||||
@ -108,13 +103,7 @@ TEST_F(Rename, DISABLED_entry_cache_negative)
|
||||
*/
|
||||
struct timespec entry_valid = {.tv_sec = 0, .tv_nsec = 0};
|
||||
|
||||
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(RELSRC, ino, S_IFREG | 0644, 1);
|
||||
/* LOOKUP returns a negative cache entry for dst */
|
||||
EXPECT_LOOKUP(1, RELDST).WillOnce(ReturnNegativeCache(&entry_valid));
|
||||
|
||||
@ -144,7 +133,7 @@ TEST_F(Rename, DISABLED_entry_cache_negative_purge)
|
||||
const char RELDST[] = "dst";
|
||||
const char FULLSRC[] = "mountpoint/src";
|
||||
const char RELSRC[] = "src";
|
||||
// FUSE hardcodes the mountpoint to inocde 1
|
||||
// FUSE hardcodes the mountpoint to inode 1
|
||||
uint64_t dst_dir_ino = 1;
|
||||
uint64_t ino = 42;
|
||||
/*
|
||||
@ -154,13 +143,7 @@ TEST_F(Rename, DISABLED_entry_cache_negative_purge)
|
||||
*/
|
||||
struct timespec entry_valid = {.tv_sec = 0, .tv_nsec = 0};
|
||||
|
||||
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(RELSRC, ino, S_IFREG | 0644, 1);
|
||||
/* LOOKUP returns a negative cache entry for dst */
|
||||
EXPECT_LOOKUP(1, RELDST).WillOnce(ReturnNegativeCache(&entry_valid))
|
||||
.RetiresOnSaturation();
|
||||
@ -181,14 +164,7 @@ TEST_F(Rename, DISABLED_entry_cache_negative_purge)
|
||||
ASSERT_EQ(0, rename(FULLSRC, FULLDST)) << strerror(errno);
|
||||
|
||||
/* Finally, a subsequent lookup should query the daemon */
|
||||
EXPECT_LOOKUP(1, RELDST).Times(1)
|
||||
.WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.error = 0;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.mode = S_IFREG | 0644;
|
||||
SET_OUT_HEADER_LEN(out, entry);
|
||||
}));
|
||||
expect_lookup(RELSRC, ino, S_IFREG | 0644, 1);
|
||||
|
||||
ASSERT_EQ(0, access(FULLDST, F_OK)) << strerror(errno);
|
||||
}
|
||||
@ -197,18 +173,13 @@ TEST_F(Rename, exdev)
|
||||
{
|
||||
const char FULLB[] = "mountpoint/src";
|
||||
const char RELB[] = "src";
|
||||
// FUSE hardcodes the mountpoint to inocde 1
|
||||
// FUSE hardcodes the mountpoint to inode 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);
|
||||
}));
|
||||
expect_lookup(RELB, b_ino, S_IFREG | 0644, 2);
|
||||
|
||||
ASSERT_NE(0, rename(tmpfile, FULLB));
|
||||
ASSERT_EQ(EXDEV, errno);
|
||||
@ -223,16 +194,11 @@ TEST_F(Rename, ok)
|
||||
const char RELDST[] = "dst";
|
||||
const char FULLSRC[] = "mountpoint/src";
|
||||
const char RELSRC[] = "src";
|
||||
// FUSE hardcodes the mountpoint to inocde 1
|
||||
// FUSE hardcodes the mountpoint to inode 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(RELSRC, ino, S_IFREG | 0644, 1);
|
||||
EXPECT_LOOKUP(1, RELDST).WillOnce(Invoke(ReturnErrno(ENOENT)));
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
@ -260,23 +226,12 @@ TEST_F(Rename, overwrite)
|
||||
const char RELSRC[] = "src";
|
||||
// The inode of the already-existing destination file
|
||||
uint64_t dst_ino = 2;
|
||||
// FUSE hardcodes the mountpoint to inocde 1
|
||||
// FUSE hardcodes the mountpoint to inode 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_lookup(RELSRC, ino, S_IFREG | 0644, 1);
|
||||
expect_lookup(RELDST, dst_ino, S_IFREG | 0644, 1);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
const char *src = (const char*)in->body.bytes +
|
||||
|
@ -37,7 +37,19 @@ extern "C" {
|
||||
|
||||
using namespace testing;
|
||||
|
||||
class Rmdir: public FuseTest {};
|
||||
class Rmdir: public FuseTest {
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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_IFDIR | 0755;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.nlink = 2;
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Rmdir, enotempty)
|
||||
{
|
||||
@ -45,13 +57,7 @@ TEST_F(Rmdir, enotempty)
|
||||
const char RELPATH[] = "some_dir";
|
||||
uint64_t ino = 42;
|
||||
|
||||
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_IFDIR | 0755;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.nlink = 2;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_RMDIR &&
|
||||
@ -71,13 +77,7 @@ TEST_F(Rmdir, ok)
|
||||
const char RELPATH[] = "some_dir";
|
||||
uint64_t ino = 42;
|
||||
|
||||
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_IFDIR | 0755;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.nlink = 2;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_RMDIR &&
|
||||
|
@ -36,7 +36,13 @@ extern "C" {
|
||||
|
||||
using namespace testing;
|
||||
|
||||
class Unlink: public FuseTest {};
|
||||
class Unlink: public FuseTest {
|
||||
public:
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Unlink, eperm)
|
||||
{
|
||||
@ -44,13 +50,7 @@ TEST_F(Unlink, eperm)
|
||||
const char RELPATH[] = "some_file.txt";
|
||||
uint64_t ino = 42;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.nlink = 1;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_UNLINK &&
|
||||
@ -70,13 +70,7 @@ TEST_F(Unlink, ok)
|
||||
const char RELPATH[] = "some_file.txt";
|
||||
uint64_t ino = 42;
|
||||
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.nlink = 1;
|
||||
}));
|
||||
expect_lookup(RELPATH, ino);
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_UNLINK &&
|
||||
|
@ -38,7 +38,9 @@
|
||||
#include "mockfs.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
class FuseEnv: public ::testing::Environment {
|
||||
using namespace testing;
|
||||
|
||||
class FuseEnv: public Environment {
|
||||
virtual void SetUp() {
|
||||
const char *mod_name = "fuse";
|
||||
const char *devnode = "/dev/fuse";
|
||||
@ -82,6 +84,146 @@ void FuseTest::SetUp() {
|
||||
}
|
||||
}
|
||||
|
||||
void FuseTest::expect_getattr(uint64_t ino, uint64_t size)
|
||||
{
|
||||
/* Until the attr cache is working, we may send an additional GETATTR */
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(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 = size;
|
||||
out->body.attr.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void FuseTest::expect_lookup(const char *relpath, uint64_t ino, mode_t mode,
|
||||
int times)
|
||||
{
|
||||
EXPECT_LOOKUP(1, relpath)
|
||||
.Times(times)
|
||||
.WillRepeatedly(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
SET_OUT_HEADER_LEN(out, entry);
|
||||
out->body.entry.attr.mode = mode;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr.nlink = 1;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void FuseTest::expect_open(uint64_t ino, uint32_t flags, int times)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = FH;
|
||||
out->body.open.open_flags = flags;
|
||||
}));
|
||||
}
|
||||
|
||||
void FuseTest::expect_opendir(uint64_t ino)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([](auto in) {
|
||||
return (in->header.opcode == FUSE_STATFS);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
SET_OUT_HEADER_LEN(out, statfs);
|
||||
}));
|
||||
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPENDIR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = FH;
|
||||
}));
|
||||
}
|
||||
|
||||
void FuseTest::expect_read(uint64_t ino, uint64_t offset, uint64_t isize,
|
||||
uint64_t osize, const void *contents)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_READ &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.read.fh == FH &&
|
||||
in->body.read.offset == offset &&
|
||||
in->body.read.size == isize);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(struct fuse_out_header) + osize;
|
||||
memmove(out->body.bytes, contents, osize);
|
||||
})).RetiresOnSaturation();
|
||||
}
|
||||
|
||||
void FuseTest::expect_release(uint64_t ino, int times, int error)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_RELEASE &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.release.fh == FH);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke(ReturnErrno(error)));
|
||||
}
|
||||
void FuseTest::expect_write(uint64_t ino, uint64_t offset, uint64_t isize,
|
||||
uint64_t osize, uint32_t flags, const void *contents)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
const char *buf = (const char*)in->body.bytes +
|
||||
sizeof(struct fuse_write_in);
|
||||
bool pid_ok;
|
||||
|
||||
if (in->body.write.write_flags & FUSE_WRITE_CACHE)
|
||||
pid_ok = true;
|
||||
else
|
||||
pid_ok = (pid_t)in->header.pid == getpid();
|
||||
|
||||
return (in->header.opcode == FUSE_WRITE &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.write.fh == FH &&
|
||||
in->body.write.offset == offset &&
|
||||
in->body.write.size == isize &&
|
||||
pid_ok &&
|
||||
in->body.write.write_flags == flags &&
|
||||
0 == bcmp(buf, contents, isize));
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
SET_OUT_HEADER_LEN(out, write);
|
||||
out->body.write.size = osize;
|
||||
}));
|
||||
}
|
||||
|
||||
static void usage(char* progname) {
|
||||
fprintf(stderr, "Usage: %s [-v]\n\t-v increase verbosity\n", progname);
|
||||
exit(2);
|
||||
@ -91,8 +233,8 @@ int main(int argc, char **argv) {
|
||||
int ch;
|
||||
FuseEnv *fuse_env = new FuseEnv;
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
::testing::AddGlobalTestEnvironment(fuse_env);
|
||||
InitGoogleTest(&argc, argv);
|
||||
AddGlobalTestEnvironment(fuse_env);
|
||||
|
||||
while ((ch = getopt(argc, argv, "v")) != -1) {
|
||||
switch (ch) {
|
||||
|
@ -28,11 +28,21 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: remove FUSE_WRITE_CACHE definition when upgrading to protocol 7.9.
|
||||
* This bit was actually part of kernel protocol version 7.2, but never
|
||||
* documented until 7.9
|
||||
*/
|
||||
#ifndef FUSE_WRITE_CACHE
|
||||
#define FUSE_WRITE_CACHE 1
|
||||
#endif
|
||||
|
||||
class FuseTest : public ::testing::Test {
|
||||
protected:
|
||||
uint32_t m_maxreadahead;
|
||||
uint32_t m_init_flags;
|
||||
MockFS *m_mock = NULL;
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
|
||||
public:
|
||||
int m_maxbcachebuf;
|
||||
@ -52,4 +62,54 @@ class FuseTest : public ::testing::Test {
|
||||
if (m_mock)
|
||||
delete m_mock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an expectation that FUSE_GETATTR will be called for the given
|
||||
* inode any number of times. It will respond with a few basic
|
||||
* attributes, like the given size and the mode S_IFREG | 0644
|
||||
*/
|
||||
void expect_getattr(uint64_t ino, uint64_t size);
|
||||
|
||||
/*
|
||||
* Create an expectation that FUSE_LOOKUP will be called for the given
|
||||
* path exactly times times. It will respond with inode ino, mode
|
||||
* mode, and cache validity forever.
|
||||
*/
|
||||
void expect_lookup(const char *relpath, uint64_t ino, mode_t mode,
|
||||
int times);
|
||||
|
||||
/*
|
||||
* Create an expectation that FUSE_GETATTR will be called for the given
|
||||
* inode exactly times times. It will return with open_flags flags and
|
||||
* file handle FH.
|
||||
*/
|
||||
void expect_open(uint64_t ino, uint32_t flags, int times);
|
||||
|
||||
/*
|
||||
* Create an expectation that FUSE_OPENDIR will be called exactly once
|
||||
* for inode ino.
|
||||
*/
|
||||
void expect_opendir(uint64_t ino);
|
||||
|
||||
/*
|
||||
* Create an expectation that FUSE_READ will be called exactly once for
|
||||
* the given inode, at offset offset and with size isize. It will
|
||||
* return the first osize bytes from contents
|
||||
*/
|
||||
void expect_read(uint64_t ino, uint64_t offset, uint64_t isize,
|
||||
uint64_t osize, const void *contents);
|
||||
|
||||
/*
|
||||
* Create an expectation that FUSE_RELEASE will be called times times
|
||||
* for the given inode, returning error error
|
||||
*/
|
||||
void expect_release(uint64_t ino, int times, int error);
|
||||
|
||||
/*
|
||||
* Create an expectation that FUSE_WRITE will be called exactly once
|
||||
* for the given inode, at offset offset, with write_flags flags,
|
||||
* size isize and buffer contents. It will return osize
|
||||
*/
|
||||
void expect_write(uint64_t ino, uint64_t offset, uint64_t isize,
|
||||
uint64_t osize, uint32_t flags, const void *contents);
|
||||
};
|
||||
|
@ -43,87 +43,15 @@ extern "C" {
|
||||
#include "mockfs.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
/*
|
||||
* TODO: remove FUSE_WRITE_CACHE definition when upgrading to protocol 7.9.
|
||||
* This bit was actually part of kernel protocol version 7.2, but never
|
||||
* documented until 7.9
|
||||
*/
|
||||
#ifndef FUSE_WRITE_CACHE
|
||||
#define FUSE_WRITE_CACHE 1
|
||||
#endif
|
||||
|
||||
using namespace testing;
|
||||
|
||||
class Write: public FuseTest {
|
||||
|
||||
public:
|
||||
const static uint64_t FH = 0xdeadbeef1a7ebabe;
|
||||
void expect_getattr(uint64_t ino, uint64_t size)
|
||||
{
|
||||
/* Until the attr cache is working, we may send an additional GETATTR */
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_GETATTR &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillRepeatedly(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 = size;
|
||||
out->body.attr.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
void expect_lookup(const char *relpath, uint64_t ino)
|
||||
{
|
||||
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;
|
||||
out->body.entry.nodeid = ino;
|
||||
out->body.entry.attr_valid = UINT64_MAX;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_open(uint64_t ino, uint32_t flags, int times)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_OPEN &&
|
||||
in->header.nodeid == ino);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).Times(times)
|
||||
.WillRepeatedly(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(out->header);
|
||||
SET_OUT_HEADER_LEN(out, open);
|
||||
out->body.open.fh = Write::FH;
|
||||
out->body.open.open_flags = flags;
|
||||
}));
|
||||
}
|
||||
|
||||
void expect_read(uint64_t ino, uint64_t offset, uint64_t size,
|
||||
const void *contents)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
return (in->header.opcode == FUSE_READ &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.read.fh == Write::FH &&
|
||||
in->body.read.offset == offset &&
|
||||
in->body.read.size == size);
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
out->header.len = sizeof(struct fuse_out_header) + size;
|
||||
memmove(out->body.bytes, contents, size);
|
||||
})).RetiresOnSaturation();
|
||||
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1);
|
||||
}
|
||||
|
||||
void expect_release(uint64_t ino, ProcessMockerT r)
|
||||
@ -137,37 +65,6 @@ void expect_release(uint64_t ino, ProcessMockerT r)
|
||||
).WillRepeatedly(Invoke(r));
|
||||
}
|
||||
|
||||
void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, uint64_t osize,
|
||||
uint32_t flags, const void *contents)
|
||||
{
|
||||
EXPECT_CALL(*m_mock, process(
|
||||
ResultOf([=](auto in) {
|
||||
const char *buf = (const char*)in->body.bytes +
|
||||
sizeof(struct fuse_write_in);
|
||||
bool pid_ok;
|
||||
|
||||
if (in->body.write.write_flags & FUSE_WRITE_CACHE)
|
||||
pid_ok = true;
|
||||
else
|
||||
pid_ok = (pid_t)in->header.pid == getpid();
|
||||
|
||||
return (in->header.opcode == FUSE_WRITE &&
|
||||
in->header.nodeid == ino &&
|
||||
in->body.write.fh == Write::FH &&
|
||||
in->body.write.offset == offset &&
|
||||
in->body.write.size == isize &&
|
||||
pid_ok &&
|
||||
in->body.write.write_flags == flags &&
|
||||
0 == bcmp(buf, contents, isize));
|
||||
}, Eq(true)),
|
||||
_)
|
||||
).WillOnce(Invoke([=](auto in, auto out) {
|
||||
out->header.unique = in->header.unique;
|
||||
SET_OUT_HEADER_LEN(out, write);
|
||||
out->body.write.size = osize;
|
||||
}));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class AioWrite: public Write {
|
||||
@ -337,7 +234,7 @@ TEST_F(Write, DISABLED_direct_io_evicts_cache)
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, bufsize);
|
||||
expect_read(ino, 0, bufsize, CONTENTS0);
|
||||
expect_read(ino, 0, bufsize, bufsize, CONTENTS0);
|
||||
expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS1);
|
||||
|
||||
fd = open(FULLPATH, O_RDWR);
|
||||
@ -352,7 +249,7 @@ TEST_F(Write, DISABLED_direct_io_evicts_cache)
|
||||
ASSERT_EQ(bufsize, write(fd, CONTENTS1, bufsize)) << strerror(errno);
|
||||
|
||||
// Read again. Cache should be bypassed
|
||||
expect_read(ino, 0, bufsize, CONTENTS1);
|
||||
expect_read(ino, 0, bufsize, bufsize, CONTENTS1);
|
||||
ASSERT_EQ(0, fcntl(fd, F_SETFL, 0)) << strerror(errno);
|
||||
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
|
||||
ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
|
||||
@ -459,7 +356,7 @@ TEST_F(Write, DISABLED_mmap)
|
||||
expect_lookup(RELPATH, ino);
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, len);
|
||||
expect_read(ino, 0, len, zeros);
|
||||
expect_read(ino, 0, len, len, zeros);
|
||||
/*
|
||||
* Writes from the pager may or may not be associated with the correct
|
||||
* pid, so they must set FUSE_WRITE_CACHE
|
||||
@ -663,7 +560,7 @@ TEST_F(WriteBack, o_direct)
|
||||
expect_open(ino, 0, 1);
|
||||
expect_getattr(ino, 0);
|
||||
expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS);
|
||||
expect_read(ino, 0, bufsize, CONTENTS);
|
||||
expect_read(ino, 0, bufsize, bufsize, CONTENTS);
|
||||
|
||||
fd = open(FULLPATH, O_RDWR | O_DIRECT);
|
||||
EXPECT_LE(0, fd) << strerror(errno);
|
||||
|
Loading…
Reference in New Issue
Block a user