From 67684b3a9a7205cef15f5978b5adc4df632f5af5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 21 Jul 2019 13:54:41 +0100 Subject: Basically all the core functionality --- unittests/core.cpp | 340 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 306 insertions(+), 34 deletions(-) (limited to 'unittests/core.cpp') 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 +#include #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 &) + { + return strm; + } + + template + std::ostream & operator<<(std::ostream & strm, const std::vector & 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>({ + {".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>>({ + {{".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(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(); -- cgit v1.2.3