Merge from develop

This commit is contained in:
Sebastian Messmer 2017-01-21 19:18:52 +00:00
commit 42765c6be6
376 changed files with 1905 additions and 759 deletions

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ umltest.status
src/gitversion/*.pyc
src/gitversion/__pycache__
cmake-build-debug
cmake-build-release

View File

@ -7,10 +7,6 @@ compiler:
os:
- linux
- osx
matrix:
allow_failures:
- os: linux
compiler: clang
addons:
apt:
sources:

View File

@ -7,6 +7,12 @@ New Features:
Improvements:
* Performance improvements
Version 0.9.7 (unreleased)
--------------
Compatibility:
* Runs on FreeBSD
* Works with Clang++ 3.8 (Debian experimental or newer Ubuntu systems)
Version 0.9.6
---------------
Fixed bugs:

View File

@ -54,8 +54,7 @@ Requirements
- chrono
- program_options
- thread
- Crypto++ version == 5.6.3 (including development headers)
(not compatible to Crypto++ 5.6.4, but will be compatible with Crypto++ 5.6.5+)
- Crypto++ version >= 5.6.3 (including development headers)
- SSL development libraries (including development headers, e.g. libssl-dev)
- libFUSE version >= 2.8.6 (including development headers), on Mac OS X instead install osxfuse from https://osxfuse.github.io/
- Python >= 2.7
@ -90,9 +89,9 @@ Build & Install
$ sudo make install
You can pass the following variables to the *cmake* command (using *-Dvariablename=value*):
- -D**CMAKE_BUILD_TYPE**=[Release|Debug]: Whether to run code optimization or add debug symbols. Default: Release
- -D**BUILD_TESTING**=[on|off]: Whether to build the test cases (can take a long time). Default: off
- -D**CRYFS_UPDATE_CHECKS**=off: Build a CryFS that doesn't check online for updates and security vulnerabilities.
- **-DCMAKE_BUILD_TYPE**=[Release|Debug]: Whether to run code optimization or add debug symbols. Default: Release
- **-DBUILD_TESTING**=[on|off]: Whether to build the test cases (can take a long time). Default: off
- **-DCRYFS_UPDATE_CHECKS**=off: Build a CryFS that doesn't check online for updates and security vulnerabilities.
Troubleshooting
---------------

7
archive.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
TAG=$1
GPGHOMEDIR=$2
git archive --format=tgz "$1" > cryfs-$1.tar.gz
gpg --homedir "$GPGHOMEDIR" --armor --detach-sign cryfs-$1.tar.gz

View File

@ -39,7 +39,8 @@ if(BUILDTYPE MATCHES RELEASE AND NOT BUILD_TESTING)
set(CPACK_PACKAGE_EXECUTABLES "cryfs" "CryFS")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "fuse")
# Needs gnupg2 for postinst script
set(CPACK_DEBIAN_PACKAGE_DEPENDS "fuse, gnupg2")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.cryfs.org")
set(CPACK_RPM_PACKAGE_LICENSE "LGPLv3")

View File

@ -37,7 +37,7 @@ sources_list_dir () {
root=$(get_apt_config "Dir")
etc=$(get_apt_config "Dir::Etc")
sourceparts=$(get_apt_config "Dir::Etc::sourceparts")
echo $root$etc$sourceparts
echo "$root/$etc/$sourceparts"
}
add_repository () {

View File

@ -16,7 +16,6 @@
#include <cpp-utils/data/DataUtils.h>
#include <mutex>
#include <cpp-utils/logging/logging.h>
#include "../../../../vendor/googletest/gtest-1.7.0/googletest/include/gtest/gtest_prod.h"
#include "IntegrityViolationError.h"
#include "VersionCountingBlockStore.h"

View File

@ -12,6 +12,7 @@ set(SOURCES
tempfile/TempDir.cpp
network/HttpClient.cpp
network/CurlHttpClient.cpp
network/CurlInitializerRAII.cpp
network/FakeHttpClient.cpp
io/Console.cpp
io/DontEchoStdinToStdoutRAII.cpp

View File

@ -17,7 +17,7 @@ namespace cpputils {
return size * nmemb;
}
CurlHttpClient::CurlHttpClient() {
CurlHttpClient::CurlHttpClient(): curlInitializer(), curl() {
curl = curl_easy_init();
}

View File

@ -4,7 +4,7 @@
#include "HttpClient.h"
#include "../macros.h"
#include <curl/curl.h>
#include "CurlInitializerRAII.h"
namespace cpputils {
@ -17,6 +17,7 @@ namespace cpputils {
boost::optional <std::string> get(const std::string &url, boost::optional<long> timeoutMsec = boost::none) override;
private:
CurlInitializerRAII curlInitializer;
CURL *curl;
static size_t write_data(void *ptr, size_t size, size_t nmemb, std::ostringstream *stream);

View File

@ -0,0 +1,27 @@
#include "CurlInitializerRAII.h"
using std::mutex;
using std::unique_lock;
namespace cpputils {
mutex CurlInitializerRAII::_mutex;
uint32_t CurlInitializerRAII::_refcount = 0;
CurlInitializerRAII::CurlInitializerRAII() {
unique_lock<mutex> lock(_mutex);
if (0 == _refcount) {
curl_global_init(CURL_GLOBAL_ALL);
}
_refcount += 1;
}
CurlInitializerRAII::~CurlInitializerRAII() {
unique_lock<mutex> lock(_mutex);
_refcount -= 1;
if (0 == _refcount) {
curl_global_cleanup();
}
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#ifndef MESSMER_CPPUTILS_NETWORK_CURLINITIALIZERRAII_HPP
#define MESSMER_CPPUTILS_NETWORK_CURLINITIALIZERRAII_HPP
#include <cpp-utils/macros.h>
#include <mutex>
#include <curl/curl.h>
namespace cpputils {
// TODO Test
// When the first object of this class is created, it will initialize curl using curl_global_init().
// When the last object is destroyed, it will deinitialize curl using curl_global_cleanup().
class CurlInitializerRAII final {
public:
CurlInitializerRAII();
~CurlInitializerRAII();
private:
static std::mutex _mutex;
static uint32_t _refcount;
DISALLOW_COPY_AND_ASSIGN(CurlInitializerRAII);
};
}
#endif

View File

@ -14,7 +14,7 @@ namespace cpputils{
if (0 != result) {
throw std::runtime_error("sysctlbyname syscall failed");
}
#elif __linux__
#elif __linux__ || __FreeBSD__
long numRAMPages = sysconf(_SC_PHYS_PAGES);
long pageSize = sysconf(_SC_PAGESIZE);
mem = numRAMPages * pageSize;

View File

@ -25,7 +25,6 @@
#include <cpp-utils/io/NoninteractiveConsole.h>
#include "Environment.h"
//TODO Fails with gpg-homedir in filesystem: gpg --homedir gpg-homedir --gen-key
//TODO Many functions accessing the ProgramOptions object. Factor out into class that stores it as a member.
//TODO Factor out class handling askPassword
@ -71,7 +70,6 @@ using gitversion::VersionCompare;
//TODO Improve parallelity.
//TODO Replace ASSERTs with other error handling when it is not a programming error but an environment influence (e.g. a block is missing)
//TODO Can we improve performance by setting compiler parameter -maes for scrypt?
//TODO Running nano in a cryfs file system, editing and saving an existing file shows "file was modified since opening".
namespace cryfs {

View File

@ -24,14 +24,6 @@ CryConfig::CryConfig()
: _rootBlob(""), _encKey(""), _cipher(""), _version(""), _createdWithVersion(""), _blocksizeBytes(0), _filesystemId(FilesystemID::Null()), _exclusiveClientId(none), _hasVersionNumbers(true) {
}
CryConfig::CryConfig(CryConfig &&rhs)
: _rootBlob(std::move(rhs._rootBlob)), _encKey(std::move(rhs._encKey)), _cipher(std::move(rhs._cipher)), _version(std::move(rhs._version)), _createdWithVersion(std::move(rhs._createdWithVersion)), _blocksizeBytes(rhs._blocksizeBytes), _filesystemId(std::move(rhs._filesystemId)), _exclusiveClientId(std::move(rhs._exclusiveClientId)), _hasVersionNumbers(rhs._hasVersionNumbers) {
}
CryConfig::CryConfig(const CryConfig &rhs)
: _rootBlob(rhs._rootBlob), _encKey(rhs._encKey), _cipher(rhs._cipher), _version(rhs._version), _createdWithVersion(rhs._createdWithVersion), _blocksizeBytes(rhs._blocksizeBytes), _filesystemId(rhs._filesystemId) {
}
CryConfig CryConfig::load(const Data &data) {
stringstream stream;
data.StoreToStream(stream);

View File

@ -14,8 +14,8 @@ class CryConfig final {
public:
//TODO No default constructor, pass in config values instead!
CryConfig();
CryConfig(CryConfig &&rhs);
CryConfig(const CryConfig &rhs);
CryConfig(CryConfig &&rhs) = default;
CryConfig(const CryConfig &rhs) = default;
const std::string &RootBlob() const;
void SetRootBlob(const std::string &value);

View File

@ -120,7 +120,44 @@ Key CryDevice::CreateRootBlobAndReturnKey() {
return rootBlob->key();
}
optional<unique_ref<fspp::File>> CryDevice::LoadFile(const bf::path &path) {
auto loaded = Load(path);
if (loaded == none) {
return none;
}
auto file = cpputils::dynamic_pointer_move<fspp::File>(*loaded);
if (file == none) {
throw fspp::fuse::FuseErrnoException(EISDIR); // TODO Also EISDIR if it is a symlink?
}
return std::move(*file);
}
optional<unique_ref<fspp::Dir>> CryDevice::LoadDir(const bf::path &path) {
auto loaded = Load(path);
if (loaded == none) {
return none;
}
auto dir = cpputils::dynamic_pointer_move<fspp::Dir>(*loaded);
if (dir == none) {
throw fspp::fuse::FuseErrnoException(ENOTDIR);
}
return std::move(*dir);
}
optional<unique_ref<fspp::Symlink>> CryDevice::LoadSymlink(const bf::path &path) {
auto loaded = Load(path);
if (loaded == none) {
return none;
}
auto lnk = cpputils::dynamic_pointer_move<fspp::Symlink>(*loaded);
if (lnk == none) {
throw fspp::fuse::FuseErrnoException(ENOTDIR); // TODO ENOTDIR although it is a symlink?
}
return std::move(*lnk);
}
optional<unique_ref<fspp::Node>> CryDevice::Load(const bf::path &path) {
// TODO Is it faster to not let CryFile/CryDir/CryDevice inherit from CryNode and loading CryNode without having to know what it is?
// TODO Split into smaller functions
ASSERT(path.is_absolute(), "Non absolute path given");

View File

@ -35,6 +35,9 @@ public:
void onFsAction(std::function<void()> callback);
boost::optional<cpputils::unique_ref<fspp::Node>> Load(const boost::filesystem::path &path) override;
boost::optional<cpputils::unique_ref<fspp::File>> LoadFile(const boost::filesystem::path &path) override;
boost::optional<cpputils::unique_ref<fspp::Dir>> LoadDir(const boost::filesystem::path &path) override;
boost::optional<cpputils::unique_ref<fspp::Symlink>> LoadSymlink(const boost::filesystem::path &path) override;
void callFsActionCallbacks() const;

View File

@ -8,7 +8,7 @@
namespace cryfs {
class CryDir final: public fspp::Dir, CryNode {
class CryDir final: public fspp::Dir, public CryNode {
public:
CryDir(CryDevice *device, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
~CryDir();

View File

@ -9,7 +9,7 @@
namespace cryfs {
class CryFile final: public fspp::File, CryNode {
class CryFile final: public fspp::File, public CryNode {
public:
CryFile(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
~CryFile();

View File

@ -10,7 +10,7 @@
namespace cryfs {
class CryNode: public virtual fspp::Node {
class CryNode: public fspp::Node {
public:
virtual ~CryNode();

View File

@ -9,7 +9,7 @@
namespace cryfs {
class CrySymlink final: public fspp::Symlink, CryNode {
class CrySymlink final: public fspp::Symlink, public CryNode {
public:
CrySymlink(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
~CrySymlink();

View File

@ -8,6 +8,9 @@
namespace fspp {
class Node;
class File;
class Dir;
class Symlink;
class Device {
public:
@ -15,6 +18,14 @@ public:
virtual void statfs(const boost::filesystem::path &path, struct ::statvfs *fsstat) = 0;
virtual boost::optional<cpputils::unique_ref<Node>> Load(const boost::filesystem::path &path) = 0;
//TODO Test default implementation (Device.cpp)
//TODO Test client implementation (fstest)
//TODO When it exists but is wrong node type, don't throw exception, but return this somehow (or at least throw specific exception, not just FuseErrnoException)
virtual boost::optional<cpputils::unique_ref<File>> LoadFile(const boost::filesystem::path &path) = 0;
virtual boost::optional<cpputils::unique_ref<Dir>> LoadDir(const boost::filesystem::path &path) = 0;
virtual boost::optional<cpputils::unique_ref<Symlink>> LoadSymlink(const boost::filesystem::path &path) = 0;
};
}

View File

@ -2,15 +2,15 @@
#ifndef MESSMER_FSPP_FSINTERFACE_DIR_H_
#define MESSMER_FSPP_FSINTERFACE_DIR_H_
#include "Node.h"
#include <cpp-utils/pointer/unique_ref.h>
#include <string>
#include <boost/filesystem/path.hpp>
namespace fspp {
class Device;
class OpenFile;
class Dir: public virtual Node {
class Dir {
public:
virtual ~Dir() {}

View File

@ -2,14 +2,13 @@
#ifndef MESSMER_FSPP_FSINTERFACE_FILE_H_
#define MESSMER_FSPP_FSINTERFACE_FILE_H_
#include "Node.h"
#include <cpp-utils/pointer/unique_ref.h>
namespace fspp {
class Device;
class OpenFile;
class File: public virtual Node {
class File {
public:
virtual ~File() {}

View File

@ -2,14 +2,14 @@
#ifndef MESSMER_FSPP_FSINTERFACE_SYMLINK_H_
#define MESSMER_FSPP_FSINTERFACE_SYMLINK_H_
#include "Node.h"
#include <cpp-utils/pointer/unique_ref.h>
#include <string>
#include <boost/filesystem/path.hpp>
namespace fspp {
class Device;
class Symlink: public virtual Node {
class Symlink {
public:
virtual ~Symlink() {}

View File

@ -18,7 +18,8 @@
#include "FsppOpenFileTest_Timestamps.h"
#define FSPP_ADD_FILESYTEM_TESTS(FS_NAME, FIXTURE) \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest_One, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest_Two, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppDeviceTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDirTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDirTest_Timestamps, FIXTURE); \

View File

@ -2,104 +2,481 @@
#ifndef MESSMER_FSPP_FSTEST_FSPPDEVICETEST_H_
#define MESSMER_FSPP_FSTEST_FSPPDEVICETEST_H_
#include <fspp/fuse/FuseErrnoException.h>
template<class ConcreteFileSystemTestFixture>
class FsppDeviceTest: public FileSystemTest<ConcreteFileSystemTestFixture> {
public:
void InitDirStructure() {
this->LoadDir("/")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/")->createSymlink("mysymlink", "/symlink/target", 0, 0);
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/")->createDir("myemptydir", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir")->createAndOpenFile("myfile2", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir")->createSymlink("mysymlink", "/symlink/target", 0, 0);
this->LoadDir("/mydir")->createDir("mysubdir", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir/mysubdir")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir/mysubdir")->createSymlink("mysymlink", "/symlink/target", 0, 0);
this->LoadDir("/mydir/mysubdir")->createDir("mysubsubdir", this->MODE_PUBLIC, 0, 0);
}
};
TYPED_TEST_CASE_P(FsppDeviceTest);
//Unfortunately, googletest only allows 50 test cases per REGISTER_TYPED_TEST_CASE_P, so we have to split it.
template<class ConcreteFileSystemTestFixture> class FsppDeviceTest_One: public FsppDeviceTest<ConcreteFileSystemTestFixture> {};
template<class ConcreteFileSystemTestFixture> class FsppDeviceTest_Two: public FsppDeviceTest<ConcreteFileSystemTestFixture> {};
TYPED_TEST_P(FsppDeviceTest, InitFilesystem) {
TYPED_TEST_CASE_P(FsppDeviceTest_One);
TYPED_TEST_CASE_P(FsppDeviceTest_Two);
TYPED_TEST_P(FsppDeviceTest_One, InitFilesystem) {
//fixture->createDevice() is called in the FileSystemTest constructor
}
TYPED_TEST_P(FsppDeviceTest, LoadRootDir) {
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_Load) {
auto node = this->Load("/");
this->EXPECT_IS_DIR(node);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_LoadDir) {
this->LoadDir("/");
}
TYPED_TEST_P(FsppDeviceTest, LoadFileFromRootDir) {
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_LoadFile) {
EXPECT_THROW(
this->LoadFile("/"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_LoadSymlink) {
EXPECT_THROW(
this->LoadSymlink("/"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_Load) {
this->InitDirStructure();
auto node = this->Load("/myfile");
this->EXPECT_IS_FILE(node);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_LoadFile) {
this->InitDirStructure();
this->LoadFile("/myfile");
}
TYPED_TEST_P(FsppDeviceTest, LoadDirFromRootDir) {
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_LoadDir) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadDir("/myfile"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_LoadSymlink) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadSymlink("/myfile"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_Load) {
this->InitDirStructure();
auto node = this->Load("/mydir");
this->EXPECT_IS_DIR(node);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_LoadDir) {
this->InitDirStructure();
this->LoadDir("/mydir");
}
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromEmptyRootDir) {
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromRootDir) {
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_LoadFile) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromNonexistingDir) {
this->InitDirStructure();
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
EXPECT_ANY_THROW(
this->device->Load("/nonexisting/nonexisting2")
EXPECT_THROW(
this->LoadFile("/mydir"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromExistingDir) {
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_LoadSymlink) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadSymlink("/mydir"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_Load) {
this->InitDirStructure();
auto node = this->Load("/mysymlink");
this->EXPECT_IS_SYMLINK(node);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_LoadSymlink) {
this->InitDirStructure();
this->LoadSymlink("/mysymlink");
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_LoadFile) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadFile("/mysymlink"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_LoadDir) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadDir("/mysymlink"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_Load) {
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_LoadDir) {
EXPECT_EQ(boost::none, this->device->LoadDir("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_LoadFile) {
EXPECT_EQ(boost::none, this->device->LoadFile("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_LoadSymlink) {
EXPECT_EQ(boost::none, this->device->LoadSymlink("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_Load) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_LoadDir) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadDir("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_LoadFile) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadFile("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_LoadSymlink) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadSymlink("/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_Load) {
this->InitDirStructure();
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
EXPECT_ANY_THROW(
this->device->Load("/nonexisting/nonexisting2")
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_LoadDir) {
this->InitDirStructure();
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
EXPECT_ANY_THROW(
this->device->LoadDir("/nonexisting/nonexisting2")
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_LoadFile) {
this->InitDirStructure();
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
EXPECT_ANY_THROW(
this->device->LoadFile("/nonexisting/nonexisting2")
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_LoadSymlink) {
this->InitDirStructure();
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
EXPECT_ANY_THROW(
this->device->LoadSymlink("/nonexisting/nonexisting2")
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_Load) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->Load("/mydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromExistingEmptyDir) {
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_LoadDir) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadDir("/mydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_LoadFile) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadFile("/mydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_LoadSymlink) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadSymlink("/mydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_Load) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->Load("/myemptydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest, LoadFileFromDir_Nesting1) {
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_LoadDir) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadDir("/myemptydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_LoadFile) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadFile("/myemptydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_LoadSymlink) {
this->InitDirStructure();
EXPECT_EQ(boost::none, this->device->LoadSymlink("/myemptydir/nonexisting"));
}
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_Load) {
this->InitDirStructure();
auto node = this->Load("/mydir/myfile");
this->EXPECT_IS_FILE(node);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_LoadFile) {
this->InitDirStructure();
this->LoadFile("/mydir/myfile");
}
TYPED_TEST_P(FsppDeviceTest, LoadDirFromDir_Nesting1) {
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_LoadDir) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadDir("/mydir/myfile"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_LoadSymlink) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadSymlink("/mydir/myfile"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_Load) {
this->InitDirStructure();
auto node = this->Load("/mydir/mysubdir");
this->EXPECT_IS_DIR(node);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_LoadDir) {
this->InitDirStructure();
this->LoadDir("/mydir/mysubdir");
}
TYPED_TEST_P(FsppDeviceTest, LoadFileFromDir_Nesting2) {
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_LoadFile) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadFile("/mydir/mysubdir"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_LoadSymlink) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadSymlink("/mydir/mysubdir"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_Load) {
this->InitDirStructure();
auto node = this->Load("/mydir/mysymlink");
this->EXPECT_IS_SYMLINK(node);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_LoadSymlink) {
this->InitDirStructure();
this->LoadSymlink("/mydir/mysymlink");
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_LoadFile) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadFile("/mydir/mysymlink"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_LoadDir) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadDir("/mydir/mysymlink"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_Load) {
this->InitDirStructure();
auto node = this->Load("/mydir/mysubdir/myfile");
this->EXPECT_IS_FILE(node);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_LoadFile) {
this->InitDirStructure();
this->LoadFile("/mydir/mysubdir/myfile");
}
TYPED_TEST_P(FsppDeviceTest, LoadDirFromDir_Nesting2) {
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_LoadDir) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadDir("/mydir/mysubdir/myfile"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_LoadSymlink) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadSymlink("/mydir/mysubdir/myfile"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_Load) {
this->InitDirStructure();
auto node = this->Load("/mydir/mysubdir/mysubsubdir");
this->EXPECT_IS_DIR(node);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_LoadDir) {
this->InitDirStructure();
this->LoadDir("/mydir/mysubdir/mysubsubdir");
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_LoadFile) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadFile("/mydir/mysubdir/mysubsubdir"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_LoadSymlink) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadSymlink("/mydir/mysubdir/mysubsubdir"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_Load) {
this->InitDirStructure();
auto node = this->Load("/mydir/mysubdir/mysymlink");
this->EXPECT_IS_SYMLINK(node);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_LoadSymlink) {
this->InitDirStructure();
this->LoadSymlink("/mydir/mysubdir/mysymlink");
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_LoadFile) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadFile("/mydir/mysubdir/mysymlink"),
fspp::fuse::FuseErrnoException
);
}
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_LoadDir) {
this->InitDirStructure();
EXPECT_THROW(
this->LoadDir("/mydir/mysubdir/mysymlink"),
fspp::fuse::FuseErrnoException
);
}
//TODO Test statfs
REGISTER_TYPED_TEST_CASE_P(FsppDeviceTest,
REGISTER_TYPED_TEST_CASE_P(FsppDeviceTest_One,
InitFilesystem,
LoadRootDir,
LoadFileFromRootDir,
LoadDirFromRootDir,
LoadNonexistingFromEmptyRootDir,
LoadNonexistingFromRootDir,
LoadNonexistingFromNonexistingDir,
LoadNonexistingFromExistingDir,
LoadNonexistingFromExistingEmptyDir,
LoadFileFromDir_Nesting1,
LoadDirFromDir_Nesting1,
LoadFileFromDir_Nesting2,
LoadDirFromDir_Nesting2
LoadRootDir_Load,
LoadRootDir_LoadDir,
LoadRootDir_LoadFile,
LoadRootDir_LoadSymlink,
LoadFileFromRootDir_Load,
LoadFileFromRootDir_LoadFile,
LoadFileFromRootDir_LoadDir,
LoadFileFromRootDir_LoadSymlink,
LoadDirFromRootDir_Load,
LoadDirFromRootDir_LoadDir,
LoadDirFromRootDir_LoadFile,
LoadDirFromRootDir_LoadSymlink,
LoadSymlinkFromRootDir_Load,
LoadSymlinkFromRootDir_LoadSymlink,
LoadSymlinkFromRootDir_LoadFile,
LoadSymlinkFromRootDir_LoadDir,
LoadNonexistingFromEmptyRootDir_Load,
LoadNonexistingFromEmptyRootDir_LoadDir,
LoadNonexistingFromEmptyRootDir_LoadFile,
LoadNonexistingFromEmptyRootDir_LoadSymlink,
LoadNonexistingFromRootDir_Load,
LoadNonexistingFromRootDir_LoadDir,
LoadNonexistingFromRootDir_LoadFile,
LoadNonexistingFromRootDir_LoadSymlink,
LoadNonexistingFromNonexistingDir_Load,
LoadNonexistingFromNonexistingDir_LoadDir,
LoadNonexistingFromNonexistingDir_LoadFile,
LoadNonexistingFromNonexistingDir_LoadSymlink,
LoadNonexistingFromExistingDir_Load,
LoadNonexistingFromExistingDir_LoadDir,
LoadNonexistingFromExistingDir_LoadFile,
LoadNonexistingFromExistingDir_LoadSymlink,
LoadNonexistingFromExistingEmptyDir_Load,
LoadNonexistingFromExistingEmptyDir_LoadDir,
LoadNonexistingFromExistingEmptyDir_LoadFile,
LoadNonexistingFromExistingEmptyDir_LoadSymlink,
LoadFileFromDir_Nesting1_Load,
LoadFileFromDir_Nesting1_LoadFile,
LoadFileFromDir_Nesting1_LoadDir,
LoadFileFromDir_Nesting1_LoadSymlink,
LoadDirFromDir_Nesting1_Load,
LoadDirFromDir_Nesting1_LoadDir,
LoadDirFromDir_Nesting1_LoadFile,
LoadDirFromDir_Nesting1_LoadSymlink,
LoadSymlinkFromDir_Nesting1_Load,
LoadSymlinkFromDir_Nesting1_LoadSymlink,
LoadSymlinkFromDir_Nesting1_LoadFile,
LoadSymlinkFromDir_Nesting1_LoadDir
);
REGISTER_TYPED_TEST_CASE_P(FsppDeviceTest_Two,
LoadFileFromDir_Nesting2_Load,
LoadFileFromDir_Nesting2_LoadFile,
LoadFileFromDir_Nesting2_LoadDir,
LoadFileFromDir_Nesting2_LoadSymlink,
LoadDirFromDir_Nesting2_Load,
LoadDirFromDir_Nesting2_LoadDir,
LoadDirFromDir_Nesting2_LoadFile,
LoadDirFromDir_Nesting2_LoadSymlink,
LoadSymlinkFromDir_Nesting2_Load,
LoadSymlinkFromDir_Nesting2_LoadSymlink,
LoadSymlinkFromDir_Nesting2_LoadFile,
LoadSymlinkFromDir_Nesting2_LoadDir
);
//TODO Missing tests: LoadSymlink
#endif

View File

@ -5,21 +5,21 @@
#include "testutils/TimestampTestUtils.h"
template<class ConcreteFileSystemTestFixture>
class FsppDeviceTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
class FsppDeviceTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
public:
void Test_Load_While_Loaded() {
auto node = this->CreateNode("/mynode");
auto operation = [this, &node] () {
this->device->Load("/mynode");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {this->ExpectDoesntUpdateAnyTimestamps});
}
void Test_Load_While_Not_Loaded() {
struct stat oldStat;
{
auto node = this->CreateNode("/mynode");
oldStat = stat(*node);
oldStat = this->stat(*node);
this->ensureNodeTimestampsAreOld(oldStat);
}
@ -28,7 +28,7 @@ public:
auto node = this->device->Load("/mynode");
//Test that timestamps didn't change
struct stat newStat = stat(*node.value());
struct stat newStat = this->stat(*node.value());
EXPECT_EQ(oldStat.st_atim, newStat.st_atim);
EXPECT_EQ(oldStat.st_mtim, newStat.st_mtim);
EXPECT_EQ(oldStat.st_ctim, newStat.st_ctim);

View File

@ -17,7 +17,7 @@ public:
}
void EXPECT_CHILDREN_ARE(const boost::filesystem::path &path, const std::initializer_list<fspp::Dir::Entry> expected) {
EXPECT_CHILDREN_ARE(this->LoadDir(path).get(), expected);
EXPECT_CHILDREN_ARE(this->LoadDir(path).get(), expected);
}
void EXPECT_CHILDREN_ARE(fspp::Dir *dir, const std::initializer_list<fspp::Dir::Entry> expected) {
@ -163,6 +163,7 @@ TYPED_TEST_P(FsppDirTest, Children_Nested2_LargerStructure) {
TYPED_TEST_P(FsppDirTest, CreateAndOpenFile_InEmptyRoot) {
this->LoadDir("/")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
this->LoadFile("/myfile");
this->Load("/myfile"); // Test that we can also load the file node
}
TYPED_TEST_P(FsppDirTest, CreateAndOpenFile_InNonemptyRoot) {
@ -206,6 +207,7 @@ TYPED_TEST_P(FsppDirTest, CreateAndOpenFile_AlreadyExisting) {
TYPED_TEST_P(FsppDirTest, CreateDir_InEmptyRoot) {
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir");
this->Load("/mydir"); // Test we can also load the dir node
}
TYPED_TEST_P(FsppDirTest, CreateDir_InNonemptyRoot) {
@ -247,18 +249,22 @@ TYPED_TEST_P(FsppDirTest, CreateDir_AlreadyExisting) {
}
TYPED_TEST_P(FsppDirTest, Remove) {
this->CreateDir("/mytestdir");
EXPECT_NE(boost::none, this->device->Load("/mytestdir"));
this->LoadDir("/mytestdir")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mytestdir"));
this->CreateDir("/mytestdir");
EXPECT_NE(boost::none, this->device->Load("/mytestdir"));
EXPECT_NE(boost::none, this->device->LoadDir("/mytestdir"));
this->Load("/mytestdir")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mytestdir"));
EXPECT_EQ(boost::none, this->device->LoadDir("/mytestdir"));
}
TYPED_TEST_P(FsppDirTest, Remove_Nested) {
this->CreateDir("/mytestdir");
this->CreateDir("/mytestdir/mydir");
EXPECT_NE(boost::none, this->device->Load("/mytestdir/mydir"));
this->LoadDir("/mytestdir/mydir")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mytestdir/mydir"));
this->CreateDir("/mytestdir");
this->CreateDir("/mytestdir/mydir");
EXPECT_NE(boost::none, this->device->Load("/mytestdir/mydir"));
EXPECT_NE(boost::none, this->device->LoadDir("/mytestdir/mydir"));
this->Load("/mytestdir/mydir")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mytestdir/mydir"));
EXPECT_EQ(boost::none, this->device->LoadDir("/mytestdir/mydir"));
}
REGISTER_TYPED_TEST_CASE_P(FsppDirTest,

View File

@ -5,7 +5,7 @@
#include "testutils/TimestampTestUtils.h"
template<class ConcreteFileSystemTestFixture>
class FsppDirTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
class FsppDirTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
public:
};
TYPED_TEST_CASE_P(FsppDirTest_Timestamps);
@ -15,7 +15,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile) {
auto operation = [&dir] () {
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -24,7 +24,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_inRootDir) {
auto operation = [&dir] () {
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_TimestampsOfCreatedFile) {
@ -32,7 +32,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_TimestampsOfCreatedFile)
timespec lowerBound = now();
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
timespec upperBound = now();
auto child = this->LoadFile("/mydir/childname");
auto child = this->Load("/mydir/childname");
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *child);
@ -43,7 +43,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createDir) {
auto operation = [&dir] () {
dir->createDir("childname", S_IFDIR, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -52,7 +52,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createDir_inRootDir) {
auto operation = [&dir] () {
dir->createDir("childname", S_IFDIR, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, createDir_TimestampsOfCreatedDir) {
@ -60,7 +60,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createDir_TimestampsOfCreatedDir) {
timespec lowerBound = now();
dir->createDir("childname", S_IFDIR, 1000, 1000);
timespec upperBound = now();
auto child = this->LoadDir("/mydir/childname");
auto child = this->Load("/mydir/childname");
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *child);
@ -71,7 +71,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink) {
auto operation = [&dir] () {
dir->createSymlink("childname", "/target", 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -80,7 +80,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_inRootDir) {
auto operation = [&dir] () {
dir->createSymlink("childname", "/target", 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_TimestampsOfCreatedSymlink) {
@ -88,7 +88,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_TimestampsOfCreatedSymlink) {
timespec lowerBound = now();
dir->createSymlink("childname", "/target", 1000, 1000);
timespec upperBound = now();
auto child = this->LoadSymlink("/mydir/childname");
auto child = this->Load("/mydir/childname");
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *child);
@ -99,7 +99,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_empty) {
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -108,7 +108,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_empty_inRootDir) {
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty) {
@ -117,7 +117,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty) {
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -127,11 +127,11 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty_inRootDir) {
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}*/
template<class ConcreteFileSystemTestFixture>
class FsppDirTest_Timestamps_Entries: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
class FsppDirTest_Timestamps_Entries: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
public:
void Test_deleteChild() {
@ -140,9 +140,11 @@ public:
auto operation = [&child]() {
child->remove();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -152,7 +154,7 @@ public:
auto operation = [&child] () {
child->remove();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
void Test_renameChild() {
@ -161,9 +163,11 @@ public:
auto operation = [&child]() {
child->rename("/mydir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -173,7 +177,7 @@ public:
auto operation = [&child] () {
child->rename("/mydir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
void Test_moveChildIn() {
@ -183,9 +187,11 @@ public:
auto operation = [&child]() {
child->rename("/mydir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -196,7 +202,7 @@ public:
auto operation = [&child] () {
child->rename("/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
void Test_moveChildOut() {
@ -206,9 +212,11 @@ public:
auto operation = [&child]() {
child->rename("/targetdir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
@ -219,7 +227,7 @@ public:
auto operation = [&child] () {
child->rename("/targetdir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
};

View File

@ -7,6 +7,8 @@
#include "testutils/FileTest.h"
//TODO Restructure. FsppFileTest tests fspp::File interface. All tests for fspp::Node interface go to a FsppNodeTest.
template<class ConcreteFileSystemTestFixture>
class FsppFileTest: public FileTest<ConcreteFileSystemTestFixture> {
public:
@ -22,65 +24,65 @@ public:
file->open(O_RDONLY);
}
void Test_Truncate_DontChange1(fspp::File *file) {
void Test_Truncate_DontChange1(fspp::File *file, fspp::Node *node) {
file->truncate(0);
this->EXPECT_SIZE(0, file);
this->EXPECT_SIZE(0, file, node);
}
void Test_Truncate_GrowTo1(fspp::File *file) {
void Test_Truncate_GrowTo1(fspp::File *file, fspp::Node *node) {
file->truncate(1);
this->EXPECT_SIZE(1, file);
this->EXPECT_SIZE(1, file, node);
}
void Test_Truncate_Grow(fspp::File *file) {
void Test_Truncate_Grow(fspp::File *file, fspp::Node *node) {
file->truncate(10*1024*1024);
this->EXPECT_SIZE(10*1024*1024, file);
this->EXPECT_SIZE(10*1024*1024, file, node);
}
void Test_Truncate_DontChange2(fspp::File *file) {
void Test_Truncate_DontChange2(fspp::File *file, fspp::Node *node) {
file->truncate(10*1024*1024);
file->truncate(10*1024*1024);
this->EXPECT_SIZE(10*1024*1024, file);
this->EXPECT_SIZE(10*1024*1024, file, node);
}
void Test_Truncate_Shrink(fspp::File *file) {
void Test_Truncate_Shrink(fspp::File *file, fspp::Node *node) {
file->truncate(10*1024*1024);
file->truncate(5*1024*1024);
this->EXPECT_SIZE(5*1024*1024, file);
this->EXPECT_SIZE(5*1024*1024, file, node);
}
void Test_Truncate_ShrinkTo0(fspp::File *file) {
void Test_Truncate_ShrinkTo0(fspp::File *file, fspp::Node *node) {
file->truncate(10*1024*1024);
file->truncate(0);
this->EXPECT_SIZE(0, file);
this->EXPECT_SIZE(0, file, node);
}
void Test_Chown_Uid(fspp::File *file) {
file->chown(100, 200);
this->IN_STAT(file, [] (struct stat st){
EXPECT_EQ(100u, st.st_uid);
});
void Test_Chown_Uid(fspp::File *file, fspp::Node *node) {
node->chown(100, 200);
this->IN_STAT(file, node, [] (struct stat st){
EXPECT_EQ(100u, st.st_uid);
});
}
void Test_Chown_Gid(fspp::File *file) {
file->chown(100, 200);
this->IN_STAT(file, [] (struct stat st){
void Test_Chown_Gid(fspp::File *file, fspp::Node *node) {
node->chown(100, 200);
this->IN_STAT(file, node, [] (struct stat st){
EXPECT_EQ(200u, st.st_gid);
});
}
void Test_Chmod(fspp::File *file) {
file->chmod(S_IFREG | S_IRUSR | S_IWOTH);
this->IN_STAT(file, [] (struct stat st){
void Test_Chmod(fspp::File *file, fspp::Node *node) {
node->chmod(S_IFREG | S_IRUSR | S_IWOTH);
this->IN_STAT(file, node, [] (struct stat st){
EXPECT_EQ((mode_t)(S_IFREG | S_IRUSR | S_IWOTH), st.st_mode);
});
}
void Test_Utimens(fspp::File *file) {
void Test_Utimens(fspp::File *file, fspp::Node *node) {
struct timespec ATIME; ATIME.tv_sec = 1458086400; ATIME.tv_nsec = 34525;
struct timespec MTIME; MTIME.tv_sec = 1458086300; MTIME.tv_nsec = 48293;
file->utimens(ATIME, MTIME);
this->IN_STAT(file, [this, ATIME, MTIME] (struct stat st) {
node->utimens(ATIME, MTIME);
this->IN_STAT(file, node, [this, ATIME, MTIME] (struct stat st) {
this->EXPECT_ATIME_EQ(ATIME, st);
this->EXPECT_MTIME_EQ(MTIME, st);
});
@ -114,98 +116,102 @@ TYPED_TEST_P(FsppFileTest, Open_RDWR_Nested) {
}
TYPED_TEST_P(FsppFileTest, Truncate_DontChange1) {
this->Test_Truncate_DontChange1(this->file_root.get());
this->Test_Truncate_DontChange1(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_DontChange1_Nested) {
this->Test_Truncate_DontChange1(this->file_nested.get());
this->Test_Truncate_DontChange1(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_GrowTo1) {
this->Test_Truncate_GrowTo1(this->file_root.get());
this->Test_Truncate_GrowTo1(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_GrowTo1_Nested) {
this->Test_Truncate_GrowTo1(this->file_nested.get());
this->Test_Truncate_GrowTo1(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_Grow) {
this->Test_Truncate_Grow(this->file_root.get());
this->Test_Truncate_Grow(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_Grow_Nested) {
this->Test_Truncate_Grow(this->file_nested.get());
this->Test_Truncate_Grow(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_DontChange2) {
this->Test_Truncate_DontChange2(this->file_root.get());
this->Test_Truncate_DontChange2(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_DontChange2_Nested) {
this->Test_Truncate_DontChange2(this->file_nested.get());
this->Test_Truncate_DontChange2(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_Shrink) {
this->Test_Truncate_Shrink(this->file_root.get());
this->Test_Truncate_Shrink(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_Shrink_Nested) {
this->Test_Truncate_Shrink(this->file_nested.get());
this->Test_Truncate_Shrink(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_ShrinkTo0) {
this->Test_Truncate_ShrinkTo0(this->file_root.get());
this->Test_Truncate_ShrinkTo0(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Truncate_ShrinkTo0_Nested) {
this->Test_Truncate_ShrinkTo0(this->file_nested.get());
this->Test_Truncate_ShrinkTo0(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Chown_Uid) {
this->Test_Chown_Uid(this->file_root.get());
this->Test_Chown_Uid(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Chown_Uid_Nested) {
this->Test_Chown_Uid(this->file_nested.get());
this->Test_Chown_Uid(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Chown_Gid) {
this->Test_Chown_Gid(this->file_root.get());
this->Test_Chown_Gid(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Chown_Gid_Nested) {
this->Test_Chown_Gid(this->file_nested.get());
this->Test_Chown_Gid(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Chmod) {
this->Test_Chmod(this->file_root.get());
this->Test_Chmod(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Chmod_Nested) {
this->Test_Chmod(this->file_nested.get());
this->Test_Chmod(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Utimens) {
this->Test_Utimens(this->file_root.get());
this->Test_Utimens(this->file_root.get(), this->file_root_node.get());
}
TYPED_TEST_P(FsppFileTest, Utimens_Nested) {
this->Test_Utimens(this->file_nested.get());
this->Test_Utimens(this->file_nested.get(), this->file_nested_node.get());
}
TYPED_TEST_P(FsppFileTest, Remove) {
this->CreateFile("/mytestfile");
EXPECT_NE(boost::none, this->device->Load("/mytestfile"));
this->LoadFile("/mytestfile")->remove();
EXPECT_NE(boost::none, this->device->LoadFile("/mytestfile"));
this->Load("/mytestfile")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mytestfile"));
EXPECT_EQ(boost::none, this->device->LoadFile("/mytestfile"));
}
TYPED_TEST_P(FsppFileTest, Remove_Nested) {
this->CreateDir("/mytestdir");
this->CreateFile("/mytestdir/myfile");
EXPECT_NE(boost::none, this->device->Load("/mytestdir/myfile"));
this->LoadFile("/mytestdir/myfile")->remove();
EXPECT_NE(boost::none, this->device->LoadFile("/mytestdir/myfile"));
this->Load("/mytestdir/myfile")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mytestdir/myfile"));
EXPECT_EQ(boost::none, this->device->LoadFile("/mytestdir/myfile"));
}
REGISTER_TYPED_TEST_CASE_P(FsppFileTest,

View File

@ -5,12 +5,12 @@
#include "testutils/TimestampTestUtils.h"
template<class ConcreteFileSystemTestFixture>
class FsppFileTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
class FsppFileTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
public:
cpputils::unique_ref<fspp::File> CreateFileWithSize(const boost::filesystem::path &path, off_t size) {
auto file = this->CreateFile(path);
file->truncate(size);
assert(stat(*file).st_size == size);
assert(this->stat(*this->Load(path)).st_size == size);
return file;
}
};
@ -21,7 +21,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_nomode) {
auto operation = [&file] () {
file->open(0);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
}
TYPED_TEST_P(FsppFileTest_Timestamps, open_rdonly) {
@ -29,7 +29,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_rdonly) {
auto operation = [&file] () {
file->open(O_RDONLY);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
}
TYPED_TEST_P(FsppFileTest_Timestamps, open_wronly) {
@ -37,7 +37,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_wronly) {
auto operation = [&file] () {
file->open(O_WRONLY);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
}
TYPED_TEST_P(FsppFileTest_Timestamps, open_rdwr) {
@ -45,7 +45,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_rdwr) {
auto operation = [&file] () {
file->open(O_RDWR);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
}
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_empty) {
@ -53,7 +53,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_empty) {
auto operation = [&file] () {
file->truncate(0);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_nonempty) {
@ -61,7 +61,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_nonempty) {
auto operation = [&file] () {
file->truncate(10);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_empty) {
@ -69,7 +69,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_empty) {
auto operation = [&file] () {
file->truncate(0);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_shrink) {
@ -77,7 +77,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_shrink) {
auto operation = [&file] () {
file->truncate(5);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_grow) {
@ -85,7 +85,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_grow) {
auto operation = [&file] () {
file->truncate(20);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
REGISTER_TYPED_TEST_CASE_P(FsppFileTest_Timestamps,

View File

@ -16,28 +16,28 @@ public:
} catch (const fspp::fuse::FuseErrnoException &e) {
EXPECT_EQ(ENOENT, e.getErrno());
}
//Old file should still exist
//Old node should still exist
EXPECT_NE(boost::none, this->device->Load("/oldname"));
}
void Test_Error_TargetParentDirIsFile() {
auto node = this->CreateNode("/oldname");
this->CreateNode("/oldname");
this->CreateFile("/somefile");
try {
node->rename("/somefile/newname");
this->Load("/somefile")->rename("/somefile/newname");
EXPECT_TRUE(false); // Expect it throws an exception
} catch (const fspp::fuse::FuseErrnoException &e) {
EXPECT_EQ(ENOTDIR, e.getErrno());
}
//Files should still exist
//Nodes should still exist
EXPECT_NE(boost::none, this->device->Load("/oldname"));
EXPECT_NE(boost::none, this->device->Load("/somefile"));
}
void Test_Error_RootDir() {
auto root = this->LoadDir("/");
auto rootDirNode = this->Load("/");
try {
root->rename("/newname");
rootDirNode->rename("/newname");
EXPECT_TRUE(false); // expect throws
} catch (const fspp::fuse::FuseErrnoException &e) {
EXPECT_EQ(EBUSY, e.getErrno());
@ -142,10 +142,10 @@ public:
}
void Test_Overwrite_Error_DirWithFile_InSameDir() {
auto file = this->CreateFile("/oldname");
this->CreateFile("/oldname");
this->CreateDir("/newname");
try {
file->rename("/newname");
this->Load("/oldname")->rename("/newname");
EXPECT_TRUE(false); // expect throw
} catch (const fspp::fuse::FuseErrnoException &e) {
EXPECT_EQ(EISDIR, e.getErrno());
@ -157,10 +157,10 @@ public:
void Test_Overwrite_Error_DirWithFile_InDifferentDir() {
this->CreateDir("/parent1");
this->CreateDir("/parent2");
auto file = this->CreateFile("/parent1/oldname");
this->CreateFile("/parent1/oldname");
this->CreateDir("/parent2/newname");
try {
file->rename("/parent2/newname");
this->Load("/parent1/oldname")->rename("/parent2/newname");
EXPECT_TRUE(false); // expect throw
} catch (const fspp::fuse::FuseErrnoException &e) {
EXPECT_EQ(EISDIR, e.getErrno());
@ -170,10 +170,10 @@ public:
}
void Test_Overwrite_Error_FileWithDir_InSameDir() {
auto dir = this->CreateDir("/oldname");
this->CreateDir("/oldname");
this->CreateFile("/newname");
try {
dir->rename("/newname");
this->Load("/oldname")->rename("/newname");
EXPECT_TRUE(false); // expect throw
} catch (const fspp::fuse::FuseErrnoException &e) {
EXPECT_EQ(ENOTDIR, e.getErrno());
@ -185,10 +185,10 @@ public:
void Test_Overwrite_Error_FileWithDir_InDifferentDir() {
this->CreateDir("/parent1");
this->CreateDir("/parent2");
auto dir = this->CreateDir("/parent1/oldname");
this->CreateDir("/parent1/oldname");
this->CreateFile("/parent2/newname");
try {
dir->rename("/parent2/newname");
this->Load("/parent1/oldname")->rename("/parent2/newname");
EXPECT_TRUE(false); // expect throw
} catch (const fspp::fuse::FuseErrnoException &e) {
EXPECT_EQ(ENOTDIR, e.getErrno());

View File

@ -9,7 +9,8 @@ template<class ConcreteFileSystemTestFixture>
class FsppNodeTest_Stat: public FsppNodeTest<ConcreteFileSystemTestFixture> {
public:
void Test_Nlink() {
auto node = this->CreateNode("/mynode");
this->CreateNode("/mynode");
auto node = this->Load("/mynode");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_EQ(1u, st.st_nlink);
});
@ -23,13 +24,15 @@ class FsppNodeTest_Stat_FileOnly: public FileSystemTest<ConcreteFileSystemTestFi
TYPED_TEST_CASE_P(FsppNodeTest_Stat_FileOnly);
TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, CreatedFileIsEmpty) {
auto file = this->CreateFile("/myfile");
this->EXPECT_SIZE(0, file.get());
this->CreateFile("/myfile");
auto node = this->Load("/myfile");
this->EXPECT_SIZE(0, node.get());
}
TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, FileIsFile) {
auto file = this->CreateFile("/myfile");
this->IN_STAT(file.get(), [] (struct stat st) {
this->CreateFile("/myfile");
auto node = this->Load("/myfile");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISREG(st.st_mode));
});
}
@ -41,8 +44,9 @@ class FsppNodeTest_Stat_DirOnly: public FileSystemTest<ConcreteFileSystemTestFix
TYPED_TEST_CASE_P(FsppNodeTest_Stat_DirOnly);
TYPED_TEST_P(FsppNodeTest_Stat_DirOnly, DirIsDir) {
auto file = this->CreateDir("/mydir");
this->IN_STAT(file.get(), [] (struct stat st) {
this->CreateDir("/mydir");
auto node = this->Load("/mydir");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISDIR(st.st_mode));
});
}
@ -54,8 +58,9 @@ class FsppNodeTest_Stat_SymlinkOnly: public FileSystemTest<ConcreteFileSystemTes
TYPED_TEST_CASE_P(FsppNodeTest_Stat_SymlinkOnly);
TYPED_TEST_P(FsppNodeTest_Stat_SymlinkOnly, SymlinkIsSymlink) {
auto file = this->CreateSymlink("/mysymlink");
this->IN_STAT(file.get(), [] (struct stat st) {
this->CreateSymlink("/mysymlink");
auto node = this->Load("/mysymlink");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISLNK(st.st_mode));
});
}

View File

@ -11,16 +11,16 @@ using namespace cpputils::time;
using std::function;
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
class FsppNodeTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
public:
void Test_Create() {
timespec lowerBound = now();
auto node = this->CreateNode("/mynode");
timespec upperBound = now();
EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *node);
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *node);
}
void Test_Stat() {
@ -29,26 +29,36 @@ public:
struct stat st;
node->stat(&st);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Chmod() {
auto node = this->CreateNode("/mynode");
mode_t mode = stat(*node).st_mode;
mode_t mode = this->stat(*node).st_mode;
auto operation = [&node, mode] () {
node->chmod(mode);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Chown() {
auto node = this->CreateNode("/mynode");
uid_t uid = stat(*node).st_uid;
gid_t gid = stat(*node).st_gid;
uid_t uid = this->stat(*node).st_uid;
gid_t gid = this->stat(*node).st_gid;
auto operation = [&node, uid, gid] () {
node->chown(uid, gid);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Access() {
@ -56,7 +66,9 @@ public:
auto operation = [&node] () {
node->access(0);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Rename_Error_TargetParentDirDoesntExist() {
@ -69,7 +81,9 @@ public:
EXPECT_EQ(ENOENT, e.getErrno()); //Rename fails, everything is ok.
}
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Rename_Error_TargetParentDirIsFile() {
@ -83,13 +97,15 @@ public:
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
}
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Rename_Error_RootDir() {
// TODO Re-enable this test once the root dir stores timestamps correctly
/*
auto root = this->LoadDir("/");
auto root = this->Load("/");
auto operation = [&root] () {
try {
root->rename("/newname");
@ -98,7 +114,9 @@ public:
EXPECT_EQ(EBUSY, e.getErrno()); //Rename fails, everything is ok.
}
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
*/
}
@ -107,7 +125,11 @@ public:
auto operation = [&node] () {
node->rename("/newname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_InNested() {
@ -116,7 +138,11 @@ public:
auto operation = [&node] () {
node->rename("/mydir/newname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/mydir/newname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_RootToNested_SameName() {
@ -125,7 +151,11 @@ public:
auto operation = [&node] () {
node->rename("/mydir/oldname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/oldname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_RootToNested_NewName() {
@ -134,7 +164,11 @@ public:
auto operation = [&node] () {
node->rename("/mydir/newname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/newname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_NestedToRoot_SameName() {
@ -143,7 +177,11 @@ public:
auto operation = [&node] () {
node->rename("/oldname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/oldname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_NestedToRoot_NewName() {
@ -152,7 +190,11 @@ public:
auto operation = [&node] () {
node->rename("/newname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/newname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_NestedToNested_SameName() {
@ -162,7 +204,11 @@ public:
auto operation = [&node] () {
node->rename("/mydir2/oldname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/oldname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_NestedToNested_NewName() {
@ -172,7 +218,11 @@ public:
auto operation = [&node] () {
node->rename("/mydir2/newname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_ToItself() {
@ -180,7 +230,11 @@ public:
auto operation = [&node] () {
node->rename("/oldname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/oldname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_Overwrite_InSameDir() {
@ -189,7 +243,11 @@ public:
auto operation = [&node] () {
node->rename("/newname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_Overwrite_InDifferentDir() {
@ -200,12 +258,17 @@ public:
auto operation = [&node] () {
node->rename("/mydir2/newname");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation, {
this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectDoesntUpdateModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp
});
}
void Test_Rename_Overwrite_Error_DirWithFile_InSameDir() {
auto node = this->CreateFile("/oldname");
this->CreateFile("/oldname");
this->CreateDir("/newname");
auto node = this->Load("/oldname");
auto operation = [&node] () {
try {
node->rename("/newname");
@ -214,14 +277,17 @@ public:
EXPECT_EQ(EISDIR, e.getErrno()); //Rename fails, everything is ok.
}
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Rename_Overwrite_Error_DirWithFile_InDifferentDir() {
this->CreateDir("/mydir1");
this->CreateDir("/mydir2");
auto node = this->CreateFile("/mydir1/oldname");
this->CreateFile("/mydir1/oldname");
this->CreateDir("/mydir2/newname");
auto node = this->Load("/mydir1/oldname");
auto operation = [&node] () {
try {
node->rename("/mydir2/newname");
@ -230,12 +296,15 @@ public:
EXPECT_EQ(EISDIR, e.getErrno());//Rename fails, everything is ok.
}
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Rename_Overwrite_Error_FileWithDir_InSameDir() {
auto node = this->CreateDir("/oldname");
this->CreateDir("/oldname");
this->CreateFile("/newname");
auto node = this->Load("/oldname");
auto operation = [&node] () {
try {
node->rename("/newname");
@ -244,14 +313,17 @@ public:
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
}
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Rename_Overwrite_Error_FileWithDir_InDifferentDir() {
this->CreateDir("/mydir1");
this->CreateDir("/mydir2");
auto node = this->CreateDir("/mydir1/oldname");
this->CreateDir("/mydir1/oldname");
this->CreateFile("/mydir2/newname");
auto node = this->Load("/mydir1/oldname");
auto operation = [&node] () {
try {
node->rename("/mydir2/newname");
@ -260,19 +332,23 @@ public:
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
}
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation, {
this->ExpectDoesntUpdateAnyTimestamps
});
}
void Test_Utimens() {
auto node = this->CreateNode("/mynode");
timespec atime = xSecondsAgo(100);
timespec mtime = xSecondsAgo(200);
timespec atime = this->xSecondsAgo(100);
timespec mtime = this->xSecondsAgo(200);
auto operation = [&node, atime, mtime] () {
node->utimens(atime, mtime);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectUpdatesMetadataTimestamp});
EXPECT_EQ(atime, stat(*node).st_atim);
EXPECT_EQ(mtime, stat(*node).st_mtim);
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectUpdatesMetadataTimestamp
});
EXPECT_EQ(atime, this->stat(*node).st_atim);
EXPECT_EQ(mtime, this->stat(*node).st_mtim);
}
};

View File

@ -5,18 +5,50 @@
#include "testutils/FileTest.h"
template<class ConcreteFileSystemTestFixture>
class FsppOpenFileTest: public FileTest<ConcreteFileSystemTestFixture> {
class FsppOpenFileTest: public FileSystemTest<ConcreteFileSystemTestFixture> {
public:
void IN_STAT(fspp::OpenFile *openFile, std::function<void (struct stat)> callback) {
struct stat st;
openFile->stat(&st);
callback(st);
}
void EXPECT_SIZE(uint64_t expectedSize, fspp::OpenFile *openFile) {
IN_STAT(openFile, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
});
EXPECT_NUMBYTES_READABLE(expectedSize, openFile);
}
void EXPECT_NUMBYTES_READABLE(uint64_t expectedSize, fspp::OpenFile *openFile) {
cpputils::Data data(expectedSize);
//Try to read one byte more than the expected size
ssize_t readBytes = openFile->read(data.data(), expectedSize+1, 0);
//and check that it only read the expected size (but also not less)
EXPECT_EQ(expectedSize, (uint64_t)readBytes);
}
};
TYPED_TEST_CASE_P(FsppOpenFileTest);
TYPED_TEST_P(FsppOpenFileTest, Bla) {
//TODO
TYPED_TEST_P(FsppOpenFileTest, CreatedFileIsEmpty) {
auto file = this->CreateFile("/myfile");
auto openFile = this->LoadFile("/myfile")->open(O_RDONLY);
this->EXPECT_SIZE(0, openFile.get());
}
TYPED_TEST_P(FsppOpenFileTest, FileIsFile) {
auto file = this->CreateFile("/myfile");
auto openFile = this->LoadFile("/myfile")->open(O_RDONLY);
this->IN_STAT(openFile.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISREG(st.st_mode));
});
}
REGISTER_TYPED_TEST_CASE_P(FsppOpenFileTest,
Bla
CreatedFileIsEmpty,
FileIsFile
);
//TODO Test stat

View File

@ -5,7 +5,7 @@
#include "testutils/TimestampTestUtils.h"
template<class ConcreteFileSystemTestFixture>
class FsppOpenFileTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
class FsppOpenFileTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
public:
cpputils::unique_ref<fspp::OpenFile> CreateAndOpenFile(const boost::filesystem::path &path) {
return this->CreateFile(path)->open(O_RDWR);
@ -14,7 +14,8 @@ public:
auto file = this->CreateFile(path);
file->truncate(size);
auto openFile = file->open(O_RDWR);
assert(stat(*openFile).st_size == size);
assert(this->stat(*openFile).st_size == size);
assert(this->stat(*this->Load(path)).st_size == size);
return openFile;
}
};

View File

@ -35,16 +35,20 @@ TYPED_TEST_P(FsppSymlinkTest, Read_RelativePath) {
TYPED_TEST_P(FsppSymlinkTest, Remove) {
this->CreateSymlink("/mysymlink", "/my/symlink/target");
EXPECT_NE(boost::none, this->device->Load("/mysymlink"));
this->LoadSymlink("/mysymlink")->remove();
EXPECT_NE(boost::none, this->device->LoadSymlink("/mysymlink"));
this->Load("/mysymlink")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mysymlink"));
EXPECT_EQ(boost::none, this->device->LoadSymlink("/mysymlink"));
}
TYPED_TEST_P(FsppSymlinkTest, Remove_Nested) {
this->CreateDir("/mytestdir");
this->CreateSymlink("/mytestdir/mysymlink", "/my/symlink/target");
EXPECT_NE(boost::none, this->device->Load("/mytestdir/mysymlink"));
this->LoadSymlink("/mytestdir/mysymlink")->remove();
EXPECT_NE(boost::none, this->device->LoadSymlink("/mytestdir/mysymlink"));
this->Load("/mytestdir/mysymlink")->remove();
EXPECT_EQ(boost::none, this->device->Load("/mytestdir/mysymlink"));
EXPECT_EQ(boost::none, this->device->LoadSymlink("/mytestdir/mysymlink"));
}
REGISTER_TYPED_TEST_CASE_P(FsppSymlinkTest,

View File

@ -5,7 +5,7 @@
#include "testutils/TimestampTestUtils.h"
template<class ConcreteFileSystemTestFixture>
class FsppSymlinkTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
class FsppSymlinkTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
public:
};
TYPED_TEST_CASE_P(FsppSymlinkTest_Timestamps);
@ -15,7 +15,7 @@ TYPED_TEST_P(FsppSymlinkTest_Timestamps, target) {
auto operation = [&symlink] () {
symlink->target();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*symlink, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}
REGISTER_TYPED_TEST_CASE_P(FsppSymlinkTest_Timestamps,

View File

@ -9,6 +9,7 @@
#include <cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h>
#include "../../fs_interface/Device.h"
#include "../../fs_interface/Node.h"
#include "../../fs_interface/Dir.h"
#include "../../fs_interface/File.h"
#include "../../fs_interface/Symlink.h"
@ -35,28 +36,28 @@ public:
static constexpr mode_t MODE_PUBLIC = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
cpputils::unique_ref<fspp::Dir> LoadDir(const boost::filesystem::path &path) {
auto loaded = device->Load(path);
cpputils::unique_ref<fspp::Node> Load(const boost::filesystem::path &path) {
auto loaded = device->Load(path);
EXPECT_NE(boost::none, loaded);
auto dir = cpputils::dynamic_pointer_move<fspp::Dir>(*loaded);
EXPECT_NE(boost::none, dir);
return std::move(*dir);
return std::move(*loaded);
}
cpputils::unique_ref<fspp::Dir> LoadDir(const boost::filesystem::path &path) {
auto loaded = device->LoadDir(path);
EXPECT_NE(boost::none, loaded);
return std::move(*loaded);
}
cpputils::unique_ref<fspp::File> LoadFile(const boost::filesystem::path &path) {
auto loaded = device->Load(path);
auto loaded = device->LoadFile(path);
EXPECT_NE(boost::none, loaded);
auto file = cpputils::dynamic_pointer_move<fspp::File>(*loaded);
EXPECT_NE(boost::none, file);
return std::move(*file);
return std::move(*loaded);
}
cpputils::unique_ref<fspp::Symlink> LoadSymlink(const boost::filesystem::path &path) {
auto loaded = device->Load(path);
auto loaded = device->LoadSymlink(path);
EXPECT_NE(boost::none, loaded);
auto symlink = cpputils::dynamic_pointer_move<fspp::Symlink>(*loaded);
EXPECT_NE(boost::none, symlink);
return std::move(*symlink);
return std::move(*loaded);
}
cpputils::unique_ref<fspp::Dir> CreateDir(const boost::filesystem::path &path) {
@ -73,6 +74,18 @@ public:
this->LoadDir(path.parent_path())->createSymlink(path.filename().native(), target, 0, 0);
return this->LoadSymlink(path);
}
void EXPECT_IS_FILE(const cpputils::unique_ref<fspp::Node> &node) {
EXPECT_NE(nullptr, dynamic_cast<const fspp::File*>(node.get()));
}
void EXPECT_IS_DIR(const cpputils::unique_ref<fspp::Node> &node) {
EXPECT_NE(nullptr, dynamic_cast<const fspp::Dir*>(node.get()));
}
void EXPECT_IS_SYMLINK(const cpputils::unique_ref<fspp::Node> &node) {
EXPECT_NE(nullptr, dynamic_cast<const fspp::Symlink*>(node.get()));
}
};

View File

@ -13,27 +13,31 @@ public:
FileTest(): file_root(), file_nested() {
this->LoadDir("/")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
file_root = cpputils::to_unique_ptr(this->LoadFile("/myfile"));
file_root_node = cpputils::to_unique_ptr(this->Load("/myfile"));
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir")->createAndOpenFile("mynestedfile", this->MODE_PUBLIC, 0, 0);
file_nested = cpputils::to_unique_ptr(this->LoadFile("/mydir/mynestedfile"));
file_nested_node = cpputils::to_unique_ptr(this->Load("/mydir/mynestedfile"));
this->LoadDir("/")->createDir("mydir2", this->MODE_PUBLIC, 0, 0);
}
std::unique_ptr<fspp::File> file_root;
std::unique_ptr<fspp::File> file_nested;
std::unique_ptr<fspp::Node> file_root_node;
std::unique_ptr<fspp::Node> file_nested_node;
//TODO IN_STAT still needed after moving it to FsppNodeTest?
void IN_STAT(fspp::File *file, std::function<void (struct stat)> callback) {
void IN_STAT(fspp::File *file, fspp::Node *node, std::function<void (struct stat)> callback) {
struct stat st1, st2;
file->stat(&st1);
node->stat(&st1);
callback(st1);
file->open(O_RDONLY)->stat(&st2);
callback(st2);
}
void EXPECT_SIZE(uint64_t expectedSize, fspp::File *file) {
IN_STAT(file, [expectedSize] (struct stat st) {
void EXPECT_SIZE(uint64_t expectedSize, fspp::File *file, fspp::Node *node) {
IN_STAT(file, node, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
});

View File

@ -7,6 +7,8 @@
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
// TODO separation into File/Dir/Symlink Helpers probably not needed anymore
class FsppNodeTestBase {
public:
virtual void IN_STAT(fspp::Node *node, std::function<void (struct stat)> callback) = 0;
@ -22,7 +24,7 @@ public:
* See FsppNodeTest_Rename for an example.
*/
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest: public virtual FsppNodeTestBase, public FileSystemTest<ConcreteFileSystemTestFixture> {
class FsppNodeTest: public virtual FsppNodeTestBase, public virtual FileSystemTest<ConcreteFileSystemTestFixture> {
public:
virtual cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) = 0;
};
@ -30,30 +32,15 @@ public:
class FsppNodeTest_File_Helper: public virtual FsppNodeTestBase {
public:
void IN_STAT(fspp::Node *file, std::function<void (struct stat)> callback) override {
struct stat st1, st2;
file->stat(&st1);
callback(st1);
dynamic_cast<fspp::File &>(*file).open(O_RDONLY)->stat(&st2);
callback(st2);
struct stat st;
file->stat(&st);
callback(st);
}
void EXPECT_SIZE(uint64_t expectedSize, fspp::Node *node) override {
IN_STAT(node, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
});
fspp::File* fileNode = dynamic_cast<fspp::File*>(node);
ASSERT(fileNode != nullptr, "Is not a file node");
EXPECT_NUMBYTES_READABLE(expectedSize, fileNode);
}
void EXPECT_NUMBYTES_READABLE(uint64_t expectedSize, fspp::File *file) {
auto openFile = file->open(O_RDONLY);
cpputils::Data data(expectedSize);
//Try to read one byte more than the expected size
ssize_t readBytes = openFile->read(data.data(), expectedSize+1, 0);
//and check that it only read the expected size (but also not less)
EXPECT_EQ(expectedSize, (uint64_t)readBytes);
}
};
@ -101,7 +88,8 @@ public:
class Class##_FileNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_File_Helper { \
public: \
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
return this->CreateFile(path); \
this->CreateFile(path); \
return this->Load(path); \
} \
}; \
TYPED_TEST_CASE_P(Class##_FileNode); \
@ -112,7 +100,8 @@ public:
class Class##_DirNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_Dir_Helper { \
public: \
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
return this->CreateDir(path); \
this->CreateDir(path); \
return this->Load(path); \
} \
}; \
TYPED_TEST_CASE_P(Class##_DirNode); \
@ -123,7 +112,8 @@ public:
class Class##_SymlinkNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_Symlink_Helper { \
public: \
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
return this->CreateSymlink(path); \
this->CreateSymlink(path); \
return this->Load(path); \
} \
}; \
TYPED_TEST_CASE_P(Class##_SymlinkNode); \

View File

@ -4,100 +4,83 @@
#include <cpp-utils/system/time.h>
#include <cpp-utils/system/stat.h>
#include "FileSystemTest.h"
#include <functional>
class TimestampTestUtils {
template<class ConcreteFileSystemTestFixture>
class TimestampTestUtils : public virtual FileSystemTest<ConcreteFileSystemTestFixture> {
public:
using TimestampUpdateBehavior = std::function<void (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation)>;
TimestampUpdateBehavior ExpectUpdatesAccessTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_atim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_atim);
};
static TimestampUpdateBehavior ExpectUpdatesAccessTimestamp;
static TimestampUpdateBehavior ExpectDoesntUpdateAccessTimestamp;
static TimestampUpdateBehavior ExpectUpdatesModificationTimestamp;
static TimestampUpdateBehavior ExpectDoesntUpdateModificationTimestamp;
static TimestampUpdateBehavior ExpectUpdatesMetadataTimestamp;
static TimestampUpdateBehavior ExpectDoesntUpdateMetadataTimestamp;
static TimestampUpdateBehavior ExpectDoesntUpdateAnyTimestamps;
TimestampUpdateBehavior ExpectDoesntUpdateAccessTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_atim, statAfterOperation.st_atim);
};
TimestampUpdateBehavior ExpectUpdatesModificationTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_mtim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_mtim);
};
TimestampUpdateBehavior ExpectDoesntUpdateModificationTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_mtim, statAfterOperation.st_mtim);
};
TimestampUpdateBehavior ExpectUpdatesMetadataTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_ctim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_ctim);
};
TimestampUpdateBehavior ExpectDoesntUpdateMetadataTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_ctim, statAfterOperation.st_ctim);
};
TimestampUpdateBehavior ExpectDoesntUpdateAnyTimestamps = [this] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
ExpectDoesntUpdateAccessTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
ExpectDoesntUpdateModificationTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
ExpectDoesntUpdateMetadataTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
};
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(std::function<struct stat()> stat, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
struct stat oldStat = stat();
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(std::function<struct stat()> statOld, std::function<struct stat()> statNew, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
struct stat oldStat = statOld();
ensureNodeTimestampsAreOld(oldStat);
timespec timeBeforeOperation = cpputils::time::now();
operation();
timespec timeAfterOperation = cpputils::time::now();
struct stat newStat = stat();
struct stat newStat = statNew();
for (auto behaviorCheck : behaviorChecks) {
behaviorCheck(oldStat, newStat, timeBeforeOperation, timeAfterOperation);
}
}
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const fspp::OpenFile &node, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
return EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS([&node](){return stat(node);}, operation, behaviorChecks);
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(
[this, &node](){return this->stat(node);},
[this, &node](){return this->stat(node);},
operation,
behaviorChecks
);
}
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const fspp::Node &node, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
return EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS([&node](){return stat(node);}, operation, behaviorChecks);
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const boost::filesystem::path &oldPath, const boost::filesystem::path &newPath, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(
[this, oldPath](){return this->stat(*this->Load(oldPath));},
[this, newPath](){return this->stat(*this->Load(newPath));},
operation,
behaviorChecks
);
}
template<typename NodeType>
void EXPECT_ACCESS_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const NodeType &node) {
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const boost::filesystem::path &path, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(path, path, operation, behaviorChecks);
}
void EXPECT_ACCESS_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_atim);
EXPECT_GE(upperBound, stat(node).st_atim);
}
template<typename NodeType>
void EXPECT_MODIFICATION_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const NodeType &node) {
void EXPECT_MODIFICATION_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_mtim);
EXPECT_GE(upperBound, stat(node).st_mtim);
}
template<typename NodeType>
void EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const NodeType &node) {
void EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_ctim);
EXPECT_GE(upperBound, stat(node).st_ctim);
}
template<typename NodeType>
static struct stat stat(const NodeType &node) {
static struct stat stat(const fspp::Node &node) {
struct stat st;
node.stat(&st);
return st;
}
static struct stat stat(const fspp::OpenFile &openFile) {
struct stat st;
openFile.stat(&st);
return st;
}
timespec xSecondsAgo(int sec) {
timespec result = cpputils::time::now();
result.tv_sec -= sec;
@ -121,4 +104,62 @@ private:
}
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesAccessTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_atim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_atim);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAccessTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_atim, statAfterOperation.st_atim);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesModificationTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_mtim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_mtim);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateModificationTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_mtim, statAfterOperation.st_mtim);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesMetadataTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_ctim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_ctim);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateMetadataTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_ctim, statAfterOperation.st_ctim);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAnyTimestamps =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
ExpectDoesntUpdateAccessTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
ExpectDoesntUpdateModificationTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
ExpectDoesntUpdateMetadataTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
};
#endif

View File

@ -7,6 +7,7 @@
#include "../fuse/FuseErrnoException.h"
#include "../fs_interface/File.h"
#include "../fs_interface/Node.h"
#include <cpp-utils/logging/logging.h>
#include <cpp-utils/pointer/unique_ref.h>
@ -93,62 +94,31 @@ FilesystemImpl::~FilesystemImpl() {
unique_ref<File> FilesystemImpl::LoadFile(const bf::path &path) {
PROFILE(_loadFileNanosec);
auto node = _device->Load(path);
if (node == none) {
throw fuse::FuseErrnoException(EIO);
}
auto file = dynamic_pointer_move<File>(*node);
auto file = _device->LoadFile(path);
if (file == none) {
throw fuse::FuseErrnoException(EISDIR);
throw fuse::FuseErrnoException(EIO);
}
return std::move(*file);
}
unique_ref<Dir> FilesystemImpl::LoadDir(const bf::path &path) {
PROFILE(_loadDirNanosec);
auto node = _device->Load(path);
if (node == none) {
throw fuse::FuseErrnoException(EIO);
}
auto dir = dynamic_pointer_move<Dir>(*node);
auto dir = _device->LoadDir(path);
if (dir == none) {
throw fuse::FuseErrnoException(ENOTDIR);
throw fuse::FuseErrnoException(EIO);
}
return std::move(*dir);
}
unique_ref<Symlink> FilesystemImpl::LoadSymlink(const bf::path &path) {
PROFILE(_loadSymlinkNanosec);
auto node = _device->Load(path);
if (node == none) {
throw fuse::FuseErrnoException(EIO);
}
auto lnk = dynamic_pointer_move<Symlink>(*node);
auto lnk = _device->LoadSymlink(path);
if (lnk == none) {
throw fuse::FuseErrnoException(ENOTDIR);
throw fuse::FuseErrnoException(EIO);
}
return std::move(*lnk);
}
unique_ref<Node> FilesystemImpl::LoadFileOrSymlink(const bf::path &path) {
PROFILE(_loadFileOrSymlinkNanosec);
auto node = _device->Load(path);
if (node == none) {
throw fuse::FuseErrnoException(EIO);
}
auto file = dynamic_pointer_move<File>(*node);
if (file != none) {
return std::move(*file);
}
auto symlink = dynamic_pointer_move<Symlink>(*node);
if (symlink != none) {
return std::move(*symlink);
}
throw fuse::FuseErrnoException(EISDIR);
}
int FilesystemImpl::openFile(const bf::path &path, int flags) {
auto file = LoadFile(path);
return openFile(file.get(), flags);
@ -260,17 +230,25 @@ void FilesystemImpl::mkdir(const bf::path &path, mode_t mode, uid_t uid, gid_t g
}
void FilesystemImpl::rmdir(const bf::path &path) {
//TODO Don't allow removing files/symlinks with this
PROFILE(_rmdirNanosec);
auto dir = LoadDir(path);
auto node = _device->Load(path);
if(node == none) {
throw fuse::FuseErrnoException(ENOENT);
}
PROFILE(_rmdirNanosec_withoutLoading);
dir->remove();
(*node)->remove();
}
void FilesystemImpl::unlink(const bf::path &path) {
//TODO Don't allow removing directories with this
PROFILE(_unlinkNanosec);
auto node = LoadFileOrSymlink(path);
auto node = _device->Load(path);
if (node == none) {
throw fuse::FuseErrnoException(ENOENT);
}
PROFILE(_unlinkNanosec_withoutLoading);
node->remove();
(*node)->remove();
}
void FilesystemImpl::rename(const bf::path &from, const bf::path &to) {

View File

@ -11,7 +11,7 @@ function (get_git_version OUTPUT_VARIABLE)
IF(NOT ${result} EQUAL 0)
MESSAGE(FATAL_ERROR "Error running versioneer. Return code is: ${result}, error message is: ${error}")
ENDIF()
IF("${STRIPPED_VERSION}" EQUAL "0+unknown")
IF("${STRIPPED_VERSION}" STREQUAL "0+unknown")
MESSAGE(FATAL_ERROR "Unable to find git version information. Please build directly from a git repository (i.e. after git clone).")
ENDIF()
endfunction(get_git_version)

View File

@ -59,8 +59,8 @@ TEST_F(CryFsTest, CreatedRootdirIsLoadableAfterClosing) {
CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678);
}
CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678);
auto root = dev.Load(bf::path("/"));
dynamic_pointer_move<CryDir>(root.get()).get()->children();
auto rootDir = dev.LoadDir(bf::path("/"));
rootDir.value()->children();
}
TEST_F(CryFsTest, LoadingFilesystemDoesntModifyConfigFile) {

View File

@ -17,11 +17,10 @@ public:
static constexpr mode_t MODE_PUBLIC = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
unique_ref<CryNode> CreateFile(const bf::path &path) {
auto _parentDir = device().Load(path.parent_path()).value();
auto parentDir = dynamic_pointer_move<CryDir>(_parentDir).value();
auto parentDir = device().LoadDir(path.parent_path()).value();
parentDir->createAndOpenFile(path.filename().native(), MODE_PUBLIC, 0, 0);
auto createdFile = device().Load(path).value();
return dynamic_pointer_move<CryNode>(createdFile).value();
auto file = device().Load(path).value();
return dynamic_pointer_move<CryNode>(file).value();
}
unique_ref<CryNode> CreateDir(const bf::path &path) {

View File

@ -22,9 +22,13 @@ function(target_activate_cpp14 TARGET)
endif()
endif(COMPILER_HAS_CPP14_SUPPORT)
endif("${CMAKE_VERSION}" VERSION_GREATER "3.1")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Ideally, we'd like to use libc++ on linux as well, but:
# - http://stackoverflow.com/questions/37096062/get-a-basic-c-program-to-compile-using-clang-on-ubuntu-16
# - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=808086
# so only use it on Apple systems...
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND APPLE)
target_compile_options(${TARGET} PUBLIC -stdlib=libc++)
endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND APPLE)
endfunction(target_activate_cpp14)
#################################################

2
vendor/README vendored
View File

@ -1,6 +1,6 @@
This directory contains external projects, taken from the following locations:
scrypt: http://www.tarsnap.com/scrypt.html
googletest: https://github.com/google/googletest
googletest: https://github.com/google/googletest/tree/release-1.8.0
spdlog: https://github.com/gabime/spdlog/commit/0c7beb2e36008598cf80d0e8eb8635ac403febb9
- with own fix: https://github.com/cryfs/spdlog/commit/7b8d507615b8075fc6c8793a0965a32a708288c4
gitversion: https://github.com/smessmer/gitversion

View File

@ -4,7 +4,7 @@ if (BUILD_TESTING)
# When test cases are build, disable "make install", because this would also install gtest libraries.
macro(install)
endmacro(install)
add_subdirectory(gtest-1.7.0)
add_subdirectory(gtest-1.8.0)
project (googletest)
add_library(${PROJECT_NAME} dummy.cpp)

View File

@ -0,0 +1,2 @@
# Ignore CI build directory
build/

View File

@ -0,0 +1,46 @@
# Build matrix / environment variable are explained on:
# http://about.travis-ci.org/docs/user/build-configuration/
# This file can be validated on:
# http://lint.travis-ci.org/
install:
# /usr/bin/gcc is 4.6 always, but gcc-X.Y is available.
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
# /usr/bin/clang is 3.4, lets override with modern one.
- if [ "$CXX" = "clang++" ] && [ "$TRAVIS_OS_NAME" = "linux" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi
- echo ${PATH}
- echo ${CXX}
- ${CXX} --version
- ${CXX} -v
addons:
apt:
# List of whitelisted in travis packages for ubuntu-precise can be found here:
# https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
# List of whitelisted in travis apt-sources:
# https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
packages:
- gcc-4.9
- g++-4.9
- clang-3.7
- valgrind
os:
- linux
- osx
language: cpp
compiler:
- gcc
- clang
script: ./travis.sh
env:
matrix:
- GTEST_TARGET=googletest SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE
- GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE
- GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug CXX_FLAGS=-std=c++11 VERBOSE_MAKE=true VERBOSE
# - GTEST_TARGET=googletest SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
# - GTEST_TARGET=googlemock SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
notifications:
email: false
sudo: false

View File

@ -2,6 +2,7 @@
# Google Test #
[![Build Status](https://travis-ci.org/google/googletest.svg?branch=master)](https://travis-ci.org/google/googletest)
[![Build status](https://ci.appveyor.com/api/projects/status/4o38plt0xbo1ubc8/branch/master?svg=true)](https://ci.appveyor.com/project/BillyDonahue/googletest/branch/master)
Welcome to **Google Test**, Google's C++ test framework!
@ -105,7 +106,7 @@ package (as described below):
### Mac OS X Requirements ###
* Mac OS X v10.4 Tiger or newer
* XCode Developer Tools
* Xcode Developer Tools
### Requirements for Contributors ###

View File

@ -0,0 +1,71 @@
version: '{build}'
os: Visual Studio 2015
environment:
matrix:
- Toolset: v140
- Toolset: v120
- Toolset: v110
- Toolset: v100
platform:
- Win32
- x64
configuration:
# - Release
- Debug
build:
verbosity: minimal
artifacts:
- path: '_build/Testing/Temporary/*'
name: test_results
before_build:
- ps: |
Write-Output "Configuration: $env:CONFIGURATION"
Write-Output "Platform: $env:PLATFORM"
$generator = switch ($env:TOOLSET)
{
"v140" {"Visual Studio 14 2015"}
"v120" {"Visual Studio 12 2013"}
"v110" {"Visual Studio 11 2012"}
"v100" {"Visual Studio 10 2010"}
}
if ($env:PLATFORM -eq "x64")
{
$generator = "$generator Win64"
}
build_script:
- ps: |
if (($env:TOOLSET -eq "v100") -and ($env:PLATFORM -eq "x64"))
{
return
}
md _build -Force | Out-Null
cd _build
& cmake -G "$generator" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -Dgtest_build_tests=ON -Dgtest_build_samples=ON -Dgmock_build_tests=ON ..
if ($LastExitCode -ne 0) {
throw "Exec: $ErrorMessage"
}
& cmake --build . --config $env:CONFIGURATION
if ($LastExitCode -ne 0) {
throw "Exec: $ErrorMessage"
}
test_script:
- ps: |
if (($env:Toolset -eq "v100") -and ($env:PLATFORM -eq "x64"))
{
return
}
& ctest -C $env:CONFIGURATION --output-on-failure
if ($LastExitCode -ne 0) {
throw "Exec: $ErrorMessage"
}

View File

@ -2103,7 +2103,7 @@ For better readability, Google Mock also gives you:
* `WithArg<N>(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument.
As you may have realized, `InvokeWithoutArgs(...)` is just syntactic
sugar for `WithoutArgs(Inovke(...))`.
sugar for `WithoutArgs(Invoke(...))`.
Here are more tips:

View File

@ -44,7 +44,7 @@ We encourage you to use Google Mock as:
* a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators.
# Getting Started #
Using Google Mock is easy! Inside your C++ source file, just #include `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
# A Case for Mock Turtles #
Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface:

View File

@ -44,7 +44,7 @@ We encourage you to use Google Mock as:
* a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators.
# Getting Started #
Using Google Mock is easy! Inside your C++ source file, just #include `<gtest/gtest.h>` and `<gmock/gmock.h>`, and you are ready to go.
Using Google Mock is easy! Inside your C++ source file, just `#include` `<gtest/gtest.h>` and `<gmock/gmock.h>`, and you are ready to go.
# A Case for Mock Turtles #
Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface:

View File

@ -44,7 +44,7 @@ We encourage you to use Google Mock as:
* a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators.
# Getting Started #
Using Google Mock is easy! Inside your C++ source file, just #include `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
# A Case for Mock Turtles #
Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface:

View File

@ -44,7 +44,7 @@ We encourage you to use Google Mock as:
* a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators.
# Getting Started #
Using Google Mock is easy! Inside your C++ source file, just #include `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
# A Case for Mock Turtles #
Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface:

Some files were not shown because too many files have changed in this diff Show More