From f5025cf8fdd0dc505bde47209437578a19d653bb Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Fri, 28 Nov 2014 18:38:24 +0100 Subject: [PATCH] Testcases for utimens() --- src/fspp/fuse/Filesystem.h | 2 +- .../fspp/fuse/rename/FuseRenameErrorTest.cpp | 2 +- .../fuse/utimens/FuseUtimensErrorTest.cpp | 27 ++++++++ .../fuse/utimens/FuseUtimensFilenameTest.cpp | 65 +++++++++++++++++++ .../utimens/FuseUtimensTimeParameterTest.cpp | 34 ++++++++++ .../utimens/testutils/FuseUtimensTest.cpp | 27 ++++++++ .../fuse/utimens/testutils/FuseUtimensTest.h | 23 +++++++ 7 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 src/test/fspp/fuse/utimens/FuseUtimensErrorTest.cpp create mode 100644 src/test/fspp/fuse/utimens/FuseUtimensFilenameTest.cpp create mode 100644 src/test/fspp/fuse/utimens/FuseUtimensTimeParameterTest.cpp create mode 100644 src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.cpp create mode 100644 src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.h diff --git a/src/fspp/fuse/Filesystem.h b/src/fspp/fuse/Filesystem.h index 46264f9f..9849ead3 100644 --- a/src/fspp/fuse/Filesystem.h +++ b/src/fspp/fuse/Filesystem.h @@ -30,9 +30,9 @@ public: virtual void rmdir(const boost::filesystem::path &path) = 0; virtual void unlink(const boost::filesystem::path &path) = 0; virtual void rename(const boost::filesystem::path &from, const boost::filesystem::path &to) = 0; + virtual void utimens(const boost::filesystem::path &path, const timespec times[2]) = 0; //TODO Unit-Tests for all functions below virtual std::unique_ptr> readDir(const boost::filesystem::path &path) = 0; - virtual void utimens(const boost::filesystem::path &path, const timespec times[2]) = 0; virtual void statfs(const boost::filesystem::path &path, struct statvfs *fsstat) = 0; }; diff --git a/src/test/fspp/fuse/rename/FuseRenameErrorTest.cpp b/src/test/fspp/fuse/rename/FuseRenameErrorTest.cpp index 7f251bf2..aacb0a69 100644 --- a/src/test/fspp/fuse/rename/FuseRenameErrorTest.cpp +++ b/src/test/fspp/fuse/rename/FuseRenameErrorTest.cpp @@ -18,7 +18,7 @@ INSTANTIATE_TEST_CASE_P(FuseRenameErrorTest, FuseRenameErrorTest, Values(EACCES, TEST_P(FuseRenameErrorTest, ReturnedErrorIsCorrect) { ReturnIsFileOnLstat(FILENAME1); - ReturnIsFileOnLstat(FILENAME2); + ReturnDoesntExistOnLstat(FILENAME2); EXPECT_CALL(fsimpl, rename(StrEq(FILENAME1), StrEq(FILENAME2))) .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); diff --git a/src/test/fspp/fuse/utimens/FuseUtimensErrorTest.cpp b/src/test/fspp/fuse/utimens/FuseUtimensErrorTest.cpp new file mode 100644 index 00000000..61128119 --- /dev/null +++ b/src/test/fspp/fuse/utimens/FuseUtimensErrorTest.cpp @@ -0,0 +1,27 @@ +#include "testutils/FuseUtimensTest.h" +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "fspp/fuse/FuseErrnoException.h" + +using ::testing::_; +using ::testing::StrEq; +using ::testing::Throw; +using ::testing::WithParamInterface; +using ::testing::Values; + +using namespace fspp::fuse; + +class FuseUtimensErrorTest: public FuseUtimensTest, public WithParamInterface { +}; +INSTANTIATE_TEST_CASE_P(FuseUtimensErrorTest, FuseUtimensErrorTest, Values(EACCES, ENOENT, EPERM, EROFS)); + +TEST_P(FuseUtimensErrorTest, ReturnedErrorIsCorrect) { + ReturnIsFileOnLstat(FILENAME); + EXPECT_CALL(fsimpl, utimens(StrEq(FILENAME), _)) + .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); + + int retval = UtimensAllowError(FILENAME, TIMEVALUES); + EXPECT_EQ(GetParam(), errno); + EXPECT_EQ(-1, retval); +} diff --git a/src/test/fspp/fuse/utimens/FuseUtimensFilenameTest.cpp b/src/test/fspp/fuse/utimens/FuseUtimensFilenameTest.cpp new file mode 100644 index 00000000..cdfabdef --- /dev/null +++ b/src/test/fspp/fuse/utimens/FuseUtimensFilenameTest.cpp @@ -0,0 +1,65 @@ +#include "testutils/FuseUtimensTest.h" +#include "gtest/gtest.h" +#include "gmock/gmock.h" + + +using ::testing::_; +using ::testing::StrEq; +using ::testing::Return; + +class FuseUtimensFilenameTest: public FuseUtimensTest { +}; + +TEST_F(FuseUtimensFilenameTest, UtimensFile) { + ReturnIsFileOnLstat("/myfile"); + EXPECT_CALL(fsimpl, utimens(StrEq("/myfile"), _)) + .Times(1).WillOnce(Return()); + + Utimens("/myfile", TIMEVALUES); +} + +TEST_F(FuseUtimensFilenameTest, UtimensFileNested) { + ReturnIsDirOnLstat("/mydir"); + ReturnIsFileOnLstat("/mydir/myfile"); + EXPECT_CALL(fsimpl, utimens(StrEq("/mydir/myfile"), _)) + .Times(1).WillOnce(Return()); + + Utimens("/mydir/myfile", TIMEVALUES); +} + +TEST_F(FuseUtimensFilenameTest, UtimensFileNested2) { + ReturnIsDirOnLstat("/mydir"); + ReturnIsDirOnLstat("/mydir/mydir2"); + ReturnIsFileOnLstat("/mydir/mydir2/myfile"); + EXPECT_CALL(fsimpl, utimens(StrEq("/mydir/mydir2/myfile"), _)) + .Times(1).WillOnce(Return()); + + Utimens("/mydir/mydir2/myfile", TIMEVALUES); +} + +TEST_F(FuseUtimensFilenameTest, UtimensDir) { + ReturnIsDirOnLstat("/mydir"); + EXPECT_CALL(fsimpl, utimens(StrEq("/mydir"), _)) + .Times(1).WillOnce(Return()); + + Utimens("/mydir", TIMEVALUES); +} + +TEST_F(FuseUtimensFilenameTest, UtimensDirNested) { + ReturnIsDirOnLstat("/mydir"); + ReturnIsDirOnLstat("/mydir/mydir2"); + EXPECT_CALL(fsimpl, utimens(StrEq("/mydir/mydir2"), _)) + .Times(1).WillOnce(Return()); + + Utimens("/mydir/mydir2", TIMEVALUES); +} + +TEST_F(FuseUtimensFilenameTest, UtimensDirNested2) { + ReturnIsDirOnLstat("/mydir"); + ReturnIsDirOnLstat("/mydir/mydir2"); + ReturnIsDirOnLstat("/mydir/mydir2/mydir3"); + EXPECT_CALL(fsimpl, utimens(StrEq("/mydir/mydir2/mydir3"), _)) + .Times(1).WillOnce(Return()); + + Utimens("/mydir/mydir2/mydir3", TIMEVALUES); +} diff --git a/src/test/fspp/fuse/utimens/FuseUtimensTimeParameterTest.cpp b/src/test/fspp/fuse/utimens/FuseUtimensTimeParameterTest.cpp new file mode 100644 index 00000000..8dff0d6d --- /dev/null +++ b/src/test/fspp/fuse/utimens/FuseUtimensTimeParameterTest.cpp @@ -0,0 +1,34 @@ +#include "testutils/FuseUtimensTest.h" +#include "gtest/gtest.h" +#include "gmock/gmock.h" + + +using ::testing::_; +using ::testing::StrEq; +using ::testing::Return; +using ::testing::WithParamInterface; +using ::testing::Values; + +class FuseUtimensTimeParameterTest: public FuseUtimensTest, public WithParamInterface { +}; +const timespec TIMEVAL1[2] = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(0,0)}; +const timespec TIMEVAL2[2] = {FuseUtimensTest::makeTimespec(1000,0), FuseUtimensTest::makeTimespec(0,0)}; +const timespec TIMEVAL3[2] = {FuseUtimensTest::makeTimespec(0,1000), FuseUtimensTest::makeTimespec(0,0)}; +const timespec TIMEVAL4[2] = {FuseUtimensTest::makeTimespec(1000,1000), FuseUtimensTest::makeTimespec(0,0)}; +const timespec TIMEVAL5[2] = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(0,0)}; +const timespec TIMEVAL6[2] = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(1000,0)}; +const timespec TIMEVAL7[2] = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(0,1000)}; +const timespec TIMEVAL8[2] = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(1000,1000)}; +const timespec TIMEVAL9[2] = {FuseUtimensTest::makeTimespec(1417196126,123000), FuseUtimensTest::makeTimespec(1417109713,321000)}; // current timestamp and the day before as of writing this test case +const timespec TIMEVAL10[2] = {FuseUtimensTest::makeTimespec(1024L*1024*1024*1024,999000), FuseUtimensTest::makeTimespec(2L*1024*1024*1024*1024,321000)}; // needs 64bit for timestamp representation +INSTANTIATE_TEST_CASE_P(FuseUtimensTimeParameterTest, FuseUtimensTimeParameterTest, + Values(TIMEVAL1, TIMEVAL2, TIMEVAL3, TIMEVAL4, TIMEVAL5, TIMEVAL6, TIMEVAL7, TIMEVAL8, TIMEVAL9, TIMEVAL10)); + + +TEST_P(FuseUtimensTimeParameterTest, Utimens) { + ReturnIsFileOnLstat(FILENAME); + EXPECT_CALL(fsimpl, utimens(StrEq(FILENAME), TimeSpecEq(GetParam()))) + .Times(1).WillOnce(Return()); + + Utimens(FILENAME, GetParam()); +} diff --git a/src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.cpp b/src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.cpp new file mode 100644 index 00000000..6bf32478 --- /dev/null +++ b/src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.cpp @@ -0,0 +1,27 @@ +#include "FuseUtimensTest.h" + +#include +#include + +void FuseUtimensTest::Utimens(const char *filename, const timespec times[2]) { + int retval = UtimensAllowError(filename, times); + EXPECT_EQ(0, retval); +} + +int FuseUtimensTest::UtimensAllowError(const char *filename, const timespec times[2]) { + auto fs = TestFS(); + + auto realpath = fs->mountDir() / filename; + + struct timeval casted_times[2]; + TIMESPEC_TO_TIMEVAL(&casted_times[0], ×[0]); + TIMESPEC_TO_TIMEVAL(&casted_times[1], ×[1]); + return ::utimes(realpath.c_str(), casted_times); +} + +struct timespec FuseUtimensTest::makeTimespec(time_t tv_sec, long tv_nsec) { + struct timespec result; + result.tv_sec = tv_sec; + result.tv_nsec = tv_nsec; + return result; +} diff --git a/src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.h b/src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.h new file mode 100644 index 00000000..c5a9e960 --- /dev/null +++ b/src/test/fspp/fuse/utimens/testutils/FuseUtimensTest.h @@ -0,0 +1,23 @@ +#pragma once +#ifndef TEST_FSPP_FUSE_UTIMENS_TESTUTILS_FUSEUTIMENSTEST_H_ +#define TEST_FSPP_FUSE_UTIMENS_TESTUTILS_FUSEUTIMENSTEST_H_ + +#include "test/testutils/FuseTest.h" + +class FuseUtimensTest: public FuseTest { +public: + const char *FILENAME = "/myfile"; + struct timespec TIMEVALUES[2]; + + void Utimens(const char *filename, const timespec times[2]); + int UtimensAllowError(const char *filename, const timespec times[2]); + + static struct timespec makeTimespec(time_t tv_sec, long tv_nsec); +}; + +MATCHER_P(TimeSpecEq, expected, "") { + return expected[0].tv_sec == arg[0].tv_sec && expected[0].tv_nsec == arg[0].tv_nsec && + expected[1].tv_sec == arg[1].tv_sec && expected[1].tv_nsec == arg[1].tv_nsec; +} + +#endif