- Use cpputils::DataBlockFixture and cpputils::Data.

- Fix test cases
This commit is contained in:
Sebastian Messmer 2015-04-25 03:26:59 +02:00
parent c543cb398d
commit 9de2d9d04a
22 changed files with 65 additions and 176 deletions

View File

@ -3,7 +3,6 @@
[requirements]
google/gmock: 2
google/gtest: 11
messmer/blockstore: 1
messmer/cmake: 3
messmer/cpp-utils: 2
messmer/tempfile: 4

View File

@ -6,10 +6,6 @@
#include "testutils/FileTest.h"
//TODO I don't really want a dependency fspp -> blockstore. I probably should take the blockstore::Data class
// (which is the only reason for the dependency here) and put it into a different package (cpp-utils?)
#include <messmer/blockstore/utils/Data.h>
template<class ConcreteFileSystemTestFixture>
class FsppFileTest: public FileTest<ConcreteFileSystemTestFixture> {
public:

View File

@ -39,7 +39,7 @@ public:
}
void EXPECT_NUMBYTES_READABLE(uint64_t expectedSize, const fspp::OpenFile &file) {
blockstore::Data data(expectedSize);
cpputils::Data data(expectedSize);
//Try to read one byte more than the expected size
ssize_t readBytes = file.read(data.data(), expectedSize+1, 0);
//and check that it only read the expected size (but also not less)

View File

@ -14,13 +14,16 @@ class Filesystem {
public:
virtual ~Filesystem() {}
//TODO Test uid/gid parameters of createAndOpenFile
virtual int createAndOpenFile(const boost::filesystem::path &path, mode_t mode, uid_t uid, gid_t gid) = 0;
virtual int openFile(const boost::filesystem::path &path, int flags) = 0;
virtual void flush(int descriptor) = 0;
virtual void closeFile(int descriptor) = 0;
virtual void lstat(const boost::filesystem::path &path, struct ::stat *stbuf) = 0;
virtual void fstat(int descriptor, struct ::stat *stbuf) = 0;
//TODO Test chmod
virtual void chmod(const boost::filesystem::path &path, mode_t mode) = 0;
//TODO Test chown
virtual void chown(const boost::filesystem::path &path, uid_t uid, gid_t gid) = 0;
virtual void truncate(const boost::filesystem::path &path, off_t size) = 0;
virtual void ftruncate(int descriptor, off_t size) = 0;
@ -29,6 +32,7 @@ public:
virtual void fsync(int descriptor) = 0;
virtual void fdatasync(int descriptor) = 0;
virtual void access(const boost::filesystem::path &path, int mask) = 0;
//TODO Test uid/gid parameters of mkdir
virtual void mkdir(const boost::filesystem::path &path, mode_t mode, uid_t uid, gid_t gid) = 0;
virtual void rmdir(const boost::filesystem::path &path) = 0;
virtual void unlink(const boost::filesystem::path &path) = 0;
@ -37,7 +41,9 @@ public:
virtual void statfs(const boost::filesystem::path &path, struct statvfs *fsstat) = 0;
//TODO We shouldn't use Dir::Entry here, that's in another layer
virtual std::unique_ptr<std::vector<Dir::Entry>> readDir(const boost::filesystem::path &path) = 0;
//TODO Test createSymlink
virtual void createSymlink(const boost::filesystem::path &to, const boost::filesystem::path &from, uid_t uid, gid_t gid) = 0;
//TODO Test readSymlink
virtual void readSymlink(const boost::filesystem::path &path, char *buf, size_t size) = 0;
};

View File

@ -17,7 +17,7 @@ INSTANTIATE_TEST_CASE_P(FuseCreateAndOpenErrorTest, FuseCreateAndOpenErrorTest,
TEST_F(FuseCreateAndOpenErrorTest, ReturnNoError) {
ReturnDoesntExistOnLstat(FILENAME);
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _)).Times(1).WillOnce(Return(1));
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _, _, _)).Times(1).WillOnce(Return(1));
//For the syscall to succeed, we also need to give an fstat implementation.
ReturnIsFileOnFstat(1);
@ -27,7 +27,7 @@ TEST_F(FuseCreateAndOpenErrorTest, ReturnNoError) {
TEST_P(FuseCreateAndOpenErrorTest, ReturnError) {
ReturnDoesntExistOnLstat(FILENAME);
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _)).Times(1).WillOnce(Throw(FuseErrnoException(GetParam())));
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _, _, _)).Times(1).WillOnce(Throw(FuseErrnoException(GetParam())));
int error = CreateAndOpenFileReturnError(FILENAME, O_RDONLY);
EXPECT_EQ(GetParam(), error);

