Add support for atime mount options (noatime, strictatime, relatime, atime, nodiratime). As before, relatime is the default.
This commit is contained in:
parent
ae09ff98aa
commit
8e617b1342
@ -3,6 +3,9 @@ Version 0.11.0 (unreleased)
|
||||
Build changes:
|
||||
* Switch to Conan package manager
|
||||
|
||||
New features:
|
||||
* Add support for atime mount options (noatime, strictatime, relatime, atime, nodiratime). As before, relatime is the default.
|
||||
|
||||
|
||||
Version 0.10.2
|
||||
---------------
|
||||
|
@ -244,8 +244,7 @@ namespace cryfs_cli {
|
||||
}
|
||||
};
|
||||
const bool missingBlockIsIntegrityViolation = config.configFile->config()->missingBlockIsIntegrityViolation();
|
||||
_device = optional<unique_ref<CryDevice>>(make_unique_ref<CryDevice>(std::move(config.configFile), std::move(blockStore), std::move(localStateDir), config.myClientId,
|
||||
options.allowIntegrityViolations(), missingBlockIsIntegrityViolation, std::move(onIntegrityViolation)));
|
||||
_device = optional<unique_ref<CryDevice>>(make_unique_ref<CryDevice>(std::move(config.configFile), std::move(blockStore), std::move(localStateDir), config.myClientId, options.allowIntegrityViolations(), missingBlockIsIntegrityViolation, std::move(onIntegrityViolation)));
|
||||
_sanityCheckFilesystem(_device->get());
|
||||
|
||||
auto initFilesystem = [&] (fspp::fuse::Fuse *fs){
|
||||
|
@ -81,12 +81,10 @@ ProgramOptions Parser::parse(const vector<string> &supportedCiphers) const {
|
||||
if (vm.count("missing-block-is-integrity-violation")) {
|
||||
missingBlockIsIntegrityViolation = vm["missing-block-is-integrity-violation"].as<bool>();
|
||||
}
|
||||
|
||||
if (vm.count("fuse-option")) {
|
||||
auto options = vm["fuse-option"].as<vector<string>>();
|
||||
for (const auto& option: options) {
|
||||
if (option == "noatime" || option == "atime") {
|
||||
LOG(WARN, "CryFS currently doesn't support noatime/atime flags. Using relatime behavior.");
|
||||
}
|
||||
fuseOptions.push_back("-o");
|
||||
fuseOptions.push_back(option);
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ ProgramOptions::ProgramOptions(bf::path baseDir, bf::path mountDir, optional<bf:
|
||||
_foreground(foreground),
|
||||
_allowFilesystemUpgrade(allowFilesystemUpgrade), _allowReplacedFilesystem(allowReplacedFilesystem), _allowIntegrityViolations(allowIntegrityViolations),
|
||||
_cipher(std::move(cipher)), _blocksizeBytes(std::move(blocksizeBytes)), _unmountAfterIdleMinutes(std::move(unmountAfterIdleMinutes)),
|
||||
_missingBlockIsIntegrityViolation(std::move(missingBlockIsIntegrityViolation)), _logFile(std::move(logFile)), _fuseOptions(std::move(fuseOptions)) {
|
||||
_missingBlockIsIntegrityViolation(std::move(missingBlockIsIntegrityViolation)), _logFile(std::move(logFile)),
|
||||
_fuseOptions(std::move(fuseOptions)) {
|
||||
if (!_mountDirIsDriveLetter) {
|
||||
_mountDir = bf::absolute(std::move(_mountDir));
|
||||
}
|
||||
|
@ -22,8 +22,10 @@
|
||||
#include "cryfs/impl/localstate/LocalStateDir.h"
|
||||
#include <cryfs/impl/CryfsException.h>
|
||||
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
//TODO Get rid of this in favor of exception hierarchy
|
||||
using fspp::fuse::FuseErrnoException;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "cryfs/impl/filesystem/parallelaccessfsblobstore/FileBlobRef.h"
|
||||
#include "cryfs/impl/filesystem/parallelaccessfsblobstore/SymlinkBlobRef.h"
|
||||
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
class CryDevice final: public fspp::Device {
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "CryFile.h"
|
||||
#include "CryOpenFile.h"
|
||||
#include <cpp-utils/system/time.h>
|
||||
#include "cryfs/impl/filesystem/fsblobstore/utils/TimestampUpdateBehavior.h"
|
||||
|
||||
//TODO Get rid of this in favor of exception hierarchy
|
||||
using fspp::fuse::FuseErrnoException;
|
||||
@ -72,7 +71,7 @@ vector<fspp::Dir::Entry> CryDir::children() {
|
||||
device()->callFsActionCallbacks();
|
||||
if (!isRootDir()) { // NOLINT (workaround https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82481 )
|
||||
//TODO Instead of doing nothing when we're the root directory, handle timestamps in the root dir correctly (and delete isRootDir() function)
|
||||
parent()->updateAccessTimestampForChild(blockId(), fsblobstore::TimestampUpdateBehavior::RELATIME);
|
||||
parent()->updateAccessTimestampForChild(blockId(), timestampUpdateBehavior());
|
||||
}
|
||||
vector<fspp::Dir::Entry> children;
|
||||
children.push_back(fspp::Dir::Entry(fspp::Dir::EntryType::DIR, "."));
|
||||
|
@ -70,6 +70,10 @@ optional<DirBlobRef*> CryNode::grandparent() {
|
||||
return _grandparent->get();
|
||||
}
|
||||
|
||||
fspp::TimestampUpdateBehavior CryNode::timestampUpdateBehavior() const {
|
||||
return _device->getContext().timestampUpdateBehavior();
|
||||
}
|
||||
|
||||
void CryNode::rename(const bf::path &to) {
|
||||
device()->callFsActionCallbacks();
|
||||
if (_parent == none) {
|
||||
|
@ -16,6 +16,7 @@ public:
|
||||
|
||||
// TODO grandparent is only needed to set the timestamps of the parent directory on rename and remove. Delete grandparent parameter once we store timestamps in the blob itself instead of in the directory listing.
|
||||
CryNode(CryDevice *device, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::BlockId &blockId);
|
||||
|
||||
void access(int mask) const override;
|
||||
stat_info stat() const override;
|
||||
void chmod(fspp::mode_t mode) override;
|
||||
@ -37,6 +38,7 @@ protected:
|
||||
std::shared_ptr<const parallelaccessfsblobstore::DirBlobRef> parent() const;
|
||||
std::shared_ptr<parallelaccessfsblobstore::DirBlobRef> parent();
|
||||
boost::optional<parallelaccessfsblobstore::DirBlobRef*> grandparent();
|
||||
fspp::TimestampUpdateBehavior timestampUpdateBehavior() const;
|
||||
|
||||
virtual fspp::Dir::EntryType getType() const = 0;
|
||||
|
||||
|
@ -43,7 +43,7 @@ void CryOpenFile::truncate(fspp::num_bytes_t size) const {
|
||||
|
||||
fspp::num_bytes_t CryOpenFile::read(void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) const {
|
||||
_device->callFsActionCallbacks();
|
||||
_parent->updateAccessTimestampForChild(_fileBlob->blockId(), fsblobstore::TimestampUpdateBehavior::RELATIME);
|
||||
_parent->updateAccessTimestampForChild(_fileBlob->blockId(), timestampUpdateBehavior());
|
||||
return _fileBlob->read(buf, offset, count);
|
||||
}
|
||||
|
||||
@ -64,4 +64,8 @@ void CryOpenFile::fdatasync() {
|
||||
_fileBlob->flush();
|
||||
}
|
||||
|
||||
fspp::TimestampUpdateBehavior CryOpenFile::timestampUpdateBehavior() const {
|
||||
return _device->getContext().timestampUpdateBehavior();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ public:
|
||||
void flush() override;
|
||||
void fsync() override;
|
||||
void fdatasync() override;
|
||||
fspp::TimestampUpdateBehavior timestampUpdateBehavior() const;
|
||||
|
||||
private:
|
||||
const CryDevice *_device;
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "CryDevice.h"
|
||||
#include "CrySymlink.h"
|
||||
#include "cryfs/impl/filesystem/parallelaccessfsblobstore/SymlinkBlobRef.h"
|
||||
#include "cryfs/impl/filesystem/fsblobstore/utils/TimestampUpdateBehavior.h"
|
||||
|
||||
//TODO Get rid of this in favor of exception hierarchy
|
||||
|
||||
@ -43,7 +42,7 @@ fspp::Dir::EntryType CrySymlink::getType() const {
|
||||
|
||||
bf::path CrySymlink::target() {
|
||||
device()->callFsActionCallbacks();
|
||||
parent()->updateAccessTimestampForChild(blockId(), fsblobstore::TimestampUpdateBehavior::RELATIME);
|
||||
parent()->updateAccessTimestampForChild(blockId(), timestampUpdateBehavior());
|
||||
auto blob = LoadBlob(); // NOLINT (workaround https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82481 )
|
||||
return blob->target();
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#include "FsBlobRef.h"
|
||||
#include "cryfs/impl/filesystem/fsblobstore/DirBlob.h"
|
||||
#include "cryfs/impl/filesystem/fsblobstore/utils/TimestampUpdateBehavior.h"
|
||||
#include <fspp/fs_interface/Node.h>
|
||||
#include <fspp/fs_interface/Context.h>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cachingfsblobstore {
|
||||
@ -62,7 +62,7 @@ public:
|
||||
return _base->statChildWithKnownSize(blockId, size);
|
||||
}
|
||||
|
||||
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, fsblobstore::TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, fspp::TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
return _base->updateAccessTimestampForChild(blockId, timestampUpdateBehavior);
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ fspp::Node::stat_info DirBlob::statChildWithKnownSize(const BlockId &blockId, fs
|
||||
return result;
|
||||
}
|
||||
|
||||
void DirBlob::updateAccessTimestampForChild(const BlockId &blockId, TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
void DirBlob::updateAccessTimestampForChild(const BlockId &blockId, fspp::TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
|
||||
if (_entries.updateAccessTimestampForChild(blockId, timestampUpdateBehavior)) {
|
||||
_changed = true;
|
||||
|
@ -61,7 +61,7 @@ namespace cryfs {
|
||||
|
||||
fspp::Node::stat_info statChildWithKnownSize(const blockstore::BlockId &blockId, fspp::num_bytes_t size) const;
|
||||
|
||||
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, TimestampUpdateBehavior timestampUpdateBehavior);
|
||||
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, fspp::TimestampUpdateBehavior timestampUpdateBehavior);
|
||||
|
||||
void updateModificationTimestampForChild(const blockstore::BlockId &blockId);
|
||||
|
||||
|
@ -228,22 +228,30 @@ void DirEntryList::setAccessTimes(const blockstore::BlockId &blockId, timespec l
|
||||
found->setLastModificationTime(lastModificationTime);
|
||||
}
|
||||
|
||||
bool DirEntryList::updateAccessTimestampForChild(const blockstore::BlockId &blockId, TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
ASSERT(timestampUpdateBehavior == TimestampUpdateBehavior::RELATIME, "Currently only relatime supported");
|
||||
bool DirEntryList::updateAccessTimestampForChild(const blockstore::BlockId &blockId, fspp::TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
auto found = _findById(blockId);
|
||||
|
||||
const timespec lastAccessTime = found->lastAccessTime();
|
||||
const timespec lastModificationTime = found->lastModificationTime();
|
||||
const timespec now = cpputils::time::now();
|
||||
const timespec yesterday {
|
||||
/*.tv_sec = */ now.tv_sec - 60*60*24,
|
||||
/*.tv_nsec = */ now.tv_nsec
|
||||
};
|
||||
bool changed = false;
|
||||
if (lastAccessTime < lastModificationTime || lastAccessTime < yesterday) {
|
||||
found->setLastAccessTime(now);
|
||||
changed = true;
|
||||
|
||||
switch (found->type()) {
|
||||
case fspp::Dir::EntryType::FILE:
|
||||
// fallthrough
|
||||
case fspp::Dir::EntryType::SYMLINK:
|
||||
if (timestampUpdateBehavior->shouldUpdateATimeOnFileRead(lastAccessTime, lastModificationTime, now)) {
|
||||
found->setLastAccessTime(now);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case fspp::Dir::EntryType::DIR:
|
||||
if (timestampUpdateBehavior->shouldUpdateATimeOnDirectoryRead(lastAccessTime, lastModificationTime, now)) {
|
||||
found->setLastAccessTime(now);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return changed;
|
||||
throw std::logic_error("Unhandled case");
|
||||
}
|
||||
|
||||
void DirEntryList::updateModificationTimestampForChild(const blockstore::BlockId &blockId) {
|
||||
|
@ -3,10 +3,10 @@
|
||||
#define MESSMER_CRYFS_FILESYSTEM_FSBLOBSTORE_UTILS_DIRENTRYLIST_H
|
||||
|
||||
#include <cpp-utils/data/Data.h>
|
||||
#include <fspp/fs_interface/Context.h>
|
||||
#include "DirEntry.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "TimestampUpdateBehavior.h"
|
||||
|
||||
//TODO Address elements by name instead of by blockId when accessing them. Who knows whether there is two hard links for the same blob.
|
||||
|
||||
@ -40,7 +40,7 @@ namespace cryfs {
|
||||
void setMode(const blockstore::BlockId &blockId, fspp::mode_t mode);
|
||||
bool setUidGid(const blockstore::BlockId &blockId, fspp::uid_t uid, fspp::gid_t gid);
|
||||
void setAccessTimes(const blockstore::BlockId &blockId, timespec lastAccessTime, timespec lastModificationTime);
|
||||
bool updateAccessTimestampForChild(const blockstore::BlockId &blockId, TimestampUpdateBehavior timestampUpdateBehavior);
|
||||
bool updateAccessTimestampForChild(const blockstore::BlockId &blockId, fspp::TimestampUpdateBehavior timestampUpdateBehavior);
|
||||
void updateModificationTimestampForChild(const blockstore::BlockId &blockId);
|
||||
|
||||
private:
|
||||
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CRYFS_TIMESTAMPUPDATEBEHAVIOR_H
|
||||
#define CRYFS_TIMESTAMPUPDATEBEHAVIOR_H
|
||||
|
||||
namespace cryfs {
|
||||
namespace fsblobstore {
|
||||
|
||||
enum class TimestampUpdateBehavior : uint8_t {
|
||||
// currently only relatime supported
|
||||
RELATIME
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include "FsBlobRef.h"
|
||||
#include "cryfs/impl/filesystem/cachingfsblobstore/DirBlobRef.h"
|
||||
#include "cryfs/impl/filesystem/fsblobstore/utils/TimestampUpdateBehavior.h"
|
||||
#include <fspp/fs_interface/Node.h>
|
||||
|
||||
namespace cryfs {
|
||||
@ -58,7 +57,7 @@ public:
|
||||
return _base->statChildWithKnownSize(blockId, size);
|
||||
}
|
||||
|
||||
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, fsblobstore::TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, fspp::TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
return _base->updateAccessTimestampForChild(blockId, timestampUpdateBehavior);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,9 @@ set(SOURCES
|
||||
Node.cpp
|
||||
OpenFile.cpp
|
||||
Symlink.cpp
|
||||
Types.cpp)
|
||||
Types.cpp
|
||||
Context.cpp
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||
|
||||
|
1
src/fspp/fs_interface/Context.cpp
Normal file
1
src/fspp/fs_interface/Context.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "Context.h"
|
128
src/fspp/fs_interface/Context.h
Normal file
128
src/fspp/fs_interface/Context.h
Normal file
@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_FSPP_FSINTERFACE_CONTEXT_H_
|
||||
#define MESSMER_FSPP_FSINTERFACE_CONTEXT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <cpp-utils/system/time.h>
|
||||
|
||||
namespace fspp {
|
||||
|
||||
namespace detail {
|
||||
class TimestampUpdateBehaviorBase {
|
||||
public:
|
||||
virtual bool shouldUpdateATimeOnFileRead(timespec oldATime, timespec oldMTime, timespec newATime) const = 0;
|
||||
virtual bool shouldUpdateATimeOnDirectoryRead(timespec oldATime, timespec oldMTime, timespec newATime) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
// Defines how atime timestamps of files and directories are accessed on read accesses
|
||||
// (e.g. atime, strictatime, relatime, nodiratime)
|
||||
using TimestampUpdateBehavior = std::shared_ptr<detail::TimestampUpdateBehaviorBase>;
|
||||
|
||||
// atime attribute (of both files and directories) is updated only during write access.
|
||||
inline TimestampUpdateBehavior noatime() {
|
||||
class BehaviorImpl final : public detail::TimestampUpdateBehaviorBase {
|
||||
public:
|
||||
bool shouldUpdateATimeOnFileRead(timespec /*oldATime*/, timespec /*oldMTime*/, timespec /*newATime*/) const override {
|
||||
return false;
|
||||
}
|
||||
bool shouldUpdateATimeOnDirectoryRead(timespec /*oldATime*/, timespec /*oldMTime*/, timespec /*newATime*/) const override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static std::shared_ptr<BehaviorImpl> singleton = std::make_shared<BehaviorImpl>();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
// This causes the atime attribute to update with every file access. (accessing file data, not just the metadata/attributes)
|
||||
inline TimestampUpdateBehavior strictatime() {
|
||||
class BehaviorImpl final : public detail::TimestampUpdateBehaviorBase {
|
||||
public:
|
||||
bool shouldUpdateATimeOnFileRead(timespec /*oldATime*/, timespec /*oldMTime*/, timespec /*newATime*/) const override {
|
||||
return true;
|
||||
}
|
||||
bool shouldUpdateATimeOnDirectoryRead(timespec /*oldATime*/, timespec /*oldMTime*/, timespec /*newATime*/) const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static std::shared_ptr<BehaviorImpl> singleton = std::make_shared<BehaviorImpl>();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
// This option causes the atime attribute to update only if the previous atime is older than mtime or ctime, or the previous atime is over 24 hours old.
|
||||
inline TimestampUpdateBehavior relatime() {
|
||||
// This option causes the atime attribute to update only if the previous atime is older than mtime or ctime, or the previous atime is over 24 hours old.
|
||||
class BehaviorImpl final : public detail::TimestampUpdateBehaviorBase {
|
||||
public:
|
||||
bool shouldUpdateATimeOnFileRead(timespec oldATime, timespec oldMTime, timespec newATime) const override {
|
||||
const timespec yesterday {
|
||||
/*.tv_sec = */ newATime.tv_sec - 60*60*24,
|
||||
/*.tv_nsec = */ newATime.tv_nsec
|
||||
};
|
||||
|
||||
return oldATime < oldMTime || oldATime < yesterday;
|
||||
}
|
||||
bool shouldUpdateATimeOnDirectoryRead(timespec oldATime, timespec oldMTime, timespec newATime) const override {
|
||||
return shouldUpdateATimeOnFileRead(oldATime, oldMTime, newATime);
|
||||
}
|
||||
};
|
||||
|
||||
static std::shared_ptr<BehaviorImpl> singleton = std::make_shared<BehaviorImpl>();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
// atime of directories is updated only during write access, can be combined with relatime. atime of files follows the relatime rules.
|
||||
inline TimestampUpdateBehavior nodiratime_relatime() {
|
||||
class BehaviorImpl final : public detail::TimestampUpdateBehaviorBase {
|
||||
public:
|
||||
bool shouldUpdateATimeOnFileRead(timespec oldATime, timespec oldMTime, timespec newATime) const override {
|
||||
return relatime()->shouldUpdateATimeOnFileRead(oldATime, oldMTime, newATime);
|
||||
}
|
||||
bool shouldUpdateATimeOnDirectoryRead(timespec /*oldATime*/, timespec /*oldMTime*/, timespec /*newATime*/) const override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static std::shared_ptr<BehaviorImpl> singleton = std::make_shared<BehaviorImpl>();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
// atime of directories is updated only during write access, can be combined with relatime. atime of files follows the strictatime rules.
|
||||
inline TimestampUpdateBehavior nodiratime_strictatime() {
|
||||
class BehaviorImpl final : public detail::TimestampUpdateBehaviorBase {
|
||||
public:
|
||||
bool shouldUpdateATimeOnFileRead(timespec oldATime, timespec oldMTime, timespec newATime) const override {
|
||||
return strictatime()->shouldUpdateATimeOnFileRead(oldATime, oldMTime, newATime);
|
||||
}
|
||||
bool shouldUpdateATimeOnDirectoryRead(timespec /*oldATime*/, timespec /*oldMTime*/, timespec /*newATime*/) const override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static std::shared_ptr<BehaviorImpl> singleton = std::make_shared<BehaviorImpl>();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
class Context final {
|
||||
public:
|
||||
explicit Context(TimestampUpdateBehavior timestampUpdateBehavior)
|
||||
: _timestampUpdateBehavior(std::move(timestampUpdateBehavior)) {}
|
||||
|
||||
const TimestampUpdateBehavior& timestampUpdateBehavior() const {
|
||||
return _timestampUpdateBehavior;
|
||||
}
|
||||
|
||||
void setTimestampUpdateBehavior(TimestampUpdateBehavior value) {
|
||||
_timestampUpdateBehavior = std::move(value);
|
||||
}
|
||||
|
||||
private:
|
||||
TimestampUpdateBehavior _timestampUpdateBehavior;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -5,6 +5,8 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <cpp-utils/pointer/unique_ref.h>
|
||||
#include "Types.h"
|
||||
#include "Context.h"
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace fspp {
|
||||
class Node;
|
||||
@ -28,6 +30,19 @@ public:
|
||||
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;
|
||||
|
||||
const Context& getContext() const {
|
||||
ASSERT(_context != boost::none, "Tried to call getContext() but file system isn't running yet.");
|
||||
return *_context;
|
||||
}
|
||||
|
||||
// called by fspp system on file system init. Don't call this manually.
|
||||
// TODO Is there a better way to do this?
|
||||
void setContext(Context&& context) {
|
||||
_context = std::move(context);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::optional<Context> _context;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -8,30 +8,36 @@ template<class ConcreteFileSystemTestFixture>
|
||||
class FsppDeviceTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
void Test_Load_While_Loaded() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
auto operation = [this] () {
|
||||
this->device->Load("/mynode");
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
return [this] {
|
||||
this->device->Load("/mynode");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Load_While_Not_Loaded() {
|
||||
fspp::Node::stat_info oldStat{};
|
||||
{
|
||||
auto node = this->CreateNode("/mynode");
|
||||
oldStat = this->stat(*node);
|
||||
this->ensureNodeTimestampsAreOld(oldStat);
|
||||
}
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
fspp::Node::stat_info oldStat{};
|
||||
{
|
||||
auto node = this->CreateNode("/mynode");
|
||||
oldStat = this->stat(*node);
|
||||
this->ensureNodeTimestampsAreOld(oldStat);
|
||||
}
|
||||
|
||||
this->device->Load("/myfile");
|
||||
this->device->Load("/myfile");
|
||||
|
||||
auto node = this->device->Load("/mynode");
|
||||
auto node = this->device->Load("/mynode");
|
||||
|
||||
//Test that timestamps didn't change
|
||||
fspp::Node::stat_info newStat = this->stat(*node.value());
|
||||
EXPECT_EQ(oldStat.atime, newStat.atime);
|
||||
EXPECT_EQ(oldStat.mtime, newStat.mtime);
|
||||
EXPECT_EQ(oldStat.ctime, newStat.ctime);
|
||||
//Test that timestamps didn't change
|
||||
fspp::Node::stat_info newStat = this->stat(*node.value());
|
||||
EXPECT_EQ(oldStat.atime, newStat.atime);
|
||||
EXPECT_EQ(oldStat.mtime, newStat.mtime);
|
||||
EXPECT_EQ(oldStat.ctime, newStat.ctime);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,225 +11,501 @@ public:
|
||||
TYPED_TEST_SUITE_P(FsppDirTest_Timestamps);
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto operation = [&dir] () {
|
||||
dir->createAndOpenFile("childname", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->createAndOpenFile("childname", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
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
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_inRootDir) {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto operation = [&dir] () {
|
||||
dir->createAndOpenFile("childname", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->createAndOpenFile("childname", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_TimestampsOfCreatedFile) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
dir->createAndOpenFile("childname", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
timespec upperBound = cpputils::time::now();
|
||||
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);
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
dir->createAndOpenFile("childname", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
timespec upperBound = cpputils::time::now();
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createDir) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto operation = [&dir] () {
|
||||
dir->createDir("childname", fspp::mode_t().addDirFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->createDir("childname", fspp::mode_t().addDirFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
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
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createDir_inRootDir) {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto operation = [&dir] () {
|
||||
dir->createDir("childname", fspp::mode_t().addDirFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->createDir("childname", fspp::mode_t().addDirFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createDir_TimestampsOfCreatedDir) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
dir->createDir("childname", fspp::mode_t().addDirFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
timespec upperBound = cpputils::time::now();
|
||||
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);
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
dir->createDir("childname", fspp::mode_t().addDirFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
timespec upperBound = cpputils::time::now();
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto operation = [&dir] () {
|
||||
dir->createSymlink("childname", "/target", fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->createSymlink("childname", "/target", fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
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
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_inRootDir) {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto operation = [&dir] () {
|
||||
dir->createSymlink("childname", "/target", fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->createSymlink("childname", "/target", fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_TimestampsOfCreatedSymlink) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
dir->createSymlink("childname", "/target", fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
timespec upperBound = cpputils::time::now();
|
||||
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);
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
dir->createSymlink("childname", "/target", fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
timespec upperBound = cpputils::time::now();
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, children_empty) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
this->setModificationTimestampLaterThanAccessTimestamp("/mydir"); // to make sure that even in relatime behavior, the read access below changes the access timestamp
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeOlderThanMtime_children_empty) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
this->setAtimeOlderThanMtime("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtime_children_empty) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
this->setAtimeNewerThanMtime("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtimeButBeforeYesterday_children_empty) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
this->setAtimeNewerThanMtimeButBeforeYesterday("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, children_empty_inRootDir) {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeOlderThanMtime_children_empty_inRootDir) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
this->setAtimeOlderThanMtime("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty) {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtime_children_empty_inRootDir) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
this->setAtimeNewerThanMtime("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtimeButBeforeYesterday_children_empty_inRootDir) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
this->setAtimeNewerThanMtimeButBeforeYesterday("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeOlderThanMtime_children_nonempty) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
this->setAtimeOlderThanMtime("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtime_children_nonempty) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
this->setAtimeNewerThanMtime("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtimeButBeforeYesterday_children_nonempty) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
this->setAtimeNewerThanMtimeButBeforeYesterday("/mydir");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty_inRootDir) {
|
||||
auto dir = this->LoadDir("/");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeOlderThanMtime_children_nonempty_inRootDir) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
this->setAtimeOlderThanMtime("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtime_children_nonempty_inRootDir) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
this->setAtimeNewerThanMtime("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, givenAtimeNewerThanMtimeButBeforeYesterday_children_nonempty_inRootDir) {
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
dir->createAndOpenFile("filename", fspp::mode_t().addFileFlag(), fspp::uid_t(1000), fspp::gid_t(1000));
|
||||
this->setAtimeNewerThanMtimeButBeforeYesterday("/");
|
||||
return [dir = std::move(dir)] {
|
||||
dir->children();
|
||||
};
|
||||
};
|
||||
this->testBuilder().withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppDirTest_Timestamps_Entries: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
|
||||
void Test_deleteChild() {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto child = this->CreateNode("/mydir/childname");
|
||||
auto operation = [&child]() {
|
||||
child->remove();
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto child = this->CreateNode("/mydir/childname");
|
||||
return [child = std::move(child)] {
|
||||
child->remove();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
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
|
||||
void Test_deleteChild_inRootDir() {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto child = this->CreateNode("/childname");
|
||||
auto operation = [&child] () {
|
||||
child->remove();
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto child = this->CreateNode("/mydir/childname");
|
||||
return [child = std::move(child)] {
|
||||
child->remove();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
void Test_renameChild() {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto child = this->CreateNode("/mydir/childname");
|
||||
auto operation = [&child]() {
|
||||
child->rename("/mydir/mychild");
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto child = this->CreateNode("/mydir/childname");
|
||||
return [child = std::move(child)] {
|
||||
child->rename("/mydir/mychild");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&]{
|
||||
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
|
||||
void Test_renameChild_inRootDir() {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto child = this->CreateNode("/childname");
|
||||
auto operation = [&child] () {
|
||||
child->rename("/mydir/mychild");
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto child = this->CreateNode("/childname");
|
||||
return [child = std::move(child)] {
|
||||
child->rename("/mychild");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withAnyAtimeConfig([&]{
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
void Test_moveChildIn() {
|
||||
auto sourceDir = this->CreateDir("/sourcedir");
|
||||
auto child = this->CreateNode("/sourcedir/childname");
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto operation = [&child]() {
|
||||
child->rename("/mydir/mychild");
|
||||
auto operation = [this] {
|
||||
auto sourceDir = this->CreateDir("/sourcedir");
|
||||
auto child = this->CreateNode("/sourcedir/childname");
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
return [child = std::move(child)] {
|
||||
child->rename("/mydir/mychild");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
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
|
||||
void Test_moveChildIn_inRootDir() {
|
||||
auto sourceDir = this->CreateDir("/sourcedir");
|
||||
auto child = this->CreateNode("/sourcedir/childname");
|
||||
auto dir = this->LoadDir("/");
|
||||
auto operation = [&child] () {
|
||||
child->rename("/mychild");
|
||||
auto operation = [this] {
|
||||
auto sourceDir = this->CreateDir("/sourcedir");
|
||||
auto child = this->CreateNode("/sourcedir/childname");
|
||||
auto dir = this->LoadDir("/");
|
||||
return [child = std::move(child)] {
|
||||
child->rename("/mychild");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
void Test_moveChildOut() {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto child = this->CreateNode("/mydir/childname");
|
||||
this->CreateDir("/targetdir");
|
||||
auto operation = [&child]() {
|
||||
child->rename("/targetdir/mychild");
|
||||
auto operation = [this] {
|
||||
auto dir = this->CreateDir("/mydir");
|
||||
auto child = this->CreateNode("/mydir/childname");
|
||||
this->CreateDir("/targetdir");
|
||||
return [child = std::move(child)] {
|
||||
child->rename("/targetdir/mychild");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
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
|
||||
void Test_moveChildOut_inRootDir() {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto child = this->CreateNode("/childname");
|
||||
this->CreateDir("/targetdir");
|
||||
auto operation = [&child] () {
|
||||
child->rename("/targetdir/mychild");
|
||||
auto operation = [this] {
|
||||
auto dir = this->LoadDir("/");
|
||||
auto child = this->CreateNode("/childname");
|
||||
this->CreateDir("/targetdir");
|
||||
return [child = std::move(child)] {
|
||||
child->rename("/targetdir/mychild");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(FsppDirTest_Timestamps,
|
||||
@ -239,8 +515,12 @@ REGISTER_TYPED_TEST_SUITE_P(FsppDirTest_Timestamps,
|
||||
createDir_TimestampsOfCreatedDir,
|
||||
createSymlink,
|
||||
createSymlink_TimestampsOfCreatedSymlink,
|
||||
children_empty,
|
||||
children_nonempty
|
||||
givenAtimeNewerThanMtime_children_empty,
|
||||
givenAtimeOlderThanMtime_children_empty,
|
||||
givenAtimeNewerThanMtimeButBeforeYesterday_children_empty,
|
||||
givenAtimeNewerThanMtime_children_nonempty,
|
||||
givenAtimeOlderThanMtime_children_nonempty,
|
||||
givenAtimeNewerThanMtimeButBeforeYesterday_children_nonempty
|
||||
);
|
||||
|
||||
REGISTER_NODE_TEST_SUITE(FsppDirTest_Timestamps_Entries,
|
||||
|
@ -17,75 +17,111 @@ public:
|
||||
TYPED_TEST_SUITE_P(FsppFileTest_Timestamps);
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, open_nomode) {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
auto operation = [&file] () {
|
||||
file->open(fspp::openflags_t(0));
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
return [file = std::move(file)] {
|
||||
file->open(fspp::openflags_t(0));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, open_rdonly) {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
auto operation = [&file] () {
|
||||
file->open(fspp::openflags_t::RDONLY());
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
return [file = std::move(file)] {
|
||||
file->open(fspp::openflags_t::RDONLY());
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, open_wronly) {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
auto operation = [&file] () {
|
||||
file->open(fspp::openflags_t::WRONLY());
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
return [file = std::move(file)] {
|
||||
file->open(fspp::openflags_t::WRONLY());
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, open_rdwr) {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
auto operation = [&file] () {
|
||||
file->open(fspp::openflags_t::RDWR());
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
return [file = std::move(file)] {
|
||||
file->open(fspp::openflags_t::RDWR());
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_empty) {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
auto operation = [&file] () {
|
||||
file->truncate(fspp::num_bytes_t(0));
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
return [file = std::move(file)] {
|
||||
file->truncate(fspp::num_bytes_t(0));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_nonempty) {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
auto operation = [&file] () {
|
||||
file->truncate(fspp::num_bytes_t(10));
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
return [file = std::move(file)] {
|
||||
file->truncate(fspp::num_bytes_t(10));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_empty) {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&file] () {
|
||||
file->truncate(fspp::num_bytes_t(0));
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
return [file = std::move(file)] {
|
||||
file->truncate(fspp::num_bytes_t(0));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_shrink) {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&file] () {
|
||||
file->truncate(fspp::num_bytes_t(5));
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
return [file = std::move(file)] {
|
||||
file->truncate(fspp::num_bytes_t(5));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_grow) {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&file] () {
|
||||
file->truncate(fspp::num_bytes_t(20));
|
||||
auto operation = [this] {
|
||||
auto file = this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
return [file = std::move(file)] {
|
||||
file->truncate(fspp::num_bytes_t(20));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(FsppFileTest_Timestamps,
|
||||
|
@ -13,339 +13,361 @@ class FsppNodeTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture
|
||||
public:
|
||||
|
||||
void Test_Create() {
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
auto node = this->CreateNode("/mynode");
|
||||
timespec upperBound = cpputils::time::now();
|
||||
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
|
||||
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
|
||||
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *node);
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
timespec lowerBound = cpputils::time::now();
|
||||
auto node = this->CreateNode("/mynode");
|
||||
timespec upperBound = cpputils::time::now();
|
||||
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() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
auto operation = [&node] () {
|
||||
node->stat();
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
return [node = std::move(node)] {
|
||||
node->stat();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Chmod() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
fspp::mode_t mode = this->stat(*node).mode;
|
||||
auto operation = [&node, mode] () {
|
||||
node->chmod(mode);
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
fspp::mode_t mode = this->stat(*node).mode;
|
||||
return [mode, node = std::move(node)] {
|
||||
node->chmod(mode);
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Chown() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
fspp::uid_t uid = this->stat(*node).uid;
|
||||
fspp::gid_t gid = this->stat(*node).gid;
|
||||
auto operation = [&node, uid, gid] () {
|
||||
node->chown(uid, gid);
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
fspp::uid_t uid = this->stat(*node).uid;
|
||||
fspp::gid_t gid = this->stat(*node).gid;
|
||||
return [uid, gid, node = std::move(node)] {
|
||||
node->chown(uid, gid);
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Access() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
auto operation = [&node] () {
|
||||
node->access(0);
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
return [node = std::move(node)] {
|
||||
node->access(0);
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Error_TargetParentDirDoesntExist() {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/notexistingdir/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOENT, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
return [node = std::move(node)] {
|
||||
try {
|
||||
node->rename("/notexistingdir/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOENT, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Error_TargetParentDirIsFile() {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
this->CreateFile("/somefile");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/somefile/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
this->CreateFile("/somefile");
|
||||
return [node = std::move(node)] {
|
||||
try {
|
||||
node->rename("/somefile/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
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->Load("/");
|
||||
auto operation = [&root] () {
|
||||
try {
|
||||
root->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect throws
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EBUSY, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
auto operation = [this] {
|
||||
auto root = this->Load("/");
|
||||
return [root = std::move(root)] {
|
||||
try {
|
||||
root->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect throws
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EBUSY, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
*/
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
void Test_Rename_InRoot() {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/newname");
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/newname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_InNested() {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/mydir/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir/newname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/mydir/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/mydir/newname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/mydir/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/mydir/newname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_RootToNested_SameName() {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir/oldname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/mydir/oldname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/oldname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_RootToNested_NewName() {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir/newname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/mydir/newname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/newname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToRoot_SameName() {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/mydir/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/oldname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/mydir/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/oldname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/oldname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToRoot_NewName() {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/mydir/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/newname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->CreateNode("/mydir/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/newname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/newname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToNested_SameName() {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
auto node = this->CreateNode("/mydir1/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir2/oldname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
auto node = this->CreateNode("/mydir1/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/mydir2/oldname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/oldname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToNested_NewName() {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
auto node = this->CreateNode("/mydir1/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir2/newname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
auto node = this->CreateNode("/mydir1/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/mydir2/newname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_ToItself() {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/oldname");
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/oldname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/oldname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_InSameDir() {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
this->CreateNode("/newname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/newname");
|
||||
auto operation = [this] {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
this->CreateNode("/newname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/newname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_InDifferentDir() {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
this->CreateNode("/mydir2/newname");
|
||||
auto node = this->CreateNode("/mydir1/oldname");
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir2/newname");
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
this->CreateNode("/mydir2/newname");
|
||||
auto node = this->CreateNode("/mydir1/oldname");
|
||||
return [node = std::move(node)] {
|
||||
node->rename("/mydir2/newname");
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation(), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_DirWithFile_InSameDir() {
|
||||
this->CreateFile("/oldname");
|
||||
this->CreateDir("/newname");
|
||||
auto node = this->Load("/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EISDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
auto operation = [this] {
|
||||
this->CreateFile("/oldname");
|
||||
this->CreateDir("/newname");
|
||||
auto node = this->Load("/oldname");
|
||||
return [node = std::move(node)] {
|
||||
try {
|
||||
node->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EISDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_DirWithFile_InDifferentDir() {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
this->CreateFile("/mydir1/oldname");
|
||||
this->CreateDir("/mydir2/newname");
|
||||
auto node = this->Load("/mydir1/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/mydir2/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EISDIR, e.getErrno());//Rename fails, everything is ok.
|
||||
}
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
this->CreateFile("/mydir1/oldname");
|
||||
this->CreateDir("/mydir2/newname");
|
||||
auto node = this->Load("/mydir1/oldname");
|
||||
return [node = std::move(node)] {
|
||||
try {
|
||||
node->rename("/mydir2/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EISDIR, e.getErrno());//Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_FileWithDir_InSameDir() {
|
||||
this->CreateDir("/oldname");
|
||||
this->CreateFile("/newname");
|
||||
auto node = this->Load("/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/oldname");
|
||||
this->CreateFile("/newname");
|
||||
auto node = this->Load("/oldname");
|
||||
return [node = std::move(node)] {
|
||||
try {
|
||||
node->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_FileWithDir_InDifferentDir() {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
this->CreateDir("/mydir1/oldname");
|
||||
this->CreateFile("/mydir2/newname");
|
||||
auto node = this->Load("/mydir1/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/mydir2/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
auto operation = [this] {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
this->CreateDir("/mydir1/oldname");
|
||||
this->CreateFile("/mydir2/newname");
|
||||
auto node = this->Load("/mydir1/oldname");
|
||||
return [node = std::move(node)] {
|
||||
try {
|
||||
node->rename("/mydir2/newname");
|
||||
EXPECT_TRUE(false); // expect rename to fail
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Utimens() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
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("/mynode", operation, {
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
timespec atime = this->xSecondsAgo(100);
|
||||
timespec mtime = this->xSecondsAgo(200);
|
||||
auto operation = [atime, mtime, &node] {
|
||||
node->utimens(atime, mtime);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
EXPECT_EQ(atime, this->stat(*node).atime);
|
||||
EXPECT_EQ(mtime, this->stat(*node).mtime);
|
||||
});
|
||||
EXPECT_EQ(atime, this->stat(*node).atime);
|
||||
EXPECT_EQ(mtime, this->stat(*node).mtime);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,120 +14,343 @@ public:
|
||||
auto file = this->CreateFile(path);
|
||||
file->truncate(size);
|
||||
auto openFile = file->open(fspp::openflags_t::RDWR());
|
||||
assert(this->stat(*openFile).size == size);
|
||||
assert(this->stat(*this->Load(path)).size == size);
|
||||
ASSERT(this->stat(*openFile).size == size, "");
|
||||
ASSERT(this->stat(*this->Load(path)).size == size, "");
|
||||
return openFile;
|
||||
}
|
||||
void CreateFileWithSize(const boost::filesystem::path &path, fspp::num_bytes_t size) {
|
||||
auto file = this->CreateFile(path);
|
||||
file->truncate(size);
|
||||
}
|
||||
cpputils::unique_ref<fspp::OpenFile> OpenFile(const boost::filesystem::path &path, fspp::num_bytes_t size) {
|
||||
auto file = this->LoadFile(path);
|
||||
auto openFile = file->open(fspp::openflags_t::RDWR());
|
||||
ASSERT(this->stat(*openFile).size == size, "");
|
||||
ASSERT(this->stat(*this->Load(path)).size == size, "");
|
||||
return openFile;
|
||||
}
|
||||
};
|
||||
TYPED_TEST_SUITE_P(FsppOpenFileTest_Timestamps);
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, stat) {
|
||||
auto openFile = this->CreateAndOpenFile("/mynode");
|
||||
auto operation = [&openFile] () {
|
||||
openFile->stat();
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->stat();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFile("/mynode");
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, truncate_empty_to_empty) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->truncate(fspp::num_bytes_t(0));
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->truncate(fspp::num_bytes_t(0));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, truncate_empty_to_nonempty) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->truncate(fspp::num_bytes_t(10));
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->truncate(fspp::num_bytes_t(10));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, truncate_nonempty_to_empty) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->truncate(fspp::num_bytes_t(0));
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->truncate(fspp::num_bytes_t(0));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, truncate_nonempty_to_nonempty_shrink) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->truncate(fspp::num_bytes_t(5));
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->truncate(fspp::num_bytes_t(5));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, truncate_nonempty_to_nonempty_grow) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->truncate(fspp::num_bytes_t(20));
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->truncate(fspp::num_bytes_t(20));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, read_inbounds) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&openFile] () {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(0));
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, givenAtimeNewerThanMtimeButBeforeYesterday_read_inbounds) {
|
||||
auto operation = [this] () {
|
||||
this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->setAtimeNewerThanMtimeButBeforeYesterday("/myfile");
|
||||
auto openFile = this->OpenFile("/myfile", fspp::num_bytes_t(10));
|
||||
auto* openFilePtr = openFile.get();
|
||||
|
||||
return std::make_pair(openFilePtr, [openFile = std::move(openFile)] {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(0));
|
||||
});
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, read_outofbounds) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
auto operation = [&openFile] () {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(2));
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, givenAtimeNewerThanMtime_read_inbounds) {
|
||||
auto operation = [this] () {
|
||||
this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->setAtimeNewerThanMtime("/myfile");
|
||||
auto openFile = this->OpenFile("/myfile", fspp::num_bytes_t(10));
|
||||
auto* openFilePtr = openFile.get();
|
||||
|
||||
return std::make_pair(openFilePtr, [openFile = std::move(openFile)] {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(0));
|
||||
});
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, givenAtimeOlderThanMtime_read_inbounds) {
|
||||
auto operation = [this] () {
|
||||
this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->setAtimeOlderThanMtime("/myfile");
|
||||
auto openFile = this->OpenFile("/myfile", fspp::num_bytes_t(10));
|
||||
auto* openFilePtr = openFile.get();
|
||||
|
||||
return std::make_pair(openFilePtr, [openFile = std::move(openFile)] {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(0));
|
||||
});
|
||||
};
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, givenAtimeNewerThanMtimeButBeforeYesterday_read_outofbounds) {
|
||||
auto operation = [this] () {
|
||||
this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->setAtimeNewerThanMtimeButBeforeYesterday("/myfile");
|
||||
auto openFile = this->OpenFile("/myfile", fspp::num_bytes_t(10));
|
||||
auto* openFilePtr = openFile.get();
|
||||
|
||||
return std::make_pair(openFilePtr, [openFile = std::move(openFile)] {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(2));
|
||||
});
|
||||
};
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, givenAtimeNewerThanMtime_read_outofbounds) {
|
||||
auto operation = [this] () {
|
||||
this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->setAtimeNewerThanMtime("/myfile");
|
||||
auto openFile = this->OpenFile("/myfile", fspp::num_bytes_t(10));
|
||||
auto* openFilePtr = openFile.get();
|
||||
|
||||
return std::make_pair(openFilePtr, [openFile = std::move(openFile)] {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(2));
|
||||
});
|
||||
};
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, givenAtimeOlderThanMtime_read_outofbounds) {
|
||||
auto operation = [this] () {
|
||||
this->CreateFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->setAtimeOlderThanMtime("/myfile");
|
||||
auto openFile = this->OpenFile("/myfile", fspp::num_bytes_t(10));
|
||||
auto* openFilePtr = openFile.get();
|
||||
|
||||
return std::make_pair(openFilePtr, [openFile = std::move(openFile)] {
|
||||
std::array<char, 5> buffer{};
|
||||
openFile->read(buffer.data(), fspp::num_bytes_t(5), fspp::num_bytes_t(2));
|
||||
});
|
||||
};
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
auto op = operation();
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*op.first, std::move(op.second), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, write_inbounds) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, write_outofbounds) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(2));
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
return [openFile] {
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(2));
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(0));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, flush) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->flush();
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
return [openFile] {
|
||||
openFile->flush();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, fsync) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->fsync();
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
return [openFile] {
|
||||
openFile->fsync();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest_Timestamps, fdatasync) {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
auto operation = [&openFile] () {
|
||||
openFile->fdatasync();
|
||||
auto operation = [] (fspp::OpenFile* openFile){
|
||||
openFile->write("content", fspp::num_bytes_t(7), fspp::num_bytes_t(0));
|
||||
return [openFile] {
|
||||
openFile->fdatasync();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->testBuilder().withAnyAtimeConfig([&] {
|
||||
auto openFile = this->CreateAndOpenFileWithSize("/myfile", fspp::num_bytes_t(10));
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation(openFile.get()), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
});
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(FsppOpenFileTest_Timestamps,
|
||||
@ -137,8 +360,12 @@ REGISTER_TYPED_TEST_SUITE_P(FsppOpenFileTest_Timestamps,
|
||||
truncate_nonempty_to_empty,
|
||||
truncate_nonempty_to_nonempty_shrink,
|
||||
truncate_nonempty_to_nonempty_grow,
|
||||
read_inbounds,
|
||||
read_outofbounds,
|
||||
givenAtimeNewerThanMtimeButBeforeYesterday_read_inbounds,
|
||||
givenAtimeNewerThanMtime_read_inbounds,
|
||||
givenAtimeOlderThanMtime_read_inbounds,
|
||||
givenAtimeNewerThanMtimeButBeforeYesterday_read_outofbounds,
|
||||
givenAtimeNewerThanMtime_read_outofbounds,
|
||||
givenAtimeOlderThanMtime_read_outofbounds,
|
||||
write_inbounds,
|
||||
write_outofbounds,
|
||||
flush,
|
||||
|
@ -10,17 +10,76 @@ public:
|
||||
};
|
||||
TYPED_TEST_SUITE_P(FsppSymlinkTest_Timestamps);
|
||||
|
||||
TYPED_TEST_P(FsppSymlinkTest_Timestamps, target) {
|
||||
auto symlink = this->CreateSymlink("/mysymlink");
|
||||
this->setModificationTimestampLaterThanAccessTimestamp("/mysymlink"); // to make sure that even in relatime behavior, the read access below changes the access timestamp
|
||||
auto operation = [&symlink] () {
|
||||
symlink->target();
|
||||
TYPED_TEST_P(FsppSymlinkTest_Timestamps, givenAtimeNewerThanMtimeButBeforeYesterday_target) {
|
||||
auto operation = [this] {
|
||||
auto symlink = this->CreateSymlink("/mysymlink");
|
||||
this->setAtimeNewerThanMtimeButBeforeYesterday("/mysymlink");
|
||||
return [symlink = std::move(symlink)] {
|
||||
symlink->target();
|
||||
};
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppSymlinkTest_Timestamps, givenAtimeOlderThanMtime_target) {
|
||||
auto operation = [this] {
|
||||
auto symlink = this->CreateSymlink("/mysymlink");
|
||||
this->setAtimeOlderThanMtime("/mysymlink");
|
||||
return [symlink = std::move(symlink)] {
|
||||
symlink->target();
|
||||
};
|
||||
};
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppSymlinkTest_Timestamps, givenAtimeNewerThanMtime_target) {
|
||||
auto operation = [this] {
|
||||
auto symlink = this->CreateSymlink("/mysymlink");
|
||||
this->setAtimeNewerThanMtime("/mysymlink");
|
||||
return [symlink = std::move(symlink)] {
|
||||
symlink->target();
|
||||
};
|
||||
};
|
||||
this->testBuilder()
|
||||
.withNoatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}).withRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeRelatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}).withNodiratimeStrictatime([&] {
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation(), {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
});
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(FsppSymlinkTest_Timestamps,
|
||||
target
|
||||
givenAtimeNewerThanMtimeButBeforeYesterday_target,
|
||||
givenAtimeNewerThanMtime_target,
|
||||
givenAtimeOlderThanMtime_target
|
||||
);
|
||||
|
||||
#endif
|
||||
|
@ -30,10 +30,20 @@ public:
|
||||
"Given test fixture for instantiating the (type parameterized) FileSystemTest must inherit from FileSystemTestFixture"
|
||||
);
|
||||
|
||||
FileSystemTest(): fixture(), device(fixture.createDevice()) {}
|
||||
FileSystemTest(): fixture(nullptr), device(nullptr) {
|
||||
resetFilesystem(fspp::Context{fspp::relatime()});
|
||||
}
|
||||
|
||||
ConcreteFileSystemTestFixture fixture;
|
||||
cpputils::unique_ref<fspp::Device> device;
|
||||
void resetFilesystem(fspp::Context&& context) {
|
||||
device = nullptr;
|
||||
fixture = nullptr;
|
||||
fixture = std::make_unique<ConcreteFileSystemTestFixture>();
|
||||
device = fixture->createDevice();
|
||||
device->setContext(std::move(context));
|
||||
}
|
||||
|
||||
std::unique_ptr<ConcreteFileSystemTestFixture> fixture;
|
||||
std::unique_ptr<fspp::Device> device;
|
||||
|
||||
static constexpr fspp::mode_t MODE_PUBLIC = fspp::mode_t()
|
||||
.addUserReadFlag().addUserWriteFlag().addUserExecFlag()
|
||||
@ -91,15 +101,41 @@ public:
|
||||
EXPECT_NE(nullptr, dynamic_cast<const fspp::Symlink*>(node.get()));
|
||||
}
|
||||
|
||||
void setModificationTimestampLaterThanAccessTimestamp(const boost::filesystem::path& path) {
|
||||
void setAtimeOlderThanMtime(const boost::filesystem::path& path) {
|
||||
auto node = device->Load(path).value();
|
||||
auto st = node->stat();
|
||||
st.mtime.tv_nsec = st.mtime.tv_nsec + 1;
|
||||
st.atime.tv_nsec = st.mtime.tv_nsec - 1;
|
||||
node->utimens(
|
||||
st.atime,
|
||||
st.mtime
|
||||
);
|
||||
}
|
||||
|
||||
void setAtimeNewerThanMtime(const boost::filesystem::path& path) {
|
||||
auto node = device->Load(path).value();
|
||||
auto st = node->stat();
|
||||
st.atime.tv_nsec = st.mtime.tv_nsec + 1;
|
||||
node->utimens(
|
||||
st.atime,
|
||||
st.mtime
|
||||
);
|
||||
}
|
||||
|
||||
void setAtimeNewerThanMtimeButBeforeYesterday(const boost::filesystem::path& path) {
|
||||
auto node = device->Load(path).value();
|
||||
auto st = node->stat();
|
||||
const timespec now = cpputils::time::now();
|
||||
const timespec before_yesterday {
|
||||
/*.tv_sec = */ now.tv_sec - 60*60*24 - 1,
|
||||
/*.tv_nsec = */ now.tv_nsec
|
||||
};
|
||||
st.atime = before_yesterday;
|
||||
st.mtime.tv_nsec = st.atime.tv_nsec - 1;
|
||||
node->utimens(
|
||||
st.atime,
|
||||
st.mtime
|
||||
);
|
||||
}
|
||||
};
|
||||
template<class ConcreteFileSystemTestFixture> constexpr fspp::mode_t FileSystemTest<ConcreteFileSystemTestFixture>::MODE_PUBLIC;
|
||||
|
||||
|
@ -10,17 +10,22 @@
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class TimestampTestUtils : public virtual FileSystemTest<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
using TimestampUpdateBehavior = std::function<void (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation)>;
|
||||
using TimestampUpdateExpectation = std::function<void (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation)>;
|
||||
|
||||
static TimestampUpdateBehavior ExpectUpdatesAccessTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateAccessTimestamp;
|
||||
static TimestampUpdateBehavior ExpectUpdatesModificationTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateModificationTimestamp;
|
||||
static TimestampUpdateBehavior ExpectUpdatesMetadataTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateMetadataTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateAnyTimestamps;
|
||||
static TimestampUpdateExpectation ExpectUpdatesAccessTimestamp;
|
||||
static TimestampUpdateExpectation ExpectDoesntUpdateAccessTimestamp;
|
||||
static TimestampUpdateExpectation ExpectUpdatesModificationTimestamp;
|
||||
static TimestampUpdateExpectation ExpectDoesntUpdateModificationTimestamp;
|
||||
static TimestampUpdateExpectation ExpectUpdatesMetadataTimestamp;
|
||||
static TimestampUpdateExpectation ExpectDoesntUpdateMetadataTimestamp;
|
||||
static TimestampUpdateExpectation ExpectDoesntUpdateAnyTimestamps;
|
||||
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(std::function<fspp::Node::stat_info()> statOld, std::function<fspp::Node::stat_info()> statNew, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
|
||||
void setTimestampUpdateBehavior(fspp::TimestampUpdateBehavior timestampUpdateBehavior) {
|
||||
FileSystemTest<ConcreteFileSystemTestFixture>::device->setContext(fspp::Context { timestampUpdateBehavior });
|
||||
}
|
||||
|
||||
template<class Operation>
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(std::function<fspp::Node::stat_info()> statOld, std::function<fspp::Node::stat_info()> statNew, Operation&& operation, std::initializer_list<TimestampUpdateExpectation> behaviorChecks) {
|
||||
auto oldStat = statOld();
|
||||
ensureNodeTimestampsAreOld(oldStat);
|
||||
timespec timeBeforeOperation = cpputils::time::now();
|
||||
@ -32,26 +37,29 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const fspp::OpenFile &node, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
|
||||
template<class Operation>
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const fspp::OpenFile &node, Operation&& operation, std::initializer_list<TimestampUpdateExpectation> behaviorChecks) {
|
||||
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(
|
||||
[this, &node](){return this->stat(node);},
|
||||
[this, &node](){return this->stat(node);},
|
||||
operation,
|
||||
std::forward<Operation>(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) {
|
||||
template<class Operation>
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const boost::filesystem::path &oldPath, const boost::filesystem::path &newPath, Operation&& operation, std::initializer_list<TimestampUpdateExpectation> behaviorChecks) {
|
||||
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(
|
||||
[this, oldPath](){return this->stat(*this->Load(oldPath));},
|
||||
[this, newPath](){return this->stat(*this->Load(newPath));},
|
||||
operation,
|
||||
std::forward<Operation>(operation),
|
||||
behaviorChecks
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
template<class Operation>
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const boost::filesystem::path &path, Operation&& operation, std::initializer_list<TimestampUpdateExpectation> behaviorChecks) {
|
||||
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(path, path, std::forward<Operation>(operation), behaviorChecks);
|
||||
}
|
||||
|
||||
void EXPECT_ACCESS_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
|
||||
@ -90,6 +98,55 @@ public:
|
||||
EXPECT_LT(nodeStat.ctime, cpputils::time::now());
|
||||
}
|
||||
|
||||
class TestBuilder final {
|
||||
public:
|
||||
explicit TestBuilder(TimestampTestUtils* fixture): _fixture(fixture) {}
|
||||
|
||||
const TestBuilder& withNoatime(std::function<void()> expectations) const {
|
||||
_fixture->resetFilesystem(fspp::Context {fspp::noatime()});
|
||||
expectations();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const TestBuilder& withStrictatime(std::function<void()> expectations) const {
|
||||
_fixture->resetFilesystem(fspp::Context {fspp::strictatime()});
|
||||
expectations();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const TestBuilder& withRelatime(std::function<void()> expectations) const {
|
||||
_fixture->resetFilesystem(fspp::Context {fspp::relatime()});
|
||||
expectations();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const TestBuilder& withNodiratimeRelatime(std::function<void()> expectations) const {
|
||||
_fixture->resetFilesystem(fspp::Context {fspp::nodiratime_relatime()});
|
||||
expectations();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const TestBuilder& withNodiratimeStrictatime(std::function<void()> expectations) const {
|
||||
_fixture->resetFilesystem(fspp::Context {fspp::nodiratime_strictatime()});
|
||||
expectations();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const TestBuilder& withAnyAtimeConfig(std::function<void()> expectations) const {
|
||||
return withNoatime(expectations)
|
||||
.withStrictatime(expectations)
|
||||
.withRelatime(expectations)
|
||||
.withNodiratimeRelatime(expectations)
|
||||
.withNodiratimeStrictatime(expectations);
|
||||
}
|
||||
|
||||
private:
|
||||
TimestampTestUtils* _fixture;
|
||||
};
|
||||
TestBuilder testBuilder() {
|
||||
return TestBuilder(this);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void waitUntilClockProgresses() {
|
||||
@ -101,7 +158,7 @@ private:
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesAccessTimestamp =
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateExpectation TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesAccessTimestamp =
|
||||
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
UNUSED(timeBeforeOperation);
|
||||
@ -111,7 +168,7 @@ typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehav
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAccessTimestamp =
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateExpectation TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAccessTimestamp =
|
||||
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
@ -119,7 +176,7 @@ typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehav
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesModificationTimestamp =
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateExpectation TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesModificationTimestamp =
|
||||
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.mtime);
|
||||
@ -127,7 +184,7 @@ typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehav
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateModificationTimestamp =
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateExpectation TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateModificationTimestamp =
|
||||
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
@ -135,7 +192,7 @@ typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehav
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesMetadataTimestamp =
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateExpectation TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesMetadataTimestamp =
|
||||
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.ctime);
|
||||
@ -143,7 +200,7 @@ typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehav
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateMetadataTimestamp =
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateExpectation TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateMetadataTimestamp =
|
||||
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
@ -151,7 +208,7 @@ typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehav
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAnyTimestamps =
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateExpectation TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAnyTimestamps =
|
||||
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
ExpectDoesntUpdateAccessTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
ExpectDoesntUpdateModificationTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <cpp-utils/pointer/unique_ref.h>
|
||||
#include <sys/stat.h>
|
||||
#include "../fs_interface/Dir.h"
|
||||
#include "../fs_interface/Context.h"
|
||||
#if defined(_MSC_VER)
|
||||
#include <fuse/fuse.h>
|
||||
#else
|
||||
@ -19,6 +20,8 @@ class Filesystem {
|
||||
public:
|
||||
virtual ~Filesystem() {}
|
||||
|
||||
virtual void setContext(Context&& context) = 0;
|
||||
|
||||
//TODO Test uid/gid parameters of createAndOpenFile
|
||||
virtual int createAndOpenFile(const boost::filesystem::path &path, ::mode_t mode, ::uid_t uid, ::gid_t gid) = 0;
|
||||
virtual int openFile(const boost::filesystem::path &path, int flags) = 0;
|
||||
|
@ -13,6 +13,10 @@
|
||||
#include "InvalidFilesystem.h"
|
||||
#include <codecvt>
|
||||
|
||||
#include <range/v3/view/split.hpp>
|
||||
#include <range/v3/view/join.hpp>
|
||||
#include <range/v3/view/filter.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <codecvt>
|
||||
#include <dokan/dokan.h>
|
||||
@ -265,19 +269,19 @@ void Fuse::_logUnknownException() {
|
||||
LOG(ERR, "Unknown exception thrown");
|
||||
}
|
||||
|
||||
void Fuse::runInForeground(const bf::path &mountdir, const vector<string> &fuseOptions) {
|
||||
vector<string> realFuseOptions = fuseOptions;
|
||||
void Fuse::runInForeground(const bf::path &mountdir, vector<string> fuseOptions) {
|
||||
vector<string> realFuseOptions = std::move(fuseOptions);
|
||||
if (std::find(realFuseOptions.begin(), realFuseOptions.end(), "-f") == realFuseOptions.end()) {
|
||||
realFuseOptions.push_back("-f");
|
||||
}
|
||||
_run(mountdir, realFuseOptions);
|
||||
_run(mountdir, std::move(realFuseOptions));
|
||||
}
|
||||
|
||||
void Fuse::runInBackground(const bf::path &mountdir, const vector<string> &fuseOptions) {
|
||||
vector<string> realFuseOptions = fuseOptions;
|
||||
void Fuse::runInBackground(const bf::path &mountdir, vector<string> fuseOptions) {
|
||||
vector<string> realFuseOptions = std::move(fuseOptions);
|
||||
_removeAndWarnIfExists(&realFuseOptions, "-f");
|
||||
_removeAndWarnIfExists(&realFuseOptions, "-d");
|
||||
_run(mountdir, realFuseOptions);
|
||||
_run(mountdir, std::move(realFuseOptions));
|
||||
}
|
||||
|
||||
void Fuse::_removeAndWarnIfExists(vector<string> *fuseOptions, const std::string &option) {
|
||||
@ -291,7 +295,52 @@ void Fuse::_removeAndWarnIfExists(vector<string> *fuseOptions, const std::string
|
||||
}
|
||||
}
|
||||
|
||||
void Fuse::_run(const bf::path &mountdir, const vector<string> &fuseOptions) {
|
||||
namespace {
|
||||
void extractAllAtimeOptionsAndRemoveOnesUnknownToLibfuse_(string* csv_options, vector<string>* result) {
|
||||
const auto is_fuse_supported_atime_flag = [] (const std::string& flag) {
|
||||
constexpr std::array<const char*, 2> flags = {"noatime", "atime"};
|
||||
return flags.end() != std::find(flags.begin(), flags.end(), flag);
|
||||
};
|
||||
const auto is_fuse_unsupported_atime_flag = [] (const std::string& flag) {
|
||||
constexpr std::array<const char*, 3> flags = {"strictatime", "relatime", "nodiratime"};
|
||||
return flags.end() != std::find(flags.begin(), flags.end(), flag);
|
||||
};
|
||||
*csv_options = *csv_options
|
||||
| ranges::view::split(',')
|
||||
| ranges::view::filter(
|
||||
[&] (const std::string& elem) {
|
||||
if (is_fuse_unsupported_atime_flag(elem)) {
|
||||
result->push_back(elem);
|
||||
return false;
|
||||
}
|
||||
if (is_fuse_supported_atime_flag(elem)) {
|
||||
result->push_back(elem);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
| ranges::view::join(',')
|
||||
| ranges::to<string>();
|
||||
}
|
||||
|
||||
// Return a list of all atime options (e.g. atime, noatime, relatime, strictatime, nodiratime) that occur in the
|
||||
// fuseOptions input. They must be preceded by a '-o', i.e. {..., '-o', 'noatime', ...} and multiple ones can be
|
||||
// csv-concatenated, i.e. {..., '-o', 'atime,nodiratime', ...}.
|
||||
// Also, this function removes all of these atime options that are unknown to libfuse (i.e. all except atime and noatime)
|
||||
// from the input fuseOptions so we can pass it on to libfuse without crashing.
|
||||
vector<string> extractAllAtimeOptionsAndRemoveOnesUnknownToLibfuse_(vector<string>* fuseOptions) {
|
||||
vector<string> result;
|
||||
bool lastOptionWasDashO = false;
|
||||
for (string& option : *fuseOptions) {
|
||||
if (lastOptionWasDashO) {
|
||||
extractAllAtimeOptionsAndRemoveOnesUnknownToLibfuse_(&option, &result);
|
||||
}
|
||||
lastOptionWasDashO = (option == "-o");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void Fuse::_run(const bf::path &mountdir, vector<string> fuseOptions) {
|
||||
#if defined(__GLIBC__)|| defined(__APPLE__) || defined(_MSC_VER)
|
||||
// Avoid encoding errors for non-utf8 characters, see https://github.com/cryfs/cryfs/issues/247
|
||||
// this is ifdef'd out for non-glibc linux, because musl doesn't handle this correctly.
|
||||
@ -302,11 +351,66 @@ void Fuse::_run(const bf::path &mountdir, const vector<string> &fuseOptions) {
|
||||
|
||||
ASSERT(_argv.size() == 0, "Filesystem already started");
|
||||
|
||||
vector<string> atimeOptions = extractAllAtimeOptionsAndRemoveOnesUnknownToLibfuse_(&fuseOptions);
|
||||
_createContext(atimeOptions);
|
||||
|
||||
_argv = _build_argv(mountdir, fuseOptions);
|
||||
|
||||
fuse_main(_argv.size(), _argv.data(), operations(), this);
|
||||
}
|
||||
|
||||
void Fuse::_createContext(const vector<string> &fuseOptions) {
|
||||
const bool has_atime_flag = fuseOptions.end() != std::find(fuseOptions.begin(), fuseOptions.end(), "atime");
|
||||
const bool has_noatime_flag = fuseOptions.end() != std::find(fuseOptions.begin(), fuseOptions.end(), "noatime");
|
||||
const bool has_relatime_flag = fuseOptions.end() != std::find(fuseOptions.begin(), fuseOptions.end(), "relatime");
|
||||
const bool has_strictatime_flag = fuseOptions.end() != std::find(fuseOptions.begin(), fuseOptions.end(), "strictatime");
|
||||
const bool has_nodiratime_flag = fuseOptions.end() != std::find(fuseOptions.begin(), fuseOptions.end(), "nodiratime");
|
||||
|
||||
// Default is RELATIME
|
||||
_context = Context(relatime());
|
||||
|
||||
if (has_noatime_flag) {
|
||||
ASSERT(!has_atime_flag, "Cannot have both, noatime and atime flags set.");
|
||||
ASSERT(!has_relatime_flag, "Cannot have both, noatime and relatime flags set.");
|
||||
ASSERT(!has_strictatime_flag, "Cannot have both, noatime and strictatime flags set.");
|
||||
// note: can have nodiratime flag set but that is ignored because it is already included in the noatime policy.
|
||||
_context->setTimestampUpdateBehavior(noatime());
|
||||
} else if (has_relatime_flag) {
|
||||
// note: can have atime and relatime both set, they're identical
|
||||
ASSERT(!has_noatime_flag, "This shouldn't happen, or we would have hit a case above.");
|
||||
ASSERT(!has_strictatime_flag, "Cannot have both, relatime and strictatime flags set.");
|
||||
if (has_nodiratime_flag) {
|
||||
_context->setTimestampUpdateBehavior(nodiratime_relatime());
|
||||
} else {
|
||||
_context->setTimestampUpdateBehavior(relatime());
|
||||
}
|
||||
} else if (has_atime_flag) {
|
||||
// note: can have atime and relatime both set, they're identical
|
||||
ASSERT(!has_noatime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
ASSERT(!has_strictatime_flag, "Cannot have both, atime and strictatime flags set.");
|
||||
if (has_nodiratime_flag) {
|
||||
_context->setTimestampUpdateBehavior(nodiratime_relatime());
|
||||
} else {
|
||||
_context->setTimestampUpdateBehavior(relatime());
|
||||
}
|
||||
} else if (has_strictatime_flag) {
|
||||
ASSERT(!has_noatime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
ASSERT(!has_atime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
ASSERT(!has_relatime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
if (has_nodiratime_flag) {
|
||||
_context->setTimestampUpdateBehavior(nodiratime_strictatime());
|
||||
} else {
|
||||
_context->setTimestampUpdateBehavior(strictatime());
|
||||
}
|
||||
} else if (has_nodiratime_flag) {
|
||||
ASSERT(!has_noatime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
ASSERT(!has_atime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
ASSERT(!has_relatime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
ASSERT(!has_strictatime_flag, "This shouldn't happen, or we would have hit a case above");
|
||||
_context->setTimestampUpdateBehavior(nodiratime_relatime()); // use relatime by default
|
||||
}
|
||||
}
|
||||
|
||||
vector<char *> Fuse::_build_argv(const bf::path &mountdir, const vector<string> &fuseOptions) {
|
||||
vector<char *> argv;
|
||||
argv.reserve(6 + fuseOptions.size()); // fuseOptions + executable name + mountdir + 2x fuse options (subtype, fsname), each taking 2 entries ("-o", "key=value").
|
||||
@ -1100,6 +1204,9 @@ void Fuse::init(fuse_conn_info *conn) {
|
||||
ThreadNameForDebugging _threadName("init");
|
||||
_fs = _init(this);
|
||||
|
||||
ASSERT(_context != boost::none, "Context should have been initialized in Fuse::run() but somehow didn't");
|
||||
_fs->setContext(fspp::Context { *_context });
|
||||
|
||||
LOG(INFO, "Filesystem started.");
|
||||
|
||||
_running = true;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <cpp-utils/macros.h>
|
||||
#include <atomic>
|
||||
#include "stat_compatibility.h"
|
||||
#include <fspp/fs_interface/Context.h>
|
||||
|
||||
namespace fspp {
|
||||
class Device;
|
||||
@ -24,8 +25,8 @@ public:
|
||||
explicit Fuse(std::function<std::shared_ptr<Filesystem> (Fuse *fuse)> init, std::function<void()> onMounted, std::string fstype, boost::optional<std::string> fsname);
|
||||
~Fuse();
|
||||
|
||||
void runInBackground(const boost::filesystem::path &mountdir, const std::vector<std::string> &fuseOptions);
|
||||
void runInForeground(const boost::filesystem::path &mountdir, const std::vector<std::string> &fuseOptions);
|
||||
void runInBackground(const boost::filesystem::path &mountdir, std::vector<std::string> fuseOptions);
|
||||
void runInForeground(const boost::filesystem::path &mountdir, std::vector<std::string> fuseOptions);
|
||||
bool running() const;
|
||||
void stop();
|
||||
|
||||
@ -67,11 +68,12 @@ private:
|
||||
static void _logUnknownException();
|
||||
static char *_create_c_string(const std::string &str);
|
||||
static void _removeAndWarnIfExists(std::vector<std::string> *fuseOptions, const std::string &option);
|
||||
void _run(const boost::filesystem::path &mountdir, const std::vector<std::string> &fuseOptions);
|
||||
void _run(const boost::filesystem::path &mountdir, std::vector<std::string> fuseOptions);
|
||||
static bool _has_option(const std::vector<char *> &vec, const std::string &key);
|
||||
static bool _has_entry_with_prefix(const std::string &prefix, const std::vector<char *> &vec);
|
||||
std::vector<char *> _build_argv(const boost::filesystem::path &mountdir, const std::vector<std::string> &fuseOptions);
|
||||
void _add_fuse_option_if_not_exists(std::vector<char *> *argv, const std::string &key, const std::string &value);
|
||||
void _createContext(const std::vector<std::string> &fuseOptions);
|
||||
|
||||
std::function<std::shared_ptr<Filesystem> (Fuse *fuse)> _init;
|
||||
std::function<void()> _onMounted;
|
||||
@ -81,6 +83,7 @@ private:
|
||||
std::atomic<bool> _running;
|
||||
std::string _fstype;
|
||||
boost::optional<std::string> _fsname;
|
||||
boost::optional<Context> _context;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Fuse);
|
||||
};
|
||||
|
@ -7,6 +7,10 @@
|
||||
namespace fspp {
|
||||
namespace fuse {
|
||||
class InvalidFilesystem final : public Filesystem {
|
||||
void setContext(Context&&) override {
|
||||
throw std::logic_error("Filesystem not initialized yet");
|
||||
}
|
||||
|
||||
int createAndOpenFile(const boost::filesystem::path &, ::mode_t , ::uid_t , ::gid_t ) override {
|
||||
throw std::logic_error("Filesystem not initialized yet");
|
||||
}
|
||||
|
@ -91,6 +91,10 @@ FilesystemImpl::~FilesystemImpl() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void FilesystemImpl::setContext(Context&& context) {
|
||||
_device->setContext(std::move(context));
|
||||
}
|
||||
|
||||
unique_ref<File> FilesystemImpl::LoadFile(const bf::path &path) {
|
||||
PROFILE(_loadFileNanosec);
|
||||
auto file = _device->LoadFile(path);
|
||||
|
@ -24,6 +24,8 @@ public:
|
||||
explicit FilesystemImpl(cpputils::unique_ref<Device> device);
|
||||
virtual ~FilesystemImpl();
|
||||
|
||||
void setContext(Context&& context) override;
|
||||
|
||||
int openFile(const boost::filesystem::path &path, int flags) override;
|
||||
void flush(int descriptor) override;
|
||||
void closeFile(int descriptor) override;
|
||||
|
@ -91,7 +91,7 @@ TEST(BacktraceTest, ContainsBacktrace) {
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) {
|
||||
auto output = call_process_exiting_with_nullptr_violation();
|
||||
auto output = call_process_exiting_with_nullptr_violation();
|
||||
#if defined(_MSC_VER)
|
||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||
#else
|
||||
@ -120,7 +120,7 @@ TEST(BacktraceTest, ShowBacktraceOnUnhandledException) {
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
||||
auto output = call_process_exiting_with_sigill();
|
||||
#if defined(_MSC_VER)
|
||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||
#else
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
#endif
|
||||
@ -153,8 +153,8 @@ TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt) {
|
||||
auto output = call_process_exiting_with_sigabrt();
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
auto output = call_process_exiting_with_sigabrt();
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) {
|
||||
|
@ -137,4 +137,3 @@ TEST_F(ProgramOptionsTest, SomeFuseOptions) {
|
||||
//Fuse should have the mount dir as first parameter
|
||||
EXPECT_VECTOR_EQ({"-f", "--longoption"}, testobj.fuseOptions());
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,10 @@ auto failOnIntegrityViolation() {
|
||||
TEST_F(CryFsTest, CreatedRootdirIsLoadableAfterClosing) {
|
||||
{
|
||||
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation());
|
||||
dev.setContext(fspp::Context {fspp::relatime()});
|
||||
}
|
||||
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation());
|
||||
dev.setContext(fspp::Context {fspp::relatime()});
|
||||
auto rootDir = dev.LoadDir(bf::path("/"));
|
||||
rootDir.value()->children();
|
||||
}
|
||||
@ -74,10 +76,12 @@ TEST_F(CryFsTest, CreatedRootdirIsLoadableAfterClosing) {
|
||||
TEST_F(CryFsTest, LoadingFilesystemDoesntModifyConfigFile) {
|
||||
{
|
||||
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation());
|
||||
dev.setContext(fspp::Context {fspp::relatime()});
|
||||
}
|
||||
Data configAfterCreating = Data::LoadFromFile(config.path()).value();
|
||||
{
|
||||
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation());
|
||||
dev.setContext(fspp::Context {fspp::relatime()});
|
||||
}
|
||||
Data configAfterLoading = Data::LoadFromFile(config.path()).value();
|
||||
EXPECT_EQ(configAfterCreating, configAfterLoading);
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
CryTestBase(): _tempLocalStateDir(), _localStateDir(_tempLocalStateDir.path()), _configFile(false), _device(nullptr) {
|
||||
auto fakeBlockStore = cpputils::make_unique_ref<blockstore::inmemory::InMemoryBlockStore2>();
|
||||
_device = std::make_unique<cryfs::CryDevice>(configFile(), std::move(fakeBlockStore), _localStateDir, 0x12345678, false, false, failOnIntegrityViolation());
|
||||
_device->setContext(fspp::Context { fspp::relatime() });
|
||||
}
|
||||
|
||||
std::shared_ptr<cryfs::CryConfigFile> configFile() {
|
||||
|
@ -69,6 +69,7 @@ set(SOURCES
|
||||
fuse/access/FuseAccessModeTest.cpp
|
||||
fuse/access/FuseAccessErrorTest.cpp
|
||||
fuse/BasicFuseTest.cpp
|
||||
fuse/TimestampTest.cpp
|
||||
fuse/rmdir/testutils/FuseRmdirTest.cpp
|
||||
fuse/rmdir/FuseRmdirErrorTest.cpp
|
||||
fuse/rmdir/FuseRmdirDirnameTest.cpp
|
||||
|
313
test/fspp/fuse/TimestampTest.cpp
Normal file
313
test/fspp/fuse/TimestampTest.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
#include "../testutils/FuseTest.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace fspp::fuse;
|
||||
|
||||
typedef FuseTest FuseTimestampTest;
|
||||
|
||||
// Single flag
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithoutAnyAtimeFlag_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeFlag_thenHasNoatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "noatime"});
|
||||
EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeFlag_thenHasStrictatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "strictatime"});
|
||||
EXPECT_EQ(fspp::strictatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeFlag_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "relatime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeFlag_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "atime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeFlag_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Flag combinations
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeAtimeFlag_withCsv_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "atime,atime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeAtimeFlag_withSeparateFlags_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "atime", "-o", "atime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeNoatimeFlag_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "atime,noatime"}),
|
||||
"Cannot have both, noatime and atime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeNoatimeFlag_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "atime", "-o", "noatime"}),
|
||||
"Cannot have both, noatime and atime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeRelatimeFlag_withCsv_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "atime,relatime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeRelatimeFlag_withSeparateFlags_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "atime", "-o", "relatime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeStrictatimeFlag_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "atime,strictatime"}),
|
||||
"Cannot have both, atime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeStrictatimeFlag_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "atime", "-o", "strictatime"}),
|
||||
"Cannot have both, atime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeNodiratimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "atime,nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithAtimeNodiratimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "atime", "-o", "nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeAtime_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "noatime,atime"}),
|
||||
"Cannot have both, noatime and atime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeAtime_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "noatime", "-o", "atime"}),
|
||||
"Cannot have both, noatime and atime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeNoatimeFlag_withCsv_thenHasNoatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "noatime,noatime"});
|
||||
EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeNoatimeFlag_withSeparateFlags_thenHasNoatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "noatime", "-o", "noatime"});
|
||||
EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeRelatime_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "noatime,relatime"}),
|
||||
"Cannot have both, noatime and relatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeRelatime_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "noatime", "-o", "relatime"}),
|
||||
"Cannot have both, noatime and relatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeStrictatime_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "noatime,strictatime"}),
|
||||
"Cannot have both, noatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeStrictatime_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "noatime", "-o", "strictatime"}),
|
||||
"Cannot have both, noatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeNodiratimeFlag_withCsv_thenHasNoatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "noatime,nodiratime"});
|
||||
EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNoatimeNodiratimeFlag_withSeparateFlags_thenHasNoatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "noatime", "-o", "nodiratime"});
|
||||
EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeAtimeFlag_withCsv_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "relatime,atime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeAtimeFlag_withSeparateFlags_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "relatime", "-o", "atime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeNoatime_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "relatime,noatime"}),
|
||||
"Cannot have both, noatime and relatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeNoatime_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "relatime", "-o", "noatime"}),
|
||||
"Cannot have both, noatime and relatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeRelatimeFlag_withCsv_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "relatime,relatime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeRelatimeFlag_withSeparateFlags_thenHasRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "relatime", "-o", "relatime"});
|
||||
EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeStrictatime_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "relatime,strictatime"}),
|
||||
"Cannot have both, relatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeStrictatime_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "relatime", "-o", "strictatime"}),
|
||||
"Cannot have both, relatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeNodiratimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "relatime,nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithRelatimeNodiratimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "relatime", "-o", "nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeAtimeFlag_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "strictatime,atime"}),
|
||||
"Cannot have both, atime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeAtimeFlag_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "strictatime", "-o", "atime"}),
|
||||
"Cannot have both, atime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNoatimeFlag_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "strictatime,noatime"}),
|
||||
"Cannot have both, noatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNoatimeFlag_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "strictatime", "-o", "noatime"}),
|
||||
"Cannot have both, noatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeRelatimeFlag_withCsv_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "strictatime,relatime"}),
|
||||
"Cannot have both, relatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeRelatimeFlag_withSeparateFlags_thenFails) {
|
||||
EXPECT_DEATH(
|
||||
TestFS({"-o", "strictatime", "-o", "relatime"}),
|
||||
"Cannot have both, relatime and strictatime flags set.");
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeStrictatimeFlag_withCsv_thenHasStrictatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "strictatime,strictatime"});
|
||||
EXPECT_EQ(fspp::strictatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeStrictatimeFlag_withSeparateFlags_thenHasStrictatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "strictatime", "-o", "strictatime"});
|
||||
EXPECT_EQ(fspp::strictatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNodiratimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "strictatime,nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNodiratimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "strictatime", "-o", "nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeAtimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime,atime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeAtimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime", "-o", "atime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNoatimeFlag_withCsv_thenHasNoatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime,noatime"});
|
||||
EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNoatimeFlag_withSeparateFlags_thenHasNoatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime", "-o", "noatime"});
|
||||
EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeRelatimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime,relatime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeRelatimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime", "-o", "relatime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeStrictatimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime,strictatime"});
|
||||
EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeStrictatimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime", "-o", "strictatime"});
|
||||
EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNodiratimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime,nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
||||
|
||||
TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNodiratimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) {
|
||||
auto fs = TestFS({"-o", "nodiratime", "-o", "nodiratime"});
|
||||
EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get());
|
||||
}
|
@ -19,7 +19,7 @@ using namespace fspp::fuse;
|
||||
MockFilesystem::MockFilesystem() {}
|
||||
MockFilesystem::~MockFilesystem() {}
|
||||
|
||||
FuseTest::FuseTest(): fsimpl(make_shared<MockFilesystem>()) {
|
||||
FuseTest::FuseTest(): fsimpl(make_shared<MockFilesystem>()), _context(boost::none) {
|
||||
auto defaultAction = Throw(FuseErrnoException(EIO));
|
||||
ON_CALL(*fsimpl, openFile(_,_)).WillByDefault(defaultAction);
|
||||
ON_CALL(*fsimpl, closeFile(_)).WillByDefault(defaultAction);
|
||||
@ -48,18 +48,23 @@ FuseTest::FuseTest(): fsimpl(make_shared<MockFilesystem>()) {
|
||||
ON_CALL(*fsimpl, readSymlink(_,_,_)).WillByDefault(defaultAction);
|
||||
|
||||
EXPECT_CALL(*fsimpl, access(_,_)).WillRepeatedly(Return());
|
||||
|
||||
ON_CALL(*fsimpl, setContext(_)).WillByDefault(Invoke([this] (fspp::Context context) {
|
||||
_context = std::move(context);
|
||||
}));
|
||||
|
||||
ReturnIsDirOnLstat("/");
|
||||
}
|
||||
|
||||
unique_ref<FuseTest::TempTestFS> FuseTest::TestFS() {
|
||||
return make_unique_ref<TempTestFS>(fsimpl);
|
||||
unique_ref<FuseTest::TempTestFS> FuseTest::TestFS(const std::vector<std::string>& fuseOptions) {
|
||||
return make_unique_ref<TempTestFS>(fsimpl, fuseOptions);
|
||||
}
|
||||
|
||||
FuseTest::TempTestFS::TempTestFS(shared_ptr<MockFilesystem> fsimpl)
|
||||
FuseTest::TempTestFS::TempTestFS(shared_ptr<MockFilesystem> fsimpl, const std::vector<std::string>& fuseOptions)
|
||||
:_mountDir(),
|
||||
_fuse([fsimpl] (Fuse*) {return fsimpl;}, []{}, "fusetest", boost::none), _fuse_thread(&_fuse) {
|
||||
|
||||
_fuse_thread.start(_mountDir.path(), {});
|
||||
_fuse_thread.start(_mountDir.path(), fuseOptions);
|
||||
}
|
||||
|
||||
FuseTest::TempTestFS::~TempTestFS() {
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
MockFilesystem();
|
||||
virtual ~MockFilesystem();
|
||||
|
||||
MOCK_METHOD(void, setContext, (fspp::Context&&), (override));
|
||||
MOCK_METHOD(int, openFile, (const boost::filesystem::path&, int), (override));
|
||||
MOCK_METHOD(void, closeFile, (int), (override));
|
||||
MOCK_METHOD(void, lstat, (const boost::filesystem::path&, fspp::fuse::STAT*), (override));
|
||||
@ -54,7 +55,7 @@ public:
|
||||
|
||||
class TempTestFS {
|
||||
public:
|
||||
TempTestFS(std::shared_ptr<MockFilesystem> fsimpl);
|
||||
TempTestFS(std::shared_ptr<MockFilesystem> fsimpl, const std::vector<std::string>& fuseOptions = {});
|
||||
virtual ~TempTestFS();
|
||||
public:
|
||||
const boost::filesystem::path &mountDir() const;
|
||||
@ -64,10 +65,18 @@ public:
|
||||
FuseThread _fuse_thread;
|
||||
};
|
||||
|
||||
cpputils::unique_ref<TempTestFS> TestFS();
|
||||
cpputils::unique_ref<TempTestFS> TestFS(const std::vector<std::string>& fuseOptions = {});
|
||||
|
||||
std::shared_ptr<MockFilesystem> fsimpl;
|
||||
|
||||
const fspp::Context& context() const {
|
||||
ASSERT(_context != boost::none, "Context wasn't correctly initialized");
|
||||
return *_context;
|
||||
}
|
||||
private:
|
||||
boost::optional<fspp::Context> _context;
|
||||
|
||||
public:
|
||||
|
||||
//TODO Combine ReturnIsFile and ReturnIsFileFstat. This should be possible in gmock by either (a) using ::testing::Undefined as parameter type or (b) using action macros
|
||||
static ::testing::Action<void(const boost::filesystem::path&, fspp::fuse::STAT*)> ReturnIsFile;
|
||||
|
Loading…
Reference in New Issue
Block a user