summaryrefslogtreecommitdiff
path: root/unittests/core.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/core.cpp')
-rw-r--r--unittests/core.cpp340
1 files changed, 306 insertions, 34 deletions
diff --git a/unittests/core.cpp b/unittests/core.cpp
index aad6b65..78be8d7 100644
--- a/unittests/core.cpp
+++ b/unittests/core.cpp
@@ -1,69 +1,341 @@
#define BOOST_TEST_MODULE GitFS_Core
#include <boost/test/unit_test.hpp>
+#include <boost/test/data/test_case.hpp>
#include "mockDefs.h"
#include "sys/stat.h"
+#include "sys/fcntl.h"
using namespace GitFS;
using namespace GitFS::Test;
+namespace std {
+ std::ostream & operator<<(std::ostream & strm, const std::tuple<std::string, int> &)
+ {
+ return strm;
+ }
+
+ template<typename T>
+ std::ostream & operator<<(std::ostream & strm, const std::vector<T> & v)
+ {
+ strm << "[ ";
+ for (const auto & e : v) {
+ if (&e != &v.front()) {
+ strm << ", ";
+ }
+ strm << e;
+ }
+ strm << " ]";
+ return strm;
+ }
+}
+
+#define BOOST_CHECK_THROW_SYSTEMERROR(CODE, ERRNO) \
+ try { \
+ BOOST_TEST_CHECKPOINT(""); \
+ [&](){ CODE ; }(); \
+ BOOST_ERROR("No exception thrown, NetFS::SystemError expected"); \
+ } catch (const NetFS::SystemError & se) { \
+ BOOST_CHECK_EQUAL(se.syserrno, ERRNO); \
+ } catch (...) { \
+ BOOST_ERROR("NetFS::SystemError not thrown"); \
+ }\
+
BOOST_TEST_GLOBAL_FIXTURE(Service);
-BOOST_FIXTURE_TEST_SUITE(client, Client)
+BOOST_FIXTURE_TEST_SUITE(client, Client);
// TODO
BOOST_AUTO_TEST_SUITE_END();
-BOOST_FIXTURE_TEST_SUITE(volume, VolumeClient)
+BOOST_FIXTURE_TEST_SUITE(volume, VolumeClient);
-BOOST_AUTO_TEST_CASE( access )
+BOOST_AUTO_TEST_CASE( unsupported_rofs_ops )
{
- // Noting is writable
- // Directories are all readable and executable
+ BOOST_CHECK_THROW_SYSTEMERROR(v->create(env, {}, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->truncate(env, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->unlink(env, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->mkdir(env, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->rmdir(env, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->mknod(env, {}, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->symlink(env, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->link(env, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->rename(env, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->chmod(env, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->chown(env, {}, {}, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->utimens(env, {}, {}, {}, {}, {}), EROFS);
+}
- BOOST_CHECK_EQUAL(EINVAL, v->access(env, "", R_OK));
+BOOST_AUTO_TEST_CASE( statfs )
+{
+ // Don't know what this should return, but it shouldn't error given a valid path
+ BOOST_CHECK_THROW_SYSTEMERROR(v->statfs(env, ""), EINVAL);
+ BOOST_CHECK_NO_THROW(v->statfs(env, "/"));
+}
- BOOST_CHECK_EQUAL(0, v->access(env, "/", R_OK));
- BOOST_CHECK_EQUAL(EACCES, v->access(env, "/", W_OK));
- BOOST_CHECK_EQUAL(0, v->access(env, "/", X_OK));
+namespace btdata = boost::unit_test::data;
+const auto INVALIDPATHS = btdata::make({
+ ""
+});
+const auto BADPATHS = btdata::make({
+ "/.",
+ "/../",
+ ".",
+ "..",
+ "../",
+});
+const auto DIRPATHS = btdata::make({
+ "/",
+ "/src",
+ "/unittests",
+ "/unittests/fixtures",
+});
+const auto REGPATHS = btdata::make({
+ "/.gitignore",
+ "/Jamroot.jam",
+ "/src/Jamfile.jam",
+ "/unittests/Jamfile.jam",
+});
+const auto EXECPATHS = btdata::make({
+ "/unittests/fixtures/executable",
+});
+const auto LINKPATHS = btdata::make({
+ "/unittests/fixtures/symlink",
+});
+const auto MISSINGPATHS = btdata::make({
+ "/.missing",
+ "/missing",
+ "/src/missing",
+ "/unittests/fixtures/missing",
+});
- BOOST_CHECK_EQUAL(0, v->access(env, "/src", R_OK));
- BOOST_CHECK_EQUAL(EACCES, v->access(env, "/src", W_OK));
- BOOST_CHECK_EQUAL(0, v->access(env, "/src", X_OK));
+BOOST_DATA_TEST_CASE(accessWrite, INVALIDPATHS + DIRPATHS + REGPATHS + EXECPATHS + LINKPATHS + MISSINGPATHS + BADPATHS, path)
+{
+ BOOST_CHECK_EQUAL(EACCES, v->access(env, path, W_OK));
+}
+BOOST_DATA_TEST_CASE(accessDirs, DIRPATHS, path)
+{
+ BOOST_CHECK_EQUAL(0, v->access(env, path, R_OK));
+ BOOST_CHECK_EQUAL(0, v->access(env, path, X_OK));
+}
+BOOST_DATA_TEST_CASE(accessRead, REGPATHS, path)
+{
+ BOOST_CHECK_EQUAL(0, v->access(env, path, R_OK));
+ BOOST_CHECK_EQUAL(EACCES, v->access(env, path, X_OK));
+}
+BOOST_DATA_TEST_CASE(accessLink, LINKPATHS, path)
+{
+ BOOST_CHECK_EQUAL(0, v->access(env, path, R_OK));
+ BOOST_CHECK_EQUAL(0, v->access(env, path, X_OK));
+}
+BOOST_DATA_TEST_CASE(accessExec, EXECPATHS, path)
+{
+ BOOST_CHECK_EQUAL(0, v->access(env, path, R_OK));
+ BOOST_CHECK_EQUAL(0, v->access(env, path, X_OK));
+}
+BOOST_DATA_TEST_CASE( accessInval, INVALIDPATHS * btdata::make({ R_OK, X_OK }), path, mode)
+{
+ BOOST_CHECK_EQUAL(EINVAL, v->access(env, path, mode));
+}
+BOOST_DATA_TEST_CASE( accessBad, BADPATHS * btdata::make({ R_OK, X_OK }), path, mode)
+{
+ BOOST_CHECK_EQUAL(ENOENT, v->access(env, path, mode));
+}
+BOOST_DATA_TEST_CASE( statInval, INVALIDPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->getattr(env, path), EINVAL);
+}
+BOOST_DATA_TEST_CASE( statBad, BADPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->getattr(env, path), ENOENT);
+}
- BOOST_CHECK_EQUAL(0, v->access(env, "/src/Jamfile.jam", R_OK));
- BOOST_CHECK_EQUAL(EACCES, v->access(env, "/src/Jamfile.jam", W_OK));
- BOOST_CHECK_EQUAL(EACCES, v->access(env, "/src/Jamfile.jam", X_OK));
- BOOST_CHECK_EQUAL(0, v->access(env, "/unittests/fixtures/executable", R_OK));
- BOOST_CHECK_EQUAL(EACCES, v->access(env, "/unittests/fixtures/executable", W_OK));
- BOOST_CHECK_EQUAL(0, v->access(env, "/unittests/fixtures/executable", X_OK));
+const auto DIRMODE = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+const auto FILEMODE = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
+const auto EXECMODE = FILEMODE | S_IXUSR | S_IXGRP | S_IXOTH;
+const auto LINKMODE = S_IFLNK | S_IRUSR | S_IRGRP | S_IROTH;
+const time_t COMMIT_TIME = 1563621030;
+const std::string USER = "root";
+const std::string GROUP = "root";
- BOOST_CHECK_EQUAL(ENOENT, v->access(env, "/missing", R_OK));
- BOOST_CHECK_EQUAL(EACCES, v->access(env, "/missing", W_OK));
- BOOST_CHECK_EQUAL(ENOENT, v->access(env, "/missing", X_OK));
+BOOST_DATA_TEST_CASE( statDirs, DIRPATHS, path )
+{
+ const auto attr = v->getattr(env, path);
+ BOOST_CHECK_EQUAL(DIRMODE, attr.mode);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.mtime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.ctime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.atime);
+ BOOST_CHECK_EQUAL(0, attr.size);
+ BOOST_CHECK_EQUAL(USER, attr.uid);
+ BOOST_CHECK_EQUAL(GROUP, attr.gid);
+}
+BOOST_DATA_TEST_CASE( statFiles, REGPATHS, path )
+{
+ const auto attr = v->getattr(env, path);
+ BOOST_CHECK_EQUAL(FILEMODE, attr.mode);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.mtime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.ctime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.atime);
+ BOOST_CHECK_LE(4, attr.size);
+ BOOST_CHECK_EQUAL(USER, attr.uid);
+ BOOST_CHECK_EQUAL(GROUP, attr.gid);
+}
+BOOST_DATA_TEST_CASE( statExecs, EXECPATHS, path )
+{
+ const auto attr = v->getattr(env, path);
+ BOOST_CHECK_EQUAL(EXECMODE, attr.mode);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.mtime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.ctime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.atime);
+ BOOST_CHECK_LE(4, attr.size);
+ BOOST_CHECK_EQUAL(USER, attr.uid);
+ BOOST_CHECK_EQUAL(GROUP, attr.gid);
+}
+BOOST_DATA_TEST_CASE( statSymlink, LINKPATHS, path )
+{
+ const auto attr = v->getattr(env, path);
+ BOOST_CHECK_EQUAL(LINKMODE, attr.mode);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.mtime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.ctime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, attr.atime);
+ BOOST_CHECK_EQUAL(0, attr.size);
+ BOOST_CHECK_EQUAL(USER, attr.uid);
+ BOOST_CHECK_EQUAL(GROUP, attr.gid);
+}
- BOOST_CHECK_EQUAL(ENOENT, v->access(env, "/.", R_OK));
- BOOST_CHECK_EQUAL(ENOENT, v->access(env, "/../", R_OK));
- BOOST_CHECK_EQUAL(ENOENT, v->access(env, ".", R_OK));
- BOOST_CHECK_EQUAL(ENOENT, v->access(env, "..", R_OK));
- BOOST_CHECK_EQUAL(ENOENT, v->access(env, "../", R_OK));
+
+BOOST_DATA_TEST_CASE( readlinkInval, INVALIDPATHS + DIRPATHS + REGPATHS + EXECPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->readlink(env, path), EINVAL);
}
+BOOST_DATA_TEST_CASE( readlinkBad, BADPATHS + MISSINGPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->readlink(env, path), ENOENT);
+}
+BOOST_DATA_TEST_CASE( readlink, LINKPATHS ^ btdata::make({ "executable" }), path, target )
+{
+ BOOST_CHECK_EQUAL(target, v->readlink(env, path));
+}
+
+
+BOOST_DATA_TEST_CASE( openDirInval, INVALIDPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->opendir(env, path), EINVAL);
+}
+BOOST_DATA_TEST_CASE( openDirBad, BADPATHS + MISSINGPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->opendir(env, path), ENOENT);
+}
+BOOST_DATA_TEST_CASE( openDirNotDir, REGPATHS + LINKPATHS + EXECPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->opendir(env, path), ENOTDIR);
+}
+const auto DIRCONTENTS = btdata::make<std::vector<std::string>>({
+ {".gitignore", "Jamroot.jam", "src", "unittests"},
+ {"Jamfile.jam", "blob.cpp", "blob.h", "dir.cpp", "dir.h", "git.cpp", "git.h", "main.cpp", "repo.cpp", "repo.h", "repoList.cpp", "repoList.h"},
+ {"Jamfile.jam", "core.cpp", "fixtures", "mockDefs.cpp", "mockDefs.h"},
+ {"executable", "symlink"},
+});
+BOOST_DATA_TEST_CASE( openDirRead, DIRPATHS ^ DIRCONTENTS, path, contents )
+{
+ auto dir = v->opendir(env, path);
+ BOOST_REQUIRE(dir);
+ auto names = dir->readdir();
+ std::sort(names.begin(), names.end());
+ BOOST_CHECK_EQUAL_COLLECTIONS(names.begin(), names.end(), contents.begin(), contents.end());
+ dir->close();
+}
+const auto DIRCONTENTMODES = btdata::make<std::vector<std::tuple<std::string, int>>>({
+ {{".gitignore", FILEMODE}, {"Jamroot.jam", FILEMODE}, {"src",DIRMODE}, {"unittests", DIRMODE}},
+ {{"Jamfile.jam", FILEMODE}, {"blob.cpp", FILEMODE}, {"blob.h", FILEMODE}, {"dir.cpp", FILEMODE}, {"dir.h", FILEMODE}, {"git.cpp", FILEMODE}, {"git.h", FILEMODE}, {"main.cpp", FILEMODE}, {"repo.cpp", FILEMODE}, {"repo.h", FILEMODE}, {"repoList.cpp", FILEMODE}, {"repoList.h", FILEMODE}},
+ {{"Jamfile.jam", FILEMODE}, {"core.cpp", FILEMODE}, {"fixtures", DIRMODE}, {"mockDefs.cpp", FILEMODE}, {"mockDefs.h", FILEMODE}},
+ {{"executable", EXECMODE}, {"symlink", LINKMODE}},
+});
+BOOST_DATA_TEST_CASE( openDirList, DIRPATHS ^ DIRCONTENTMODES, path, contents )
+{
+ auto dir = v->opendir(env, path);
+ BOOST_REQUIRE(dir);
+ auto dir2 = Ice::checkedCast<NetFS::DirectoryV2Prx>(dir);
+ BOOST_REQUIRE(dir2);
+ auto list = dir2->listdir();
+ BOOST_REQUIRE_EQUAL(contents.size(), list.size());
+ for (const auto & c : contents) {
+ auto li = list.find(std::get<0>(c));
+ BOOST_REQUIRE(li != list.end());
+ BOOST_CHECK_EQUAL(li->second.mode, std::get<1>(c));
+ BOOST_CHECK_EQUAL(COMMIT_TIME, li->second.mtime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, li->second.ctime);
+ BOOST_CHECK_EQUAL(COMMIT_TIME, li->second.atime);
+ BOOST_CHECK_EQUAL(USER, li->second.uid);
+ BOOST_CHECK_EQUAL(GROUP, li->second.gid);
+ if (S_ISREG(li->second.mode)) {
+ BOOST_CHECK_LE(4, li->second.size);
+ }
+ }
+ dir->close();
+}
+
-BOOST_AUTO_TEST_CASE( statRoot )
+BOOST_DATA_TEST_CASE( openInval, INVALIDPATHS, path )
{
- //auto a = v->getattr(env, "/");
- //BOOST_CHECK_EQUAL(0170555, a.mode);
- //BOOST_CHECK_EQUAL(1563566842, a.mtime);
- //BOOST_CHECK_EQUAL(1563566842, a.ctime);
- //BOOST_CHECK_EQUAL(1563566842, a.atime);
+ BOOST_CHECK_THROW_SYSTEMERROR(v->open(env, path, O_RDONLY), EINVAL);
+}
+BOOST_DATA_TEST_CASE( openBad, BADPATHS + MISSINGPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->open(env, path, O_RDONLY), ENOENT);
+}
+BOOST_DATA_TEST_CASE( openNotFileDir, DIRPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->open(env, path, O_RDONLY), EISDIR);
+}
+BOOST_DATA_TEST_CASE( openNotFileLink, LINKPATHS, path )
+{
+ BOOST_CHECK_THROW_SYSTEMERROR(v->open(env, path, O_RDONLY), ELOOP);
+}
+BOOST_DATA_TEST_CASE( openFileROFSOps, REGPATHS + EXECPATHS, path )
+{
+ auto f = v->open(env, path, O_RDONLY);
+ BOOST_REQUIRE(f);
+ BOOST_CHECK_THROW_SYSTEMERROR(f->ftruncate(env, {}), EROFS);
+ BOOST_CHECK_THROW_SYSTEMERROR(f->write({}, {}, {}), EROFS);
+ f->close();
}
-BOOST_AUTO_TEST_CASE(stat_root)
+BOOST_DATA_TEST_CASE( openFileGetAttr, REGPATHS + EXECPATHS, path )
{
- auto attr = v->getattr(env, "");
+ auto f = v->open(env, path, O_RDONLY);
+ BOOST_REQUIRE(f);
+ const auto attr = f->fgetattr(env);
+ BOOST_CHECK(S_ISREG(attr.mode));
+ BOOST_CHECK_EQUAL(attr.size, attr.blocks);
+ BOOST_CHECK_EQUAL(1, attr.blockSize);
+ BOOST_CHECK_LE(4, attr.size);
+ BOOST_CHECK_EQUAL(USER, attr.uid);
+ BOOST_CHECK_EQUAL(GROUP, attr.gid);
+ f->close();
}
+BOOST_DATA_TEST_CASE( openFileRead, REGPATHS + EXECPATHS, path )
+{
+ auto f = v->open(env, path, O_RDONLY);
+ BOOST_REQUIRE(f);
+
+ const auto attr = f->fgetattr(env);
+
+ const auto readAll = f->read(0, attr.size);
+ BOOST_CHECK_EQUAL(attr.size, readAll.size());
+
+ const auto readTrunc = f->read(0, BUFSIZ);
+ BOOST_CHECK_EQUAL(attr.size, readTrunc.size());
+
+ const auto readBeyond = f->read(BUFSIZ, BUFSIZ);
+ BOOST_CHECK(readBeyond.empty());
+
+ f->close();
+}
+
+
BOOST_AUTO_TEST_SUITE_END();