View File

@ -31,7 +31,7 @@ INSTANTIATE_TEST_CASE_P(FuseCreateAndOpenFileDescriptorTest, FuseCreateAndOpenFi
TEST_P(FuseCreateAndOpenFileDescriptorTest, TestReturnedFileDescriptor) {
ReturnDoesntExistOnLstat(FILENAME);
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _))
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), _, _, _))
.Times(1).WillOnce(Return(GetParam()));
EXPECT_CALL(fsimpl, read(GetParam(), _, _, _)).Times(1).WillOnce(Return(0));
//For the syscall to succeed, we also need to give an fstat implementation.

View File

@ -10,7 +10,7 @@ public:
TEST_F(FuseCreateAndOpenFilenameTest, CreateAndOpenFile) {
ReturnDoesntExistOnLstat("/myfile");
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq("/myfile"), _))
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq("/myfile"), _, _, _))
.Times(1).WillOnce(Return(0));
//For the syscall to succeed, we also need to give an fstat implementation.
ReturnIsFileOnFstat(0);
@ -21,7 +21,7 @@ TEST_F(FuseCreateAndOpenFilenameTest, CreateAndOpenFile) {
TEST_F(FuseCreateAndOpenFilenameTest, CreateAndOpenFileNested) {
ReturnIsDirOnLstat("/mydir");
ReturnDoesntExistOnLstat("/mydir/myfile");
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq("/mydir/myfile"), _))
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq("/mydir/myfile"), _, _, _))
.Times(1).WillOnce(Return(0));
//For the syscall to succeed, we also need to give an fstat implementation.
ReturnIsFileOnFstat(0);
@ -33,7 +33,7 @@ TEST_F(FuseCreateAndOpenFilenameTest, CreateAndOpenFileNested2) {
ReturnIsDirOnLstat("/mydir");
ReturnIsDirOnLstat("/mydir/mydir2");
ReturnDoesntExistOnLstat("/mydir/mydir2/myfile");
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq("/mydir/mydir2/myfile"), _))
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq("/mydir/mydir2/myfile"), _, _, _))
.Times(1).WillOnce(Return(0));
//For the syscall to succeed, we also need to give an fstat implementation.
ReturnIsFileOnFstat(0);

View File

@ -13,7 +13,7 @@ INSTANTIATE_TEST_CASE_P(FuseCreateAndOpenFlagsTest, FuseCreateAndOpenFlagsTest,
//TODO Disabled because it doesn't seem to work. Fuse doesn't seem to pass flags to create(). Why?
TEST_P(FuseCreateAndOpenFlagsTest, DISABLED_testFlags) {
ReturnDoesntExistOnLstat(FILENAME);
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), OpenFlagsEq(GetParam())))
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(FILENAME), OpenFlagsEq(GetParam()), _, _))
.Times(1).WillOnce(Return(0));
//For the syscall to succeed, we also need to give an fstat implementation.
ReturnIsFileOnFstat(0);

View File

@ -30,5 +30,5 @@ int FuseFstatTest::CreateFileAllowErrors(const TempTestFS *fs, const std::string
}
void FuseFstatTest::OnCreateAndOpenReturnFileDescriptor(const char *filename, int descriptor) {
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(filename), _)).Times(1).WillOnce(Return(descriptor));
EXPECT_CALL(fsimpl, createAndOpenFile(StrEq(filename), _, _, _)).Times(1).WillOnce(Return(descriptor));
}

View File

@ -11,10 +11,10 @@ class FuseMkdirDirnameTest: public FuseMkdirTest {
TEST_F(FuseMkdirDirnameTest, Mkdir) {
ReturnDoesntExistOnLstat("/mydir");
EXPECT_CALL(fsimpl, mkdir(StrEq("/mydir"), _))
// After mkdir was called, lstat should return that it is a dir.
// This is needed to make the ::mkdir() syscall pass.
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
EXPECT_CALL(fsimpl, mkdir(StrEq("/mydir"), _, _, _))
// After mkdir was called, lstat should return that it is a dir.
// This is needed to make the ::mkdir() syscall pass.
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
Mkdir("/mydir", 0);
}
@ -22,10 +22,10 @@ TEST_F(FuseMkdirDirnameTest, Mkdir) {
TEST_F(FuseMkdirDirnameTest, MkdirNested) {
ReturnIsDirOnLstat("/mydir");
ReturnDoesntExistOnLstat("/mydir/mysubdir");
EXPECT_CALL(fsimpl, mkdir(StrEq("/mydir/mysubdir"), _))
// After mkdir was called, lstat should return that it is a dir.
// This is needed to make the ::mkdir() syscall pass.
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
EXPECT_CALL(fsimpl, mkdir(StrEq("/mydir/mysubdir"), _, _, _))
// After mkdir was called, lstat should return that it is a dir.
// This is needed to make the ::mkdir() syscall pass.
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
Mkdir("/mydir/mysubdir", 0);
}
@ -34,10 +34,10 @@ TEST_F(FuseMkdirDirnameTest, MkdirNested2) {
ReturnIsDirOnLstat("/mydir");
ReturnIsDirOnLstat("/mydir/mydir2");
ReturnDoesntExistOnLstat("/mydir/mydir2/mydir3");
EXPECT_CALL(fsimpl, mkdir(StrEq("/mydir/mydir2/mydir3"), _))
// After mkdir was called, lstat should return that it is a dir.
// This is needed to make the ::mkdir() syscall pass.
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
EXPECT_CALL(fsimpl, mkdir(StrEq("/mydir/mydir2/mydir3"), _, _, _))
// After mkdir was called, lstat should return that it is a dir.
// This is needed to make the ::mkdir() syscall pass.
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
Mkdir("/mydir/mydir2/mydir3", 0);
}

View File

@ -16,7 +16,7 @@ INSTANTIATE_TEST_CASE_P(FuseMkdirErrorTest, FuseMkdirErrorTest, Values(EACCES, E
TEST_F(FuseMkdirErrorTest, NoError) {
ReturnDoesntExistOnLstat(DIRNAME);
EXPECT_CALL(fsimpl, mkdir(StrEq(DIRNAME), _))
EXPECT_CALL(fsimpl, mkdir(StrEq(DIRNAME), _, _, _))
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
int error = MkdirReturnError(DIRNAME, 0);
@ -25,7 +25,7 @@ TEST_F(FuseMkdirErrorTest, NoError) {
TEST_P(FuseMkdirErrorTest, ReturnedErrorIsCorrect) {
ReturnDoesntExistOnLstat(DIRNAME);
EXPECT_CALL(fsimpl, mkdir(StrEq(DIRNAME), _))
EXPECT_CALL(fsimpl, mkdir(StrEq(DIRNAME), _, _, _))
.Times(1).WillOnce(Throw(FuseErrnoException(GetParam())));
int error = MkdirReturnError(DIRNAME, 0);

View File

@ -13,7 +13,7 @@ INSTANTIATE_TEST_CASE_P(FuseMkdirModeTest, FuseMkdirModeTest, Values(0, S_IRUSR,
TEST_P(FuseMkdirModeTest, Mkdir) {
ReturnDoesntExistOnLstat(DIRNAME);
EXPECT_CALL(fsimpl, mkdir(StrEq(DIRNAME), GetParam()))
EXPECT_CALL(fsimpl, mkdir(StrEq(DIRNAME), GetParam(), _, _))
.Times(1).WillOnce(FromNowOnReturnIsDirOnLstat());
Mkdir(DIRNAME, GetParam());

View File

@ -20,8 +20,8 @@ int FuseMkdirTest::MkdirReturnError(const char *dirname, mode_t mode) {
}
}
Action<void(const char*, mode_t)> FuseMkdirTest::FromNowOnReturnIsDirOnLstat() {
return Invoke([this](const char *dirname, mode_t) {
Action<void(const char*, mode_t, uid_t, gid_t)> FuseMkdirTest::FromNowOnReturnIsDirOnLstat() {
return Invoke([this](const char *dirname, mode_t, uid_t, gid_t) {
ReturnIsDirOnLstat(dirname);
});
}

View File

@ -11,7 +11,7 @@ public:
void Mkdir(const char *dirname, mode_t mode);
int MkdirReturnError(const char *dirname, mode_t mode);
::testing::Action<void(const char*, mode_t)> FromNowOnReturnIsDirOnLstat();
::testing::Action<void(const char*, mode_t, uid_t, gid_t)> FromNowOnReturnIsDirOnLstat();
};
#endif

View File

@ -1,4 +1,4 @@
#include "../../testutils/DataBlockFixture.h"
#include <messmer/cpp-utils/data/DataBlockFixture.h>
#include "testutils/FuseReadTest.h"
#include "../../../fuse/FuseErrnoException.h"
@ -21,6 +21,7 @@ using std::get;
using std::min;
using std::unique_ptr;
using std::make_unique;
using cpputils::DataBlockFixture;
using namespace fspp::fuse;

View File

@ -1,4 +1,4 @@
#include "../../testutils/DataBlockFixture.h"
#include <messmer/cpp-utils/data/DataBlockFixture.h>
#include "testutils/FuseWriteTest.h"
#include "../../../fuse/FuseErrnoException.h"
@ -21,6 +21,8 @@ using std::get;
using std::min;
using std::unique_ptr;
using std::make_unique;
using cpputils::DataBlockFixture;
using cpputils::DataBlockFixtureWriteable;
using namespace fspp::fuse;

View File

@ -1,4 +1,4 @@
#include "../../testutils/DataBlockFixture.h"
#include <messmer/cpp-utils/data/DataBlockFixture.h>
#include "testutils/FuseWriteTest.h"
#include "../../../fuse/FuseErrnoException.h"
@ -11,6 +11,8 @@ using ::testing::Invoke;
using ::testing::Action;
using std::min;
using cpputils::DataBlockFixture;
using cpputils::DataBlockFixtureWriteable;
using namespace fspp::fuse;

View File

@ -20,7 +20,7 @@ public:
MOCK_CONST_METHOD1(stat, void(struct ::stat*));
MOCK_CONST_METHOD1(truncate, void(off_t));
MOCK_METHOD3(read, ssize_t(void*, size_t, off_t));
MOCK_CONST_METHOD3(read, ssize_t(void*, size_t, off_t));
MOCK_METHOD3(write, void(const void*, size_t, off_t));
MOCK_METHOD0(flush, void());
MOCK_METHOD0(fsync, void());

View File

@ -1,87 +0,0 @@
#include "DataBlockFixture.h"
#include <algorithm>
#include <cstring>
using std::min;
DataBlockFixture::DataBlockFixture(size_t size, long long int IV): _fileData(new char[size]), _size(size) {
fillFileWithRandomData(IV);
}
DataBlockFixture::~DataBlockFixture() {
delete[] _fileData;
}
void DataBlockFixture::fillFileWithRandomData(long long int IV) {
long long int val = IV;
for(size_t i=0; i<_size/sizeof(long long int); ++i) {
//MMIX linear congruential generator
val *= 6364136223846793005L;
val += 1442695040888963407;
reinterpret_cast<long long int*>(_fileData)[i] = val;
}
uint64_t alreadyWritten = (_size/sizeof(long long int))*sizeof(long long int);
val *= 6364136223846793005L;
val += 1442695040888963407;
char *remainingBytes = reinterpret_cast<char*>(&val);
//Fill remaining bytes
for(size_t i=0; i<_size-alreadyWritten; ++i) {
reinterpret_cast<char*>(_fileData)[alreadyWritten + i] = remainingBytes[i];
}
}
const char *DataBlockFixture::data() const {
return _fileData;
}
int DataBlockFixture::read(void *buf, size_t count, off_t offset) {
size_t realCount = min(count, _size - offset);
memcpy(buf, _fileData+offset, realCount);
return realCount;
}
size_t DataBlockFixture::size() const {
return _size;
}
bool DataBlockFixture::fileContentEqual(const char *content, size_t count, off_t offset) {
return 0 == memcmp(content, _fileData + offset, count);
}
DataBlockFixtureWriteable::DataBlockFixtureWriteable(size_t size, long long int IV)
:DataBlockFixture(size, IV), _originalSize(size) {
_originalFileData = new char[size];
memcpy(_originalFileData, _fileData, size);
}
DataBlockFixtureWriteable::~DataBlockFixtureWriteable() {
delete[] _originalFileData;
}
void DataBlockFixtureWriteable::write(const void *buf, size_t count, off_t offset) {
extendFileSizeIfNecessary(count + offset);
memcpy(_fileData+offset, buf, count);
}
void DataBlockFixtureWriteable::extendFileSizeIfNecessary(size_t size) {
if (size > _size) {
extendFileSize(size);
}
}
void DataBlockFixtureWriteable::extendFileSize(size_t size) {
char *newfile = new char[size];
memcpy(newfile, _fileData, _size);
delete[] _fileData;
_fileData = newfile;
_size = size;
}
bool DataBlockFixtureWriteable::sizeUnchanged() {
return _size == _originalSize;
}
bool DataBlockFixtureWriteable::regionUnchanged(off_t offset, size_t count) {
return 0 == memcmp(_fileData+offset, _originalFileData+offset, count);
}

View File

@ -1,47 +0,0 @@
#pragma once
#ifndef TEST_TESTUTILS_DATABLOCKFIXTURE_H_
#define TEST_TESTUTILS_DATABLOCKFIXTURE_H_
#include <cstdio>
class DataBlockFixture {
public:
DataBlockFixture(size_t size, long long int IV = 1);
virtual ~DataBlockFixture();
int read(void *buf, size_t count, off_t offset);
// Return true, iff the given data is equal to the data of the file at the given offset.
bool fileContentEqual(const char *content, size_t count, off_t offset);
const char *data() const;
size_t size() const;
protected:
char *_fileData;
size_t _size;
private:
void fillFileWithRandomData(long long int IV);
};
class DataBlockFixtureWriteable: public DataBlockFixture {
public:
DataBlockFixtureWriteable(size_t size, long long int IV = 1);
virtual ~DataBlockFixtureWriteable();
void write(const void *buf, size_t count, off_t offset);
bool sizeUnchanged();
bool regionUnchanged(off_t offset, size_t count);
private:
void extendFileSizeIfNecessary(size_t size);
void extendFileSize(size_t size);
char *_originalFileData;
size_t _originalSize;
};
#endif

View File

@ -30,14 +30,18 @@ FuseTest::FuseTest(): fsimpl() {
ON_CALL(fsimpl, fsync(_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, fdatasync(_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, access(_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, createAndOpenFile(_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, mkdir(_, _)).WillByDefault(defaultAction);
ON_CALL(fsimpl, createAndOpenFile(_,_,_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, mkdir(_,_,_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, rmdir(_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, unlink(_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, rename(_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, readDir(_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, utimens(_, _)).WillByDefault(defaultAction);
ON_CALL(fsimpl, statfs(_, _)).WillByDefault(defaultAction);
ON_CALL(fsimpl, utimens(_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, statfs(_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, chmod(_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, chown(_,_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, createSymlink(_,_,_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, readSymlink(_,_,_)).WillByDefault(defaultAction);
}
unique_ptr<FuseTest::TempTestFS> FuseTest::TestFS() {

View File

@ -27,6 +27,12 @@
} \
MOCK_METHOD2(NAME, RETURNTYPE(const char*, PARAM1)); \
#define MOCK_PATH_METHOD3(NAME, RETURNTYPE, PARAM1, PARAM2) \
RETURNTYPE NAME(const boost::filesystem::path &path, PARAM1 p1, PARAM2 p2) override { \
return NAME(path.c_str(), p1, p2); \
} \
MOCK_METHOD3(NAME, RETURNTYPE(const char*, PARAM1, PARAM2)); \
#define MOCK_PATH_METHOD4(NAME, RETURNTYPE, PARAM1, PARAM2, PARAM3) \
RETURNTYPE NAME(const boost::filesystem::path &path, PARAM1 p1, PARAM2 p2, PARAM3 p3) override { \
return NAME(path.c_str(), p1, p2, p3); \
@ -50,8 +56,8 @@ public:
MOCK_METHOD1(fsync, void(int));
MOCK_METHOD1(fdatasync, void(int));
MOCK_PATH_METHOD2(access, void, int);
MOCK_PATH_METHOD2(createAndOpenFile, int, mode_t);
MOCK_PATH_METHOD2(mkdir, void, mode_t);
MOCK_PATH_METHOD4(createAndOpenFile, int, mode_t, uid_t, gid_t);
MOCK_PATH_METHOD4(mkdir, void, mode_t, uid_t, gid_t);
MOCK_PATH_METHOD1(rmdir, void);
MOCK_PATH_METHOD1(unlink, void);
void rename(const boost::filesystem::path &from, const boost::filesystem::path &to) override {
@ -67,6 +73,13 @@ public:
}
MOCK_METHOD2(utimens, void(const char*,const timespec[2]));
MOCK_PATH_METHOD2(statfs, void, struct statvfs*);
void createSymlink(const boost::filesystem::path &to, const boost::filesystem::path &from, uid_t uid, gid_t gid) override {
return createSymlink(to.c_str(), from.c_str(), uid, gid);
}
MOCK_PATH_METHOD2(chmod, void, mode_t);
MOCK_PATH_METHOD3(chown, void, uid_t, gid_t);
MOCK_METHOD4(createSymlink, void(const char*, const char*, uid_t, gid_t));
MOCK_PATH_METHOD3(readSymlink, void, char*, size_t);
};
class FuseTest: public ::testing::Test {