Commit 897c31d4 authored by Ramon Nou's avatar Ramon Nou Committed by Ramon Nou
Browse files

access and statfs coverage

SEEK CUR lseek, removed tests_example
parent 7d5d957a
......@@ -131,7 +131,7 @@ gkfs:integration:
needs: ['gkfs']
parallel:
matrix:
- SUBTEST: [ data, directories, operations, position, shell, status, coverage ]
- SUBTEST: [ data, status, coverage, directories, operations, position, shell ]
script:
## run tests
......
......@@ -76,8 +76,52 @@ def test_open_error(gkfs_daemon, gkfs_client):
# Open unexistent file
ret = ret = gkfs_client.open(file3, os.O_WRONLY)
ret = gkfs_client.open(file3, os.O_WRONLY)
assert ret.retval == -1
assert ret.errno == errno.ENOENT
\ No newline at end of file
def test_access_error(gkfs_daemon, gkfs_client):
file = gkfs_daemon.mountdir / "file"
file2 = gkfs_daemon.mountdir / "file2"
ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY)
assert ret.retval == 10000
# Access, flags are not being used
ret = gkfs_client.access(file2, os.R_OK)
assert ret.retval == -1
assert ret.errno == errno.ENOENT
ret = gkfs_client.access(file, os.R_OK)
assert ret.retval != -1
def test_stat_error(gkfs_daemon, gkfs_client):
# Stat non existing file
file = gkfs_daemon.mountdir / "file"
ret = gkfs_client.stat(file)
assert ret.retval == -1
assert ret.errno == errno.ENOENT
# test statx on existing file
ret = gkfs_client.statx(0, file, 0, 0)
assert ret.retval == -1
assert ret.errno == errno.ENOENT
def test_statfs(gkfs_daemon, gkfs_client):
# Statfs check most of the outputs
ret = gkfs_client.statfs(gkfs_daemon.mountdir)
assert ret.retval == 0
assert ret.statfsbuf.f_type == 0
assert ret.statfsbuf.f_bsize != 0
assert ret.statfsbuf.f_blocks != 0
assert ret.statfsbuf.f_bfree != 0
assert ret.statfsbuf.f_bavail != 0
assert ret.statfsbuf.f_files == 0
assert ret.statfsbuf.f_ffree == 0
\ No newline at end of file
......@@ -63,6 +63,8 @@ add_executable(gkfs.io
gkfs.io/symlink.cpp
gkfs.io/directory_validate.cpp
gkfs.io/unlink.cpp
gkfs.io/access.cpp
gkfs.io/statfs.cpp
)
include(FetchContent)
......
......@@ -26,20 +26,80 @@
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <catch2/catch.hpp>
/* C++ includes */
#include <CLI11/CLI11.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <reflection.hpp>
#include <serialize.hpp>
unsigned int Factorial( unsigned int number ) {
return number <= 1 ? number : Factorial(number-1)*number;
/* C includes */
#include <sys/types.h>
#include <unistd.h>
using json = nlohmann::json;
struct access_options {
bool verbose{};
std::string path{};
int mask{};
REFL_DECL_STRUCT(access_options, REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, path),
REFL_DECL_MEMBER(int, mask));
};
struct access_output {
int retval;
int errnum;
REFL_DECL_STRUCT(access_output, REFL_DECL_MEMBER(int, retval),
REFL_DECL_MEMBER(int, errnum));
};
void
to_json(json& record, const access_output& out) {
record = serialize(out);
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
void
access_exec(const access_options& opts) {
auto rv = ::access(opts.path.c_str(), opts.mask);
if(rv == -1) {
if(opts.verbose) {
fmt::print(
"access(path=\"{}\", mask={}) = {}, errno: {} [{}]\n",
opts.path, opts.mask, rv, errno, ::strerror(errno));
return;
}
}
json out = access_output{rv, errno};
fmt::print("{}\n", out.dump(2));
}
TEST_CASE( "Two and Two is Four", "[2+2=4]" ) {
REQUIRE( 2+2 == 4 );
void
access_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<access_options>();
auto* cmd = app.add_subcommand("access",
"Execute the access() system call");
// Add options to cmd, binding them to opts
cmd->add_flag("-v,--verbose", opts->verbose,
"Produce human writeable output");
cmd->add_option("path", opts->path, "Path to file")
->required()
->type_name("");
cmd->add_option("mask", opts->mask,
"Mask to apply to the access check")
->required()
->type_name("");
cmd->callback([opts]() { access_exec(*opts); });
}
......@@ -96,6 +96,12 @@ write_random_init(CLI::App& app);
void
truncate_init(CLI::App& app);
void
access_init(CLI::App& app);
void
statfs_init(CLI::App& app);
// UTIL
void
file_compare_init(CLI::App& app);
......
......@@ -57,6 +57,8 @@ init_commands(CLI::App& app) {
directory_validate_init(app);
write_random_init(app);
truncate_init(app);
access_init(app);
statfs_init(app);
// utils
file_compare_init(app);
chdir_init(app);
......
......@@ -34,6 +34,7 @@
extern "C" {
#include <sys/stat.h>
#include <sys/vfs.h>
}
template <typename T>
......@@ -171,6 +172,21 @@ struct adl_serializer<struct ::stat> {
}
};
// ADL specialization for struct ::statfs (not exhaustive) type
template <>
struct adl_serializer<struct ::statfs> {
static void
to_json(json& j, const struct ::statfs opt) {
j = json{{"f_type", opt.f_type},
{"f_bsize", opt.f_bsize},
{"f_blocks", opt.f_blocks},
{"f_bfree", opt.f_bfree},
{"f_bavail", opt.f_bavail},
{"f_files", opt.f_files},
{"f_ffree", opt.f_ffree}};
}
};
#ifdef STATX_TYPE
// ADL specialization for struct ::statx type
template <>
......
......@@ -26,48 +26,76 @@
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <catch2/catch.hpp>
/* C++ includes */
#include <CLI11/CLI11.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>
using json = nlohmann::json;
struct statfs_options {
bool verbose{};
std::string pathname;
REFL_DECL_STRUCT(statfs_options, REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname));
};
struct statfs_output {
int retval;
int errnum;
struct ::statfs statfsbuf;
REFL_DECL_STRUCT(statfs_output, REFL_DECL_MEMBER(int, retval),
REFL_DECL_MEMBER(int, errnum),
REFL_DECL_MEMBER(struct ::statfs, statfsbuf));
};
void
to_json(json& record, const statfs_output& out) {
record = serialize(out);
}
void
statfs_exec(const statfs_options& opts) {
struct ::statfs statfsbuf;
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
GIVEN( "A vector with some items" ) {
std::vector<int> v( 5 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
WHEN( "the size is increased" ) {
v.resize( 10 );
THEN( "the size and capacity change" ) {
REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
}
}
WHEN( "the size is reduced" ) {
v.resize( 0 );
THEN( "the size changes but not capacity" ) {
REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 );
}
}
WHEN( "more capacity is reserved" ) {
v.reserve( 10 );
THEN( "the capacity changes but not the size" ) {
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 );
}
}
WHEN( "less capacity is reserved" ) {
v.reserve( 0 );
THEN( "neither size nor capacity are changed" ) {
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
}
}
auto rv = ::statfs(opts.pathname.c_str(), &statfsbuf);
if(opts.verbose) {
fmt::print("statfs(pathname=\"{}\") = {}, errno: {} [{}]\n",
opts.pathname, rv, errno, ::strerror(errno));
return;
}
json out = statfs_output{rv, errno, statfsbuf};
fmt::print("{}\n", out.dump(2));
}
void
statfs_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<statfs_options>();
auto* cmd = app.add_subcommand("statfs", "Execute the statfs() system call");
// Add options to cmd, binding them to opts
cmd->add_flag("-v,--verbose", opts->verbose,
"Produce human readable output");
cmd->add_option("pathname", opts->pathname, "Directory name")
->required()
->type_name("");
cmd->callback([opts]() { statfs_exec(*opts); });
}
......@@ -83,6 +83,27 @@ class StructStatSchema(Schema):
'st_atim', 'st_mtim', 'st_ctim'])(**data)
class StructStatfsSchema(Schema):
"""Schema that deserializes a struct statfs"""
f_type = fields.Integer(required=True)
f_bsize = fields.Integer(required=True)
f_blocks = fields.Integer(required=True)
f_bfree = fields.Integer(required=True)
f_bavail = fields.Integer(required=True)
f_files = fields.Integer(required=True)
f_ffree = fields.Integer(required=True)
# f_fsid = fields.Integer(required=True)
# f_namelen = fields.Integer(required=True)
# f_frsize = fields.Integer(required=True)
# f_flags = fields.Integer(required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('StructStatfs',
['f_type', 'f_bsize', 'f_blocks', 'f_bfree',
'f_bavail', 'f_files', 'f_ffree'])(**data)
class StructStatxTimestampSchema(Schema):
"""Schema that deserializes a struct timespec"""
tv_sec = fields.Integer(required=True)
......@@ -298,6 +319,16 @@ class StatxOutputSchema(Schema):
def make_object(self, data, **kwargs):
return namedtuple('StatxReturn', ['retval', 'statbuf', 'errno'])(**data)
class StatfsOutputSchema(Schema):
"""Schema to deserialize the results of a statfs() execution"""
retval = fields.Integer(required=True)
statfsbuf = fields.Nested(StructStatfsSchema, required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('StatfsReturn', ['retval', 'statfsbuf', 'errno'])(**data)
class LseekOutputSchema(Schema):
"""Schema to deserialize the results of an lseek() execution"""
......@@ -349,6 +380,16 @@ class TruncateOutputSchema(Schema):
def make_object(self, data, **kwargs):
return namedtuple('TruncateReturn', ['retval', 'errno'])(**data)
class AccessOutputSchema(Schema):
"""Schema to deserialize the results of an access() execution"""
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('AccessReturn', ['retval', 'errno'])(**data)
class ChdirOutputSchema(Schema):
"""Schema to deserialize the results of an chdir() execution"""
......@@ -429,6 +470,8 @@ class IOParser:
'truncate': TruncateOutputSchema(),
'directory_validate' : DirectoryValidateOutputSchema(),
'unlink' : UnlinkOutputSchema(),
'access' : AccessOutputSchema(),
'statfs' : StatfsOutputSchema(),
# UTIL
'file_compare': FileCompareOutputSchema(),
'chdir' : ChdirOutputSchema(),
......
......@@ -94,6 +94,9 @@ def test_lseek(gkfs_daemon, gkfs_client):
ret = gkfs_client.lseek(file_a, 5, os.SEEK_SET)
assert ret.retval == 5
ret = gkfs_client.lseek(file_a, 2, os.SEEK_CUR)
assert ret.retval == 2
# Size needs to be 0
ret = gkfs_client.stat(file_a)
......
......@@ -62,8 +62,6 @@ target_link_libraries(catch2_main
add_executable(tests)
target_sources(tests
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/test_example_00.cpp
${CMAKE_CURRENT_LIST_DIR}/test_example_01.cpp
${CMAKE_CURRENT_LIST_DIR}/test_utils_arithmetic.cpp
${CMAKE_CURRENT_LIST_DIR}/test_helpers.cpp)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment