freebsd-nq/tests/sys/fs/fusefs/statfs.cc
Alan Somers 1fa8ebfbbb fusefs: add SVN Keywords to the test files
Reported by:	SVN pre-commit hooks
MFC after:	15 days
MFC-With:	r350665
Sponsored by:	The FreeBSD Foundation
2019-08-13 15:49:40 +00:00

174 lines
5.1 KiB
C++

/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2019 The FreeBSD Foundation
*
* 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.
*
* $FreeBSD$
*/
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);
}
/*
* When the daemon is dead but the filesystem is still mounted, fuse(4) fakes
* the statfs(2) response, which is necessary for unmounting.
*/
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;
}
/*
* Like the enotconn test, but in this case the daemon dies after we send the
* FUSE_STATFS operation but before we get a response.
*/
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);
/* Just block until the daemon dies */
}));
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);
/*
* fuse(4) ignores the filesystem's reported optimal transfer size, and
* chooses a size that works well with the rest of the system instead
*/
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));
}