Add test cases that fspp::Node operations correctly modify the timestamps

This commit is contained in:
Sebastian Messmer 2016-05-27 17:26:53 -07:00
parent 183b9cf74b
commit 514de8794e
4 changed files with 210 additions and 2 deletions

View File

@ -9,6 +9,7 @@
#include "FsppSymlinkTest.h"
#include "FsppNodeTest_Rename.h"
#include "FsppNodeTest_Stat.h"
#include "FsppNodeTest_Timestamps.h"
#include "FsppOpenFileTest.h"
#define FSPP_ADD_FILESYTEM_TESTS(FS_NAME, FIXTURE) \
@ -18,9 +19,11 @@
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppSymlinkTest, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Rename, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Stat, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_FileOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_DirOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_SymlinkOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppOpenFileTest, FIXTURE); \
#endif

View File

@ -80,5 +80,3 @@ REGISTER_TYPED_TEST_CASE_P(FsppNodeTest_Stat_SymlinkOnly,
#endif
//TODO More test cases
//TODO Test all operations do (or don't) affect timestamps correctly

View File

@ -0,0 +1,100 @@
#pragma once
#ifndef MESSMER_FSPP_FSTEST_FSPPNODETEST_TIMESTAMPS_H_
#define MESSMER_FSPP_FSTEST_FSPPNODETEST_TIMESTAMPS_H_
#include "testutils/FsppNodeTest.h"
#include "../fuse/FuseErrnoException.h"
#include "testutils/TimestampTestUtils.h"
using namespace cpputils::time;
using std::function;
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
public:
void Test_Create() {
timespec lowerBound = now();
auto node = this->CreateNode("/mynode");
timespec upperBound = now();
EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *node);
}
void Test_Stat() {
auto node = this->CreateNode("/mynode");
auto operation = [&node] () {
struct stat st;
node->stat(&st);
};
EXPECT_OPERATION_DOESNT_UPDATE_TIMESTAMPS(*node, operation);
}
void Test_Chmod() {
auto node = this->CreateNode("/mynode");
mode_t mode = stat(*node).st_mode;
auto operation = [&node, mode] () {
node->chmod(mode);
};
EXPECT_OPERATION_DOESNT_UPDATE_ACCESS_TIMESTAMP(*node, operation);
EXPECT_OPERATION_DOESNT_UPDATE_MODIFICATION_TIMESTAMP(*node, operation);
EXPECT_OPERATION_UPDATES_METADATACHANGE_TIMESTAMP(*node, operation);
}
void Test_Chown() {
auto node = this->CreateNode("/mynode");
uid_t uid = stat(*node).st_uid;
gid_t gid = stat(*node).st_gid;
auto operation = [&node, uid, gid] () {
node->chown(uid, gid);
};
EXPECT_OPERATION_DOESNT_UPDATE_ACCESS_TIMESTAMP(*node, operation);
EXPECT_OPERATION_DOESNT_UPDATE_MODIFICATION_TIMESTAMP(*node, operation);
EXPECT_OPERATION_UPDATES_METADATACHANGE_TIMESTAMP(*node, operation);
}
void Test_Access() {
auto node = this->CreateNode("/mynode");
auto operation = [&node] () {
node->access(0);
};
EXPECT_OPERATION_DOESNT_UPDATE_TIMESTAMPS(*node, operation);
}
void Test_Rename() {
auto node = this->CreateNode("/mynode");
auto operation = [&node] () {
node->rename("newnodename");
};
EXPECT_OPERATION_DOESNT_UPDATE_ACCESS_TIMESTAMP(*node, operation);
EXPECT_OPERATION_DOESNT_UPDATE_MODIFICATION_TIMESTAMP(*node, operation);
EXPECT_OPERATION_UPDATES_METADATACHANGE_TIMESTAMP(*node, operation);
}
// TODO Other rename cases (e.g. failed renames/error paths, moving to different dir, ...) from FsppNodeTest_Rename
void Test_Utimens() {
auto node = this->CreateNode("/mynode");
timespec atime = xSecondsAgo(100);
timespec mtime = xSecondsAgo(200);
auto operation = [&node, atime, mtime] () {
node->utimens(atime, mtime);
};
EXPECT_OPERATION_UPDATES_METADATACHANGE_TIMESTAMP(*node, operation);
EXPECT_EQ(atime, stat(*node).st_atim);
EXPECT_EQ(mtime, stat(*node).st_mtim);
}
};
REGISTER_NODE_TEST_CASE(FsppNodeTest_Timestamps,
Create,
Stat,
Chmod,
Chown,
Access,
Rename,
Utimens
);
#endif

View File

@ -0,0 +1,107 @@
#pragma once
#ifndef MESSMER_FSPP_FSTEST_TESTUTILS_TIMESTAMPTESTUTILS_H_
#define MESSMER_FSPP_FSTEST_TESTUTILS_TIMESTAMPTESTUTILS_H_
#include <cpp-utils/system/time.h>
class TimestampTestUtils {
public:
void EXPECT_ACCESS_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_atim);
EXPECT_GE(upperBound, stat(node).st_atim);
}
void EXPECT_MODIFICATION_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_mtim);
EXPECT_GE(upperBound, stat(node).st_mtim);
}
void EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_ctim);
EXPECT_GE(upperBound, stat(node).st_ctim);
}
void EXPECT_OPERATION_DOESNT_UPDATE_ACCESS_TIMESTAMP(const fspp::Node &node, std::function<void()> operation) {
ensureNodeTimestampsAreOld(node);
timespec oldTime = stat(node).st_atim;
operation();
timespec newTime = stat(node).st_atim;
EXPECT_EQ(oldTime, newTime);
}
void EXPECT_OPERATION_DOESNT_UPDATE_MODIFICATION_TIMESTAMP(const fspp::Node &node, std::function<void()> operation) {
ensureNodeTimestampsAreOld(node);
timespec oldTime = stat(node).st_mtim;
operation();
timespec newTime = stat(node).st_mtim;
EXPECT_EQ(oldTime, newTime);
}
void EXPECT_OPERATION_DOESNT_UPDATE_METADATACHANGE_TIMESTAMP(const fspp::Node &node, std::function<void()> operation) {
ensureNodeTimestampsAreOld(node);
timespec oldTime = stat(node).st_ctim;
operation();
timespec newTime = stat(node).st_ctim;
EXPECT_EQ(oldTime, newTime);
}
void EXPECT_OPERATION_UPDATES_ACCESS_TIMESTAMP(const fspp::Node &node, std::function<void()> operation) {
ensureNodeTimestampsAreOld(node);
timespec lowerBound = cpputils::time::now();
operation();
timespec upperBound = cpputils::time::now();
EXPECT_ACCESS_TIMESTAMP_BETWEEN(lowerBound, upperBound, node);
}
void EXPECT_OPERATION_UPDATES_MODIFICATION_TIMESTAMP(const fspp::Node &node, std::function<void()> operation) {
ensureNodeTimestampsAreOld(node);
timespec lowerBound = cpputils::time::now();
operation();
timespec upperBound = cpputils::time::now();
EXPECT_MODIFICATION_TIMESTAMP_BETWEEN(lowerBound, upperBound, node);
}
void EXPECT_OPERATION_UPDATES_METADATACHANGE_TIMESTAMP(const fspp::Node &node, std::function<void()> operation) {
ensureNodeTimestampsAreOld(node);
timespec lowerBound = cpputils::time::now();
operation();
timespec upperBound = cpputils::time::now();
EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, node);
}
void EXPECT_OPERATION_DOESNT_UPDATE_TIMESTAMPS(const fspp::Node &node, std::function<void()> operation) {
EXPECT_OPERATION_DOESNT_UPDATE_ACCESS_TIMESTAMP(node, operation);
EXPECT_OPERATION_DOESNT_UPDATE_MODIFICATION_TIMESTAMP(node, operation);
EXPECT_OPERATION_DOESNT_UPDATE_METADATACHANGE_TIMESTAMP(node, operation);
}
struct stat stat(const fspp::Node &node) {
struct stat st;
node.stat(&st);
return st;
}
timespec xSecondsAgo(int sec) {
timespec result = cpputils::time::now();
result.tv_sec -= sec;
return result;
}
private:
void ensureNodeTimestampsAreOld(const fspp::Node &node) {
waitUntilClockProgresses();
EXPECT_LT(stat(node).st_atim, cpputils::time::now());
EXPECT_LT(stat(node).st_mtim, cpputils::time::now());
EXPECT_LT(stat(node).st_ctim, cpputils::time::now());
}
void waitUntilClockProgresses() {
auto start = cpputils::time::now();
while (start == cpputils::time::now()) {
// busy waiting is the fastest, we only have to wait for a nanosecond increment.
}
}
};
#endif