From 61e5b4b7de31b844940d9ffb5635f8fee911f4ea Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Tue, 25 Nov 2014 14:29:44 +0100 Subject: [PATCH] Written fstat tests --- .../fspp/fuse/fstat/FuseFstatErrorTest.cpp | 40 +++++++++++++++++++ .../fuse/fstat/FuseFstatParameterTest.cpp | 35 ++++++++++++++++ src/test/fspp/fuse/fstat/README | 6 +++ .../fspp/fuse/fstat/testutils/FuseFstatTest.h | 21 ++++++++++ src/test/testutils/FuseTest.h | 15 +++++++ 5 files changed, 117 insertions(+) create mode 100644 src/test/fspp/fuse/fstat/FuseFstatErrorTest.cpp create mode 100644 src/test/fspp/fuse/fstat/FuseFstatParameterTest.cpp create mode 100644 src/test/fspp/fuse/fstat/README create mode 100644 src/test/fspp/fuse/fstat/testutils/FuseFstatTest.h diff --git a/src/test/fspp/fuse/fstat/FuseFstatErrorTest.cpp b/src/test/fspp/fuse/fstat/FuseFstatErrorTest.cpp new file mode 100644 index 00000000..cc947f1e --- /dev/null +++ b/src/test/fspp/fuse/fstat/FuseFstatErrorTest.cpp @@ -0,0 +1,40 @@ +#include "testutils/FuseFstatTest.h" + +#include "fspp/impl/FuseErrnoException.h" + +using ::testing::_; +using ::testing::StrEq; +using ::testing::WithParamInterface; +using ::testing::Values; +using ::testing::Eq; +using ::testing::Return; +using ::testing::Throw; + +using namespace fspp; + +// Cite from FUSE documentation on the fgetattr function: +// "Currently this is only called after the create() method if that is implemented (see above). +// Later it may be called for invocations of fstat() too." +// So we need to issue a create to get our fstat called. + +class FuseFstatErrorTest: public FuseFstatTest, public WithParamInterface { +public: + int CreateFileAllowErrors(const TempTestFS *fs, const std::string &filename) { + auto real_path = fs->mountDir() / filename; + return ::open(real_path.c_str(), O_RDWR | O_CREAT); + } +}; +INSTANTIATE_TEST_CASE_P(FuseFstatErrorTest, FuseFstatErrorTest, Values(EACCES, EBADF, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EOVERFLOW)); + +TEST_P(FuseFstatErrorTest, Error) { + ReturnDoesntExistOnLstat(FILENAME); + EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _)).Times(1).WillOnce(Return(0)); + + EXPECT_CALL(fsimpl, fstat(Eq(0), _)).Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); + + auto fs = TestFS(); + + int fd = CreateFileAllowErrors(fs.get(), FILENAME); + EXPECT_EQ(-1, fd); + EXPECT_EQ(GetParam(), errno); +} diff --git a/src/test/fspp/fuse/fstat/FuseFstatParameterTest.cpp b/src/test/fspp/fuse/fstat/FuseFstatParameterTest.cpp new file mode 100644 index 00000000..235452cf --- /dev/null +++ b/src/test/fspp/fuse/fstat/FuseFstatParameterTest.cpp @@ -0,0 +1,35 @@ +#include "testutils/FuseFstatTest.h" + +#include "fspp/impl/FuseErrnoException.h" + +using ::testing::_; +using ::testing::StrEq; +using ::testing::WithParamInterface; +using ::testing::Values; +using ::testing::Eq; +using ::testing::Return; +using ::testing::Throw; + +using namespace fspp; + +// Cite from FUSE documentation on the fgetattr function: +// "Currently this is only called after the create() method if that is implemented (see above). +// Later it may be called for invocations of fstat() too." +// So we need to issue a create to get our fstat called. + +class FuseFstatParameterTest: public FuseFstatTest, public WithParamInterface { +public: + +}; +INSTANTIATE_TEST_CASE_P(FuseFstatParameterTest, FuseFstatParameterTest, Values(0,1,10,1000,1024*1024*1024)); + + +TEST_P(FuseFstatParameterTest, FileDescriptorIsCorrect) { + ReturnDoesntExistOnLstat(FILENAME); + EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _)).Times(1).WillOnce(Return(GetParam())); + + EXPECT_CALL(fsimpl, fstat(Eq(GetParam()), _)).Times(1).WillOnce(ReturnIsFileFstat); + + auto fs = TestFS(); + CreateFile(fs.get(), FILENAME); +} diff --git a/src/test/fspp/fuse/fstat/README b/src/test/fspp/fuse/fstat/README new file mode 100644 index 00000000..79d496a2 --- /dev/null +++ b/src/test/fspp/fuse/fstat/README @@ -0,0 +1,6 @@ +Cite from FUSE documentation on the fgetattr function: + Currently this is only called after the create() method if that is implemented (see above). + Later it may be called for invocations of fstat() too. +So we need to issue a create to get our fstat called. +Since fstat is currently only called after create, we can't call it directly. +So we can't test the returned values. \ No newline at end of file diff --git a/src/test/fspp/fuse/fstat/testutils/FuseFstatTest.h b/src/test/fspp/fuse/fstat/testutils/FuseFstatTest.h new file mode 100644 index 00000000..60ce4dc2 --- /dev/null +++ b/src/test/fspp/fuse/fstat/testutils/FuseFstatTest.h @@ -0,0 +1,21 @@ +#pragma once +#ifndef TEST_FSPP_FUSE_FSTAT_TESTUTILS_FUSEFSTATTEST_H_ +#define TEST_FSPP_FUSE_FSTAT_TESTUTILS_FUSEFSTATTEST_H_ + +#include "test/testutils/FuseTest.h" + +class FuseFstatTest: public FuseTest { +public: + int CreateFile(const TempTestFS *fs, const std::string &filename) { + int fd = CreateFileAllowErrors(fs, filename); + EXPECT_GE(fd, 0) << "Opening file failed"; + return fd; + } + int CreateFileAllowErrors(const TempTestFS *fs, const std::string &filename) { + auto real_path = fs->mountDir() / filename; + return ::open(real_path.c_str(), O_RDWR | O_CREAT); + } +}; + + +#endif diff --git a/src/test/testutils/FuseTest.h b/src/test/testutils/FuseTest.h index 537407ba..44becba5 100644 --- a/src/test/testutils/FuseTest.h +++ b/src/test/testutils/FuseTest.h @@ -67,6 +67,8 @@ public: class FuseTest: public ::testing::Test { public: + const char* FILENAME = "/myfile"; + FuseTest(): fsimpl() { auto defaultAction = ::testing::Throw(fspp::FuseErrnoException(EIO)); ON_CALL(fsimpl, openFile(::testing::_,::testing::_)).WillByDefault(defaultAction); @@ -119,18 +121,27 @@ public: MockFilesystem fsimpl; + //TODO Combine ReturnIsFile and ReturnIsFileFstat. This should be possible in gmock by either (a) using ::testing::Undefined as parameter type or (b) using action macros ::testing::Action ReturnIsFile = ::testing::Invoke([](const char*, struct ::stat* result) { result->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; result->st_nlink = 1; }); + ::testing::Action ReturnIsFileFstat = + ::testing::Invoke([](int, struct ::stat* result) { + result->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; + result->st_nlink = 1; + }); + ::testing::Action ReturnIsDir = ::testing::Invoke([](const char*, struct ::stat* result) { result->st_mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH; result->st_nlink = 1; }); + ::testing::Action ReturnDoesntExist = ::testing::Throw(fspp::FuseErrnoException(ENOENT)); + void ReturnIsFileOnLstat(const bf::path &path) { EXPECT_CALL(fsimpl, lstat(::testing::StrEq(path.c_str()), ::testing::_)).WillRepeatedly(ReturnIsFile); } @@ -138,6 +149,10 @@ public: void ReturnIsDirOnLstat(const bf::path &path) { EXPECT_CALL(fsimpl, lstat(::testing::StrEq(path.c_str()), ::testing::_)).WillRepeatedly(ReturnIsDir); } + + void ReturnDoesntExistOnLstat(const bf::path &path) { + EXPECT_CALL(fsimpl, lstat(::testing::StrEq(path.c_str()), ::testing::_)).WillRepeatedly(ReturnDoesntExist); + } }; #endif