extern "C" {
#include <sys/param.h>
#include <sys/mount.h>
#include <semaphore.h>
}
#include "mockfs.hh"
#include "utils.hh"
using namespace testing;
class Statfs: public FuseTest {};
TEST_F(Statfs, eio)
{
struct statfs statbuf;
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in.header.opcode == FUSE_STATFS);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(EIO)));
ASSERT_NE(0, statfs("mountpoint", &statbuf));
ASSERT_EQ(EIO, errno);
}
TEST_F(Statfs, enotconn)
{
struct statfs statbuf;
char mp[PATH_MAX];
m_mock->kill_daemon();
ASSERT_NE(nullptr, getcwd(mp, PATH_MAX)) << strerror(errno);
strlcat(mp, "/mountpoint", PATH_MAX);
ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
EXPECT_EQ(getuid(), statbuf.f_owner);
EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename));
EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname));
EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname));
}
static void* statfs_th(void* arg) {
ssize_t r;
struct statfs *sb = (struct statfs*)arg;
r = statfs("mountpoint", sb);
if (r >= 0)
return 0;
else
return (void*)(intptr_t)errno;
}
TEST_F(Statfs, enotconn_while_blocked)
{
struct statfs statbuf;
void *thr0_value;
pthread_t th0;
char mp[PATH_MAX];
sem_t sem;
ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in.header.opcode == FUSE_STATFS);
}, Eq(true)),
_)
).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
sem_post(&sem);
}));
ASSERT_NE(nullptr, getcwd(mp, PATH_MAX)) << strerror(errno);
strlcat(mp, "/mountpoint", PATH_MAX);
ASSERT_EQ(0, pthread_create(&th0, NULL, statfs_th, (void*)&statbuf))
<< strerror(errno);
ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
m_mock->kill_daemon();
pthread_join(th0, &thr0_value);
ASSERT_EQ(0, (intptr_t)thr0_value);
EXPECT_EQ(getuid(), statbuf.f_owner);
EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename));
EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname));
EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname));
}
TEST_F(Statfs, ok)
{
struct statfs statbuf;
char mp[PATH_MAX];
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in.header.opcode == FUSE_STATFS);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
SET_OUT_HEADER_LEN(out, statfs);
out.body.statfs.st.blocks = 1000;
out.body.statfs.st.bfree = 100;
out.body.statfs.st.bavail = 200;
out.body.statfs.st.files = 5;
out.body.statfs.st.ffree = 6;
out.body.statfs.st.namelen = 128;
out.body.statfs.st.frsize = 1024;
})));
ASSERT_NE(nullptr, getcwd(mp, PATH_MAX)) << strerror(errno);
strlcat(mp, "/mountpoint", PATH_MAX);
ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
EXPECT_EQ(1024ul, statbuf.f_bsize);
EXPECT_EQ(1000ul, statbuf.f_blocks);
EXPECT_EQ(100ul, statbuf.f_bfree);
EXPECT_EQ(200l, statbuf.f_bavail);
EXPECT_EQ(5ul, statbuf.f_files);
EXPECT_EQ(6l, statbuf.f_ffree);
EXPECT_EQ(128u, statbuf.f_namemax);
EXPECT_EQ(getuid(), statbuf.f_owner);
EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename));
EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname));
EXPECT_EQ(0, strcmp(mp, statbuf.f_mntonname));
}