From 7d5d957aee24b296e748d9fd8a5bc25bce8c1096 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Mon, 16 May 2022 09:32:08 +0200 Subject: [PATCH 01/16] Open Flags Error Open errors add subtest --- .gitlab-ci.yml | 2 +- tests/integration/CMakeLists.txt | 15 ++++ .../coverage/test_error_operations.py | 83 +++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/integration/coverage/test_error_operations.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f10ab485a..a1c083a26 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -131,7 +131,7 @@ gkfs:integration: needs: ['gkfs'] parallel: matrix: - - SUBTEST: [ data, directories, operations, position, shell, status ] + - SUBTEST: [ data, directories, operations, position, shell, status, coverage ] script: ## run tests diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index 497a8e558..7b0c2a677 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -120,6 +120,13 @@ gkfs_add_python_test( SOURCE data/ ) +gkfs_add_python_test( + NAME test_coverage + PYTHON_VERSION 3.6 + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/integration + SOURCE coverage/ +) + if(GKFS_INSTALL_TESTS) install(DIRECTORY harness DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration @@ -182,6 +189,14 @@ if(GKFS_INSTALL_TESTS) PATTERN ".pytest_cache" EXCLUDE ) + install(DIRECTORY coverage + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration + FILES_MATCHING + REGEX ".*\\.py" + PATTERN "__pycache__" EXCLUDE + PATTERN ".pytest_cache" EXCLUDE +) + install(DIRECTORY shell DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration FILES_MATCHING diff --git a/tests/integration/coverage/test_error_operations.py b/tests/integration/coverage/test_error_operations.py new file mode 100644 index 000000000..719bcbbcc --- /dev/null +++ b/tests/integration/coverage/test_error_operations.py @@ -0,0 +1,83 @@ +################################################################################ +# Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain # +# Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany # +# # +# This software was partially supported by the # +# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # +# # +# This software was partially supported by the # +# ADA-FS project under the SPPEXA project funded by the DFG. # +# # +# This file is part of GekkoFS. # +# # +# GekkoFS is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# GekkoFS is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with GekkoFS. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + +import harness +from pathlib import Path +import errno +import stat +import os +import ctypes +import sh +import sys +import pytest +from harness.logger import logger + +nonexisting = "nonexisting" + + +def test_open_error(gkfs_daemon, gkfs_client): + + file = gkfs_daemon.mountdir / "file" + file2 = gkfs_daemon.mountdir / "file2" + file3 = gkfs_daemon.mountdir / "file3" + + flags = [os.O_PATH, os.O_APPEND, os.O_CREAT | os.O_DIRECTORY] + # create a file in gekkofs + + for flag in flags: + ret = gkfs_client.open(file, + flag, + stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + + assert ret.retval == -1 + assert ret.errno == errno.ENOTSUP + + + # Create file and recreate + ret = gkfs_client.open(file, os.O_CREAT | os.O_EXCL | os.O_WRONLY) + assert ret.retval == 10000 + + ret = gkfs_client.open(file, os.O_CREAT | os.O_EXCL | os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.EEXIST + + + # Create file and recreate + ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + # Undefined in man + ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + + # Open unexistent file + ret = ret = gkfs_client.open(file3, os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.ENOENT + + \ No newline at end of file -- GitLab From 897c31d4d1835d14aa54c292800859f908da96bb Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Mon, 16 May 2022 14:17:35 +0200 Subject: [PATCH 02/16] access and statfs coverage SEEK CUR lseek, removed tests_example --- .gitlab-ci.yml | 2 +- .../coverage/test_error_operations.py | 48 +++++++- tests/integration/harness/CMakeLists.txt | 2 + tests/integration/harness/gkfs.io/access.cpp | 105 ++++++++++++++++++ .../integration/harness/gkfs.io/commands.hpp | 6 + tests/integration/harness/gkfs.io/main.cpp | 2 + .../integration/harness/gkfs.io/serialize.hpp | 16 +++ tests/integration/harness/gkfs.io/statfs.cpp | 101 +++++++++++++++++ tests/integration/harness/io.py | 43 +++++++ tests/integration/position/test_lseek.py | 3 + tests/unit/CMakeLists.txt | 2 - tests/unit/test_example_00.cpp | 45 -------- tests/unit/test_example_01.cpp | 73 ------------ 13 files changed, 325 insertions(+), 123 deletions(-) create mode 100644 tests/integration/harness/gkfs.io/access.cpp create mode 100644 tests/integration/harness/gkfs.io/statfs.cpp delete mode 100644 tests/unit/test_example_00.cpp delete mode 100644 tests/unit/test_example_01.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a1c083a26..768c92bd5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -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 diff --git a/tests/integration/coverage/test_error_operations.py b/tests/integration/coverage/test_error_operations.py index 719bcbbcc..fc6421ec6 100644 --- a/tests/integration/coverage/test_error_operations.py +++ b/tests/integration/coverage/test_error_operations.py @@ -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 diff --git a/tests/integration/harness/CMakeLists.txt b/tests/integration/harness/CMakeLists.txt index 30bae73e6..ab7400a10 100644 --- a/tests/integration/harness/CMakeLists.txt +++ b/tests/integration/harness/CMakeLists.txt @@ -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) diff --git a/tests/integration/harness/gkfs.io/access.cpp b/tests/integration/harness/gkfs.io/access.cpp new file mode 100644 index 000000000..49464d7ce --- /dev/null +++ b/tests/integration/harness/gkfs.io/access.cpp @@ -0,0 +1,105 @@ +/* + Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +/* C++ includes */ +#include +#include +#include +#include +#include +#include + +/* C includes */ +#include +#include + +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); +} + +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)); +} + +void +access_init(CLI::App& app) { + + // Create the option and subcommand objects + auto opts = std::make_shared(); + 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); }); +} diff --git a/tests/integration/harness/gkfs.io/commands.hpp b/tests/integration/harness/gkfs.io/commands.hpp index e489a44b6..401fc7da1 100644 --- a/tests/integration/harness/gkfs.io/commands.hpp +++ b/tests/integration/harness/gkfs.io/commands.hpp @@ -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); diff --git a/tests/integration/harness/gkfs.io/main.cpp b/tests/integration/harness/gkfs.io/main.cpp index c737722a9..fbe0228b1 100644 --- a/tests/integration/harness/gkfs.io/main.cpp +++ b/tests/integration/harness/gkfs.io/main.cpp @@ -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); diff --git a/tests/integration/harness/gkfs.io/serialize.hpp b/tests/integration/harness/gkfs.io/serialize.hpp index 5786c32ee..f7d7d425b 100644 --- a/tests/integration/harness/gkfs.io/serialize.hpp +++ b/tests/integration/harness/gkfs.io/serialize.hpp @@ -34,6 +34,7 @@ extern "C" { #include +#include } template @@ -171,6 +172,21 @@ struct adl_serializer { } }; +// ADL specialization for struct ::statfs (not exhaustive) type +template <> +struct adl_serializer { + 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 <> diff --git a/tests/integration/harness/gkfs.io/statfs.cpp b/tests/integration/harness/gkfs.io/statfs.cpp new file mode 100644 index 000000000..3ef6675d3 --- /dev/null +++ b/tests/integration/harness/gkfs.io/statfs.cpp @@ -0,0 +1,101 @@ +/* + Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +/* C++ includes */ +#include +#include +#include +#include +#include +#include +#include + +/* C includes */ +#include +#include +#include + +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; + + 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(); + 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); }); +} diff --git a/tests/integration/harness/io.py b/tests/integration/harness/io.py index 7b65adc23..b17b4afa4 100644 --- a/tests/integration/harness/io.py +++ b/tests/integration/harness/io.py @@ -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(), diff --git a/tests/integration/position/test_lseek.py b/tests/integration/position/test_lseek.py index dd96ca9ec..125b6734e 100644 --- a/tests/integration/position/test_lseek.py +++ b/tests/integration/position/test_lseek.py @@ -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) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 5d00c8b27..1bcff84ef 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -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) diff --git a/tests/unit/test_example_00.cpp b/tests/unit/test_example_00.cpp deleted file mode 100644 index 1b615220b..000000000 --- a/tests/unit/test_example_00.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain - Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany - - This software was partially supported by the - EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). - - This software was partially supported by the - ADA-FS project under the SPPEXA project funded by the DFG. - - This file is part of GekkoFS. - - GekkoFS is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GekkoFS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GekkoFS. If not, see . - - SPDX-License-Identifier: GPL-3.0-or-later -*/ - -#include -#include - -unsigned int Factorial( unsigned int number ) { - return number <= 1 ? number : Factorial(number-1)*number; -} - -TEST_CASE( "Factorials are computed", "[factorial]" ) { - REQUIRE( Factorial(1) == 1 ); - REQUIRE( Factorial(2) == 2 ); - REQUIRE( Factorial(3) == 6 ); - REQUIRE( Factorial(10) == 3628800 ); -} - -TEST_CASE( "Two and Two is Four", "[2+2=4]" ) { - REQUIRE( 2+2 == 4 ); -} diff --git a/tests/unit/test_example_01.cpp b/tests/unit/test_example_01.cpp deleted file mode 100644 index bef585f44..000000000 --- a/tests/unit/test_example_01.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain - Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany - - This software was partially supported by the - EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). - - This software was partially supported by the - ADA-FS project under the SPPEXA project funded by the DFG. - - This file is part of GekkoFS. - - GekkoFS is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GekkoFS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GekkoFS. If not, see . - - SPDX-License-Identifier: GPL-3.0-or-later -*/ - -#include -#include - -SCENARIO( "vectors can be sized and resized", "[vector]" ) { - - GIVEN( "A vector with some items" ) { - std::vector 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 ); - } - } - } -} -- GitLab From 90e03f6c370f7bd02026457c9db728db4ea7c27a Mon Sep 17 00:00:00 2001 From: rnou Date: Tue, 17 May 2022 11:45:59 +0200 Subject: [PATCH 03/16] GCC 12.1 update and statvfs Added statvfs in tests enable extra features in gekkofs --- .gitlab-ci.yml | 6 ++ include/client/open_file_map.hpp | 1 + .../coverage/test_error_operations.py | 15 +++ tests/integration/harness/CMakeLists.txt | 1 + .../integration/harness/gkfs.io/commands.hpp | 3 + tests/integration/harness/gkfs.io/main.cpp | 1 + .../integration/harness/gkfs.io/serialize.hpp | 17 +++ tests/integration/harness/gkfs.io/statvfs.cpp | 101 ++++++++++++++++++ tests/integration/harness/io.py | 34 ++++++ 9 files changed, 179 insertions(+) create mode 100644 tests/integration/harness/gkfs.io/statvfs.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 768c92bd5..9624b7e20 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,6 +49,12 @@ gkfs: interruptible: true needs: [] script: + # Change config.hpp with sed to enable extra features + - sed -i 's/\/\/constexpr auto use_atime = false;/constexpr auto use_atime = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" + - sed -i 's/\/\/constexpr auto use_ctime = false;/constexpr auto use_ctime = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" + - sed -i 's/\/\/constexpr auto use_mtime = false;/constexpr auto use_mtime = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" + - sed -i 's/\/\/constexpr auto use_link_cnt = false;/constexpr auto use_link_cnt = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" + - sed -i 's/\/\/constexpr auto use_blocks = false;/constexpr auto use_blocks = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" - mkdir -p ${BUILD_PATH} && cd ${BUILD_PATH} - cmake -Wdev diff --git a/include/client/open_file_map.hpp b/include/client/open_file_map.hpp index 2da1d0806..cc67913b5 100644 --- a/include/client/open_file_map.hpp +++ b/include/client/open_file_map.hpp @@ -34,6 +34,7 @@ #include #include #include +#include namespace gkfs::filemap { diff --git a/tests/integration/coverage/test_error_operations.py b/tests/integration/coverage/test_error_operations.py index fc6421ec6..3ef1e3bbf 100644 --- a/tests/integration/coverage/test_error_operations.py +++ b/tests/integration/coverage/test_error_operations.py @@ -26,6 +26,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later # ################################################################################ +from sre_parse import State import harness from pathlib import Path import errno @@ -80,6 +81,9 @@ def test_open_error(gkfs_daemon, gkfs_client): assert ret.retval == -1 assert ret.errno == errno.ENOENT + ret = gkfs_client.open(file3, os.O_CREAT | stat.S_IFSOCK | os.O_EXCL | os.O_WRONLY) + assert ret.retval == 10000 + def test_access_error(gkfs_daemon, gkfs_client): file = gkfs_daemon.mountdir / "file" @@ -123,5 +127,16 @@ def test_statfs(gkfs_daemon, gkfs_client): assert ret.statfsbuf.f_ffree == 0 +def test_statvfs(gkfs_daemon, gkfs_client): + # Statfs check most of the outputs + + ret = gkfs_client.statvfs(gkfs_daemon.mountdir) + assert ret.retval == 0 + assert ret.statvfsbuf.f_bsize != 0 + assert ret.statvfsbuf.f_blocks != 0 + assert ret.statvfsbuf.f_bfree != 0 + assert ret.statvfsbuf.f_bavail != 0 + assert ret.statvfsbuf.f_files == 0 + assert ret.statvfsbuf.f_ffree == 0 \ No newline at end of file diff --git a/tests/integration/harness/CMakeLists.txt b/tests/integration/harness/CMakeLists.txt index ab7400a10..5a66618a5 100644 --- a/tests/integration/harness/CMakeLists.txt +++ b/tests/integration/harness/CMakeLists.txt @@ -65,6 +65,7 @@ add_executable(gkfs.io gkfs.io/unlink.cpp gkfs.io/access.cpp gkfs.io/statfs.cpp + gkfs.io/statvfs.cpp ) include(FetchContent) diff --git a/tests/integration/harness/gkfs.io/commands.hpp b/tests/integration/harness/gkfs.io/commands.hpp index 401fc7da1..fa5843504 100644 --- a/tests/integration/harness/gkfs.io/commands.hpp +++ b/tests/integration/harness/gkfs.io/commands.hpp @@ -102,6 +102,9 @@ access_init(CLI::App& app); void statfs_init(CLI::App& app); +void +statvfs_init(CLI::App& app); + // UTIL void file_compare_init(CLI::App& app); diff --git a/tests/integration/harness/gkfs.io/main.cpp b/tests/integration/harness/gkfs.io/main.cpp index fbe0228b1..a1f71ec37 100644 --- a/tests/integration/harness/gkfs.io/main.cpp +++ b/tests/integration/harness/gkfs.io/main.cpp @@ -59,6 +59,7 @@ init_commands(CLI::App& app) { truncate_init(app); access_init(app); statfs_init(app); + statvfs_init(app); // utils file_compare_init(app); chdir_init(app); diff --git a/tests/integration/harness/gkfs.io/serialize.hpp b/tests/integration/harness/gkfs.io/serialize.hpp index f7d7d425b..68971ad4f 100644 --- a/tests/integration/harness/gkfs.io/serialize.hpp +++ b/tests/integration/harness/gkfs.io/serialize.hpp @@ -35,6 +35,7 @@ extern "C" { #include #include +#include } template @@ -187,6 +188,22 @@ struct adl_serializer { } }; +// ADL specialization for struct ::statvfs (not exhaustive) type +template <> +struct adl_serializer { + static void + to_json(json& j, const struct ::statvfs opt) { + j = json{ + {"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}, + {"f_favail", opt.f_favail}}; + } +}; + #ifdef STATX_TYPE // ADL specialization for struct ::statx type template <> diff --git a/tests/integration/harness/gkfs.io/statvfs.cpp b/tests/integration/harness/gkfs.io/statvfs.cpp new file mode 100644 index 000000000..1161b9dd7 --- /dev/null +++ b/tests/integration/harness/gkfs.io/statvfs.cpp @@ -0,0 +1,101 @@ +/* + Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +/* C++ includes */ +#include +#include +#include +#include +#include +#include +#include + +/* C includes */ +#include +#include +#include + +using json = nlohmann::json; + +struct statvfs_options { + bool verbose{}; + std::string pathname; + + REFL_DECL_STRUCT(statvfs_options, REFL_DECL_MEMBER(bool, verbose), + REFL_DECL_MEMBER(std::string, pathname)); +}; + +struct statvfs_output { + int retval; + int errnum; + struct ::statvfs statvfsbuf; + + REFL_DECL_STRUCT(statvfs_output, REFL_DECL_MEMBER(int, retval), + REFL_DECL_MEMBER(int, errnum), + REFL_DECL_MEMBER(struct ::statvfs, statvfsbuf)); +}; + +void +to_json(json& record, const statvfs_output& out) { + record = serialize(out); +} + +void +statvfs_exec(const statvfs_options& opts) { + + struct ::statvfs statvfsbuf; + + auto rv = ::statvfs(opts.pathname.c_str(), &statvfsbuf); + + if(opts.verbose) { + fmt::print("statvfs(pathname=\"{}\") = {}, errno: {} [{}]\n", + opts.pathname, rv, errno, ::strerror(errno)); + return; + } + + json out = statvfs_output{rv, errno, statvfsbuf}; + fmt::print("{}\n", out.dump(2)); +} + +void +statvfs_init(CLI::App& app) { + + // Create the option and subcommand objects + auto opts = std::make_shared(); + auto* cmd = app.add_subcommand("statvfs", "Execute the statvfs() 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]() { statvfs_exec(*opts); }); +} diff --git a/tests/integration/harness/io.py b/tests/integration/harness/io.py index b17b4afa4..c9b4d47be 100644 --- a/tests/integration/harness/io.py +++ b/tests/integration/harness/io.py @@ -104,6 +104,28 @@ class StructStatfsSchema(Schema): ['f_type', 'f_bsize', 'f_blocks', 'f_bfree', 'f_bavail', 'f_files', 'f_ffree'])(**data) + +class StructStatvfsSchema(Schema): + """Schema that deserializes a struct statvfs""" + + 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_favail = 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_bsize', 'f_blocks', 'f_bfree', + 'f_bavail', 'f_files', 'f_ffree', 'f_favail'])(**data) + class StructStatxTimestampSchema(Schema): """Schema that deserializes a struct timespec""" tv_sec = fields.Integer(required=True) @@ -330,6 +352,17 @@ class StatfsOutputSchema(Schema): def make_object(self, data, **kwargs): return namedtuple('StatfsReturn', ['retval', 'statfsbuf', 'errno'])(**data) +class StatvfsOutputSchema(Schema): + """Schema to deserialize the results of a statfs() execution""" + + retval = fields.Integer(required=True) + statvfsbuf = fields.Nested(StructStatvfsSchema, required=True) + errno = Errno(data_key='errnum', required=True) + + @post_load + def make_object(self, data, **kwargs): + return namedtuple('StatvfsReturn', ['retval', 'statvfsbuf', 'errno'])(**data) + class LseekOutputSchema(Schema): """Schema to deserialize the results of an lseek() execution""" retval = fields.Integer(required=True) @@ -472,6 +505,7 @@ class IOParser: 'unlink' : UnlinkOutputSchema(), 'access' : AccessOutputSchema(), 'statfs' : StatfsOutputSchema(), + 'statvfs' : StatvfsOutputSchema(), # UTIL 'file_compare': FileCompareOutputSchema(), 'chdir' : ChdirOutputSchema(), -- GitLab From 3574e007fd4fb6ff0b924e0ebb9e62d0ce69b2bf Mon Sep 17 00:00:00 2001 From: rnou Date: Tue, 17 May 2022 12:44:06 +0200 Subject: [PATCH 04/16] lseek extra WHENCE testing --- tests/integration/position/test_lseek.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/integration/position/test_lseek.py b/tests/integration/position/test_lseek.py index 125b6734e..733b3988c 100644 --- a/tests/integration/position/test_lseek.py +++ b/tests/integration/position/test_lseek.py @@ -129,7 +129,17 @@ def test_lseek(gkfs_daemon, gkfs_client): assert ret.retval == -1 #FAILS assert ret.errno == 22 + ret = gkfs_client.lseek(file_a, 0, os.SEEK_DATA) + assert ret.retval == -1 + assert ret.errno == errno.EINVAL + + ret = gkfs_client.lseek(file_a, 0, os.SEEK_HOLE) + assert ret.retval == -1 + assert ret.errno == errno.EINVAL + ret = gkfs_client.lseek(file_a, 0, 666) + assert ret.retval == -1 + assert ret.errno == errno.EINVAL -- GitLab From e3ff9bd3a8774ff488866a502f30757751ce3515 Mon Sep 17 00:00:00 2001 From: rnou Date: Tue, 17 May 2022 12:57:27 +0200 Subject: [PATCH 05/16] Truncate errors test --- .gitlab-ci.yml | 10 ++++---- tests/integration/data/test_truncate.py | 33 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9624b7e20..8f375f69e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,11 +50,11 @@ gkfs: needs: [] script: # Change config.hpp with sed to enable extra features - - sed -i 's/\/\/constexpr auto use_atime = false;/constexpr auto use_atime = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" - - sed -i 's/\/\/constexpr auto use_ctime = false;/constexpr auto use_ctime = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" - - sed -i 's/\/\/constexpr auto use_mtime = false;/constexpr auto use_mtime = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" - - sed -i 's/\/\/constexpr auto use_link_cnt = false;/constexpr auto use_link_cnt = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" - - sed -i 's/\/\/constexpr auto use_blocks = false;/constexpr auto use_blocks = true;/g' "${CI_PROJECT_DIR}/src/config.hpp" + - sed -i 's/\/\/constexpr auto use_atime = false;/constexpr auto use_atime = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_ctime = false;/constexpr auto use_ctime = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_mtime = false;/constexpr auto use_mtime = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_link_cnt = false;/constexpr auto use_link_cnt = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_blocks = false;/constexpr auto use_blocks = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" - mkdir -p ${BUILD_PATH} && cd ${BUILD_PATH} - cmake -Wdev diff --git a/tests/integration/data/test_truncate.py b/tests/integration/data/test_truncate.py index 58887a799..4d6fc40da 100644 --- a/tests/integration/data/test_truncate.py +++ b/tests/integration/data/test_truncate.py @@ -30,6 +30,7 @@ # from pathlib import Path import os import stat +import errno # @pytest.mark.xfail(reason="invalid errno returned on success") @@ -121,3 +122,35 @@ def test_truncate(gkfs_daemon, gkfs_client): ret = gkfs_client.file_compare(truncfile, truncfile_verify_2, trunc_size) assert ret.retval == 0 + + +# Tests failure cases +def test_fail_truncate(gkfs_daemon, gkfs_client): + truncfile = gkfs_daemon.mountdir / "trunc_file2" + # open and create test file + ret = gkfs_client.open(truncfile, os.O_CREAT | os.O_WRONLY, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + + assert ret.retval != -1 + + buf_length = 256 + ret = gkfs_client.write_random(truncfile, buf_length) + assert ret.retval == buf_length + + ret = gkfs_client.truncate(truncfile, buf_length) + assert ret.retval == 0 + + # Size should not change + ret = gkfs_client.stat(truncfile) + assert ret.statbuf.st_size == buf_length + + # Truncate to a negative size + ret = gkfs_client.truncate(truncfile, -1) + assert ret.retval == -1 + assert ret.errno == errno.EINVAL + + # Truncate to a size greater than the file size + ret = gkfs_client.truncate(truncfile, buf_length + 1) + assert ret.retval == -1 + assert ret.errno == errno.EINVAL + + -- GitLab From 72be2450337c83384abbc8e60adcf3dde3562999 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Tue, 17 May 2022 12:03:53 +0000 Subject: [PATCH 06/16] Update .gitlab-ci.yml --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8f375f69e..3993a63a9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,11 +50,11 @@ gkfs: needs: [] script: # Change config.hpp with sed to enable extra features - - sed -i 's/\/\/constexpr auto use_atime = false;/constexpr auto use_atime = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_ctime = false;/constexpr auto use_ctime = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_mtime = false;/constexpr auto use_mtime = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_link_cnt = false;/constexpr auto use_link_cnt = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_blocks = false;/constexpr auto use_blocks = true;/g' "${CI_PROJECT_DIR}/src/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_atime = false;/constexpr auto use_atime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_ctime = false;/constexpr auto use_ctime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_mtime = false;/constexpr auto use_mtime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_link_cnt = false;/constexpr auto use_link_cnt = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/\/\/constexpr auto use_blocks = false;/constexpr auto use_blocks = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" - mkdir -p ${BUILD_PATH} && cd ${BUILD_PATH} - cmake -Wdev -- GitLab From c1ad07f98bc1b12055112a1372c7a32b3253a97a Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Wed, 18 May 2022 08:53:09 +0200 Subject: [PATCH 07/16] Disable unused code - Remove statvfs (unused) Check Parents --- src/client/gkfs_functions.cpp | 6 +- .../coverage/test_error_operations.py | 34 +++--- tests/integration/harness/CMakeLists.txt | 1 - .../integration/harness/gkfs.io/commands.hpp | 3 - tests/integration/harness/gkfs.io/main.cpp | 1 - .../integration/harness/gkfs.io/serialize.hpp | 16 --- tests/integration/harness/gkfs.io/statvfs.cpp | 101 ------------------ tests/integration/harness/io.py | 32 ------ 8 files changed, 26 insertions(+), 168 deletions(-) delete mode 100644 tests/integration/harness/gkfs.io/statvfs.cpp diff --git a/src/client/gkfs_functions.cpp b/src/client/gkfs_functions.cpp index a9cb5069f..1ae6bb95f 100644 --- a/src/client/gkfs_functions.cpp +++ b/src/client/gkfs_functions.cpp @@ -411,6 +411,7 @@ gkfs_statfs(struct statfs* buf) { return 0; } +#ifdef ENABLE_UNUSED_FUNCTIONS /** * gkfs wrapper for statvfs() system calls * errno may be set @@ -444,6 +445,7 @@ gkfs_statvfs(struct statvfs* buf) { ST_NOATIME | ST_NODIRATIME | ST_NOSUID | ST_NODEV | ST_SYNCHRONOUS; return 0; } +#endif /** * gkfs wrapper for lseek() system calls with available file descriptor @@ -1094,7 +1096,7 @@ gkfs_getdents64(unsigned int fd, struct linux_dirent64* dirp, #ifdef HAS_SYMLINKS - +#ifdef ENABLE_UNUSED_FUNCTIONS /** * gkfs wrapper for make symlink() system calls * errno may be set @@ -1177,7 +1179,7 @@ gkfs_readlink(const std::string& path, char* buf, int bufsize) { std::strcpy(buf + CTX->mountdir().size(), md->target_path().c_str()); return path_size; } - +#endif #endif } // namespace gkfs::syscall diff --git a/tests/integration/coverage/test_error_operations.py b/tests/integration/coverage/test_error_operations.py index 3ef1e3bbf..f38c95ab5 100644 --- a/tests/integration/coverage/test_error_operations.py +++ b/tests/integration/coverage/test_error_operations.py @@ -74,6 +74,10 @@ def test_open_error(gkfs_daemon, gkfs_client): # Undefined in man ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) assert ret.retval == 10000 + + # Truncate the file + ret = gkfs_client.open(file2, os.O_TRUNC | os.O_WRONLY) + assert ret.retval == 10000 # Open unexistent file @@ -125,18 +129,24 @@ def test_statfs(gkfs_daemon, gkfs_client): assert ret.statfsbuf.f_bavail != 0 assert ret.statfsbuf.f_files == 0 assert ret.statfsbuf.f_ffree == 0 + +def test_check_parents(gkfs_daemon, gkfs_client): + file = gkfs_daemon.mountdir / "dir" / "file" + file2 = gkfs_daemon.mountdir / "file2" + file3 = gkfs_daemon.mountdir / "file2" / "file3" -def test_statvfs(gkfs_daemon, gkfs_client): - # Statfs check most of the outputs + # Parent directory does not exist + ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.ENOENT + + # Create file + ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + # Create file over a file + ret = gkfs_client.open(file3, os.O_CREAT | os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.ENOTDIR - ret = gkfs_client.statvfs(gkfs_daemon.mountdir) - assert ret.retval == 0 - assert ret.statvfsbuf.f_bsize != 0 - assert ret.statvfsbuf.f_blocks != 0 - assert ret.statvfsbuf.f_bfree != 0 - assert ret.statvfsbuf.f_bavail != 0 - assert ret.statvfsbuf.f_files == 0 - assert ret.statvfsbuf.f_ffree == 0 - - \ No newline at end of file diff --git a/tests/integration/harness/CMakeLists.txt b/tests/integration/harness/CMakeLists.txt index 5a66618a5..ab7400a10 100644 --- a/tests/integration/harness/CMakeLists.txt +++ b/tests/integration/harness/CMakeLists.txt @@ -65,7 +65,6 @@ add_executable(gkfs.io gkfs.io/unlink.cpp gkfs.io/access.cpp gkfs.io/statfs.cpp - gkfs.io/statvfs.cpp ) include(FetchContent) diff --git a/tests/integration/harness/gkfs.io/commands.hpp b/tests/integration/harness/gkfs.io/commands.hpp index fa5843504..401fc7da1 100644 --- a/tests/integration/harness/gkfs.io/commands.hpp +++ b/tests/integration/harness/gkfs.io/commands.hpp @@ -102,9 +102,6 @@ access_init(CLI::App& app); void statfs_init(CLI::App& app); -void -statvfs_init(CLI::App& app); - // UTIL void file_compare_init(CLI::App& app); diff --git a/tests/integration/harness/gkfs.io/main.cpp b/tests/integration/harness/gkfs.io/main.cpp index a1f71ec37..fbe0228b1 100644 --- a/tests/integration/harness/gkfs.io/main.cpp +++ b/tests/integration/harness/gkfs.io/main.cpp @@ -59,7 +59,6 @@ init_commands(CLI::App& app) { truncate_init(app); access_init(app); statfs_init(app); - statvfs_init(app); // utils file_compare_init(app); chdir_init(app); diff --git a/tests/integration/harness/gkfs.io/serialize.hpp b/tests/integration/harness/gkfs.io/serialize.hpp index 68971ad4f..cb740b4ab 100644 --- a/tests/integration/harness/gkfs.io/serialize.hpp +++ b/tests/integration/harness/gkfs.io/serialize.hpp @@ -188,22 +188,6 @@ struct adl_serializer { } }; -// ADL specialization for struct ::statvfs (not exhaustive) type -template <> -struct adl_serializer { - static void - to_json(json& j, const struct ::statvfs opt) { - j = json{ - {"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}, - {"f_favail", opt.f_favail}}; - } -}; - #ifdef STATX_TYPE // ADL specialization for struct ::statx type template <> diff --git a/tests/integration/harness/gkfs.io/statvfs.cpp b/tests/integration/harness/gkfs.io/statvfs.cpp deleted file mode 100644 index 1161b9dd7..000000000 --- a/tests/integration/harness/gkfs.io/statvfs.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain - Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany - - This software was partially supported by the - EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). - - This software was partially supported by the - ADA-FS project under the SPPEXA project funded by the DFG. - - This file is part of GekkoFS. - - GekkoFS is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GekkoFS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GekkoFS. If not, see . - - SPDX-License-Identifier: GPL-3.0-or-later -*/ - -/* C++ includes */ -#include -#include -#include -#include -#include -#include -#include - -/* C includes */ -#include -#include -#include - -using json = nlohmann::json; - -struct statvfs_options { - bool verbose{}; - std::string pathname; - - REFL_DECL_STRUCT(statvfs_options, REFL_DECL_MEMBER(bool, verbose), - REFL_DECL_MEMBER(std::string, pathname)); -}; - -struct statvfs_output { - int retval; - int errnum; - struct ::statvfs statvfsbuf; - - REFL_DECL_STRUCT(statvfs_output, REFL_DECL_MEMBER(int, retval), - REFL_DECL_MEMBER(int, errnum), - REFL_DECL_MEMBER(struct ::statvfs, statvfsbuf)); -}; - -void -to_json(json& record, const statvfs_output& out) { - record = serialize(out); -} - -void -statvfs_exec(const statvfs_options& opts) { - - struct ::statvfs statvfsbuf; - - auto rv = ::statvfs(opts.pathname.c_str(), &statvfsbuf); - - if(opts.verbose) { - fmt::print("statvfs(pathname=\"{}\") = {}, errno: {} [{}]\n", - opts.pathname, rv, errno, ::strerror(errno)); - return; - } - - json out = statvfs_output{rv, errno, statvfsbuf}; - fmt::print("{}\n", out.dump(2)); -} - -void -statvfs_init(CLI::App& app) { - - // Create the option and subcommand objects - auto opts = std::make_shared(); - auto* cmd = app.add_subcommand("statvfs", "Execute the statvfs() 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]() { statvfs_exec(*opts); }); -} diff --git a/tests/integration/harness/io.py b/tests/integration/harness/io.py index c9b4d47be..7e553b314 100644 --- a/tests/integration/harness/io.py +++ b/tests/integration/harness/io.py @@ -105,26 +105,6 @@ class StructStatfsSchema(Schema): 'f_bavail', 'f_files', 'f_ffree'])(**data) -class StructStatvfsSchema(Schema): - """Schema that deserializes a struct statvfs""" - - 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_favail = 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_bsize', 'f_blocks', 'f_bfree', - 'f_bavail', 'f_files', 'f_ffree', 'f_favail'])(**data) class StructStatxTimestampSchema(Schema): """Schema that deserializes a struct timespec""" @@ -352,17 +332,6 @@ class StatfsOutputSchema(Schema): def make_object(self, data, **kwargs): return namedtuple('StatfsReturn', ['retval', 'statfsbuf', 'errno'])(**data) -class StatvfsOutputSchema(Schema): - """Schema to deserialize the results of a statfs() execution""" - - retval = fields.Integer(required=True) - statvfsbuf = fields.Nested(StructStatvfsSchema, required=True) - errno = Errno(data_key='errnum', required=True) - - @post_load - def make_object(self, data, **kwargs): - return namedtuple('StatvfsReturn', ['retval', 'statvfsbuf', 'errno'])(**data) - class LseekOutputSchema(Schema): """Schema to deserialize the results of an lseek() execution""" retval = fields.Integer(required=True) @@ -505,7 +474,6 @@ class IOParser: 'unlink' : UnlinkOutputSchema(), 'access' : AccessOutputSchema(), 'statfs' : StatfsOutputSchema(), - 'statvfs' : StatvfsOutputSchema(), # UTIL 'file_compare': FileCompareOutputSchema(), 'chdir' : ChdirOutputSchema(), -- GitLab From 4110d879e5043ce24403f70d5f7cb5754817cf83 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Wed, 18 May 2022 11:04:51 +0200 Subject: [PATCH 08/16] opendir / rmdir errors --- .gitlab-ci.yml | 10 +++++----- tests/integration/directories/test_directories.py | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3993a63a9..44bf01757 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,11 +50,11 @@ gkfs: needs: [] script: # Change config.hpp with sed to enable extra features - - sed -i 's/\/\/constexpr auto use_atime = false;/constexpr auto use_atime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_ctime = false;/constexpr auto use_ctime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_mtime = false;/constexpr auto use_mtime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_link_cnt = false;/constexpr auto use_link_cnt = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" - - sed -i 's/\/\/constexpr auto use_blocks = false;/constexpr auto use_blocks = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/constexpr auto use_atime = false;/constexpr auto use_atime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/constexpr auto use_ctime = false;/constexpr auto use_ctime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/constexpr auto use_mtime = false;/constexpr auto use_mtime = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/constexpr auto use_link_cnt = false;/constexpr auto use_link_cnt = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" + - sed -i 's/constexpr auto use_blocks = false;/constexpr auto use_blocks = true;/g' "${CI_PROJECT_DIR}/include/config.hpp" - mkdir -p ${BUILD_PATH} && cd ${BUILD_PATH} - cmake -Wdev diff --git a/tests/integration/directories/test_directories.py b/tests/integration/directories/test_directories.py index 066b36962..52d036ba5 100644 --- a/tests/integration/directories/test_directories.py +++ b/tests/integration/directories/test_directories.py @@ -189,6 +189,15 @@ def test_mkdir(gkfs_daemon, gkfs_client): assert d.d_name == e[0] assert d.d_type == e[1] + # Try to open a file as a dir + ret = gkfs_client.opendir(file_a) + assert ret.dirp is None + assert ret.errno == errno.ENOTDIR + + # Try to remove a non empty dir + ret = gkfs_client.rmdir(topdir) + assert ret.retval == -1 + assert ret.errno == errno.ENOTEMPTY return -- GitLab From 9a9ad69c9ea1461b32e950867c3293218e1add2d Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Wed, 18 May 2022 15:26:08 +0200 Subject: [PATCH 09/16] dup dup2 testing syscall testing coverage --- .gitlab-ci.yml | 1 + .../coverage/test_error_operations.py | 20 +- tests/integration/coverage/test_syscalls.py | 56 +++++ tests/integration/harness/CMakeLists.txt | 2 + .../integration/harness/gkfs.io/commands.hpp | 6 + .../harness/gkfs.io/dup_validate.cpp | 132 ++++++++++++ tests/integration/harness/gkfs.io/main.cpp | 2 + .../harness/gkfs.io/syscall_coverage.cpp | 193 ++++++++++++++++++ tests/integration/harness/gkfs.py | 3 +- tests/integration/harness/io.py | 20 ++ 10 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 tests/integration/coverage/test_syscalls.py create mode 100644 tests/integration/harness/gkfs.io/dup_validate.cpp create mode 100644 tests/integration/harness/gkfs.io/syscall_coverage.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 44bf01757..27394eee5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -233,6 +233,7 @@ gkfs:unit: - ctest -j $(nproc) -L unit::all --output-junit report.xml ## capture coverage information + - cd ${BUILD_PATH} - ${CI_SCRIPTS_DIR}/coverage.sh --verbose --capture unit diff --git a/tests/integration/coverage/test_error_operations.py b/tests/integration/coverage/test_error_operations.py index f38c95ab5..a5ce6bd94 100644 --- a/tests/integration/coverage/test_error_operations.py +++ b/tests/integration/coverage/test_error_operations.py @@ -74,11 +74,18 @@ def test_open_error(gkfs_daemon, gkfs_client): # Undefined in man ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) assert ret.retval == 10000 + + # RDWR + ret = gkfs_client.open(file2, os.O_RDWR) + assert ret.retval == 10000 + # RD + ret = gkfs_client.open(file2, os.O_RDONLY) + assert ret.retval == 10000 + # Truncate the file ret = gkfs_client.open(file2, os.O_TRUNC | os.O_WRONLY) assert ret.retval == 10000 - # Open unexistent file ret = gkfs_client.open(file3, os.O_WRONLY) @@ -150,3 +157,14 @@ def test_check_parents(gkfs_daemon, gkfs_client): assert ret.retval == -1 assert ret.errno == errno.ENOTDIR + +def test_dup(gkfs_daemon, gkfs_client): + file = gkfs_daemon.mountdir / "file" + + ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + ret = gkfs_client.dup_validate(file) + assert ret.retval == 0 + assert ret.errno == 0 + diff --git a/tests/integration/coverage/test_syscalls.py b/tests/integration/coverage/test_syscalls.py new file mode 100644 index 000000000..88057a779 --- /dev/null +++ b/tests/integration/coverage/test_syscalls.py @@ -0,0 +1,56 @@ +################################################################################ +# Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain # +# Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany # +# # +# This software was partially supported by the # +# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # +# # +# This software was partially supported by the # +# ADA-FS project under the SPPEXA project funded by the DFG. # +# # +# This file is part of GekkoFS. # +# # +# GekkoFS is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# GekkoFS is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with GekkoFS. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + +from sre_parse import State +import harness +from pathlib import Path +import errno +import stat +import os +import ctypes +import sys +import pytest +from harness.logger import logger +import ctypes +nonexisting = "nonexisting" + + +def test_syscalls(gkfs_daemon, gkfs_client): + + file = gkfs_daemon.mountdir / "file" + + ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + + ret = gkfs_client.syscall_coverage(file) + assert ret.retval == 0 + assert ret.errno == 0 + + + diff --git a/tests/integration/harness/CMakeLists.txt b/tests/integration/harness/CMakeLists.txt index ab7400a10..39bd95bb2 100644 --- a/tests/integration/harness/CMakeLists.txt +++ b/tests/integration/harness/CMakeLists.txt @@ -65,6 +65,8 @@ add_executable(gkfs.io gkfs.io/unlink.cpp gkfs.io/access.cpp gkfs.io/statfs.cpp + gkfs.io/dup_validate.cpp + gkfs.io/syscall_coverage.cpp ) include(FetchContent) diff --git a/tests/integration/harness/gkfs.io/commands.hpp b/tests/integration/harness/gkfs.io/commands.hpp index 401fc7da1..c57ef5c40 100644 --- a/tests/integration/harness/gkfs.io/commands.hpp +++ b/tests/integration/harness/gkfs.io/commands.hpp @@ -117,4 +117,10 @@ symlink_init(CLI::App& app); void unlink_init(CLI::App& app); +void +dup_validate_init(CLI::App& app); + +void +syscall_coverage_init(CLI::App& app); + #endif // IO_COMMANDS_HPP diff --git a/tests/integration/harness/gkfs.io/dup_validate.cpp b/tests/integration/harness/gkfs.io/dup_validate.cpp new file mode 100644 index 000000000..acc084a37 --- /dev/null +++ b/tests/integration/harness/gkfs.io/dup_validate.cpp @@ -0,0 +1,132 @@ +/* + Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +/* C++ includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* C includes */ +#include +#include +#include +#include + +using json = nlohmann::json; + +struct dup_validate_options { + bool verbose{}; + std::string pathname; + + + REFL_DECL_STRUCT(dup_validate_options, REFL_DECL_MEMBER(bool, verbose), + REFL_DECL_MEMBER(std::string, pathname)); +}; + +struct dup_validate_output { + int retval; + int errnum; + + REFL_DECL_STRUCT(dup_validate_output, REFL_DECL_MEMBER(int, retval), + REFL_DECL_MEMBER(int, errnum)); +}; + +void +to_json(json& record, const dup_validate_output& out) { + record = serialize(out); +} + +void +dup_validate_exec(const dup_validate_options& opts) { + + int fd = ::open(opts.pathname.c_str(), O_WRONLY); + + if(fd == -1) { + if(opts.verbose) { + fmt::print( + "dup_validate(pathname=\"{}\") = {}, errno: {} [{}]\n", + opts.pathname, fd, errno, ::strerror(errno)); + return; + } + + json out = dup_validate_output{fd, errno}; + fmt::print("{}\n", out.dump(2)); + + return; + } + + + auto rv = ::dup(fd); + auto rv2 = ::dup2(fd, rv); + + + + if(opts.verbose) { + fmt::print( + "dup_validate(pathname=\"{}\") = {}, errno: {} [{}]\n", + opts.pathname, rv, errno, ::strerror(errno)); + return; + } + + if(rv < 0 || rv2 < 0) { + json out = dup_validate_output{(int) rv, errno}; + fmt::print("{}\n", out.dump(2)); + return; + } + + rv = 0; + errno = 0; + json out = dup_validate_output{(int) rv, errno}; + fmt::print("{}\n", out.dump(2)); + return; +} + +void +dup_validate_init(CLI::App& app) { + + // Create the option and subcommand objects + auto opts = std::make_shared(); + auto* cmd = app.add_subcommand( + "dup_validate", + "Execute dup, dup2, and dup3 returns 0 if the file descriptor is valid"); + + // Add options to cmd, binding them to opts + cmd->add_flag("-v,--verbose", opts->verbose, + "Produce human writeable output"); + + cmd->add_option("pathname", opts->pathname, "File name") + ->required() + ->type_name(""); + + cmd->callback([opts]() { dup_validate_exec(*opts); }); +} diff --git a/tests/integration/harness/gkfs.io/main.cpp b/tests/integration/harness/gkfs.io/main.cpp index fbe0228b1..91514bba3 100644 --- a/tests/integration/harness/gkfs.io/main.cpp +++ b/tests/integration/harness/gkfs.io/main.cpp @@ -65,6 +65,8 @@ init_commands(CLI::App& app) { getcwd_validate_init(app); symlink_init(app); unlink_init(app); + dup_validate_init(app); + syscall_coverage_init(app); } diff --git a/tests/integration/harness/gkfs.io/syscall_coverage.cpp b/tests/integration/harness/gkfs.io/syscall_coverage.cpp new file mode 100644 index 000000000..6279fa65a --- /dev/null +++ b/tests/integration/harness/gkfs.io/syscall_coverage.cpp @@ -0,0 +1,193 @@ +/* + Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +/* C++ includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* C includes */ +#include +#include +#include +#include + +using json = nlohmann::json; + +struct syscall_coverage_options { + bool verbose{}; + std::string pathname; + + + REFL_DECL_STRUCT(syscall_coverage_options, REFL_DECL_MEMBER(bool, verbose), + REFL_DECL_MEMBER(std::string, pathname)); +}; + +struct syscall_coverage_output { + int retval; + int errnum; + + REFL_DECL_STRUCT(syscall_coverage_output, REFL_DECL_MEMBER(int, retval), + REFL_DECL_MEMBER(int, errnum)); +}; + +void +to_json(json& record, const syscall_coverage_output& out) { + record = serialize(out); +} + +void output (const std::string syscall, const int ret, const syscall_coverage_options& opts) { + if(opts.verbose) { + fmt::print( + "syscall_coverage[{}](pathname=\"{}\") = {}, errno: {} [{}]\n", + syscall, opts.pathname, ret, errno, ::strerror(errno)); + } + + json out = syscall_coverage_output{ret, errno}; + fmt::print("{}\n", out.dump(2)); +} +void +syscall_coverage_exec(const syscall_coverage_options& opts) { + + int fd = ::open(opts.pathname.c_str(), O_RDWR); + + if(fd == -1) { + output ("open", fd, opts); + return; + } + + // Internal + + auto rv = ::faccessat(AT_FDCWD, opts.pathname.c_str(), F_OK, 0); + + if(rv < 0) { + output ("faccessat", rv, opts); + + return; + } + + // External + + rv = ::faccessat(AT_FDCWD, "/tmp", F_OK, 0); + + if(rv < 0) { + output ("faccessat, external", rv, opts); + + return; + } + + // lstat + + struct stat st; + rv = ::lstat(opts.pathname.c_str(), &st); + + if (rv < 0) { + output ("lstat", rv, opts); + + return; + } + + + + + rv = ::fchmod(fd, 0777); + if (errno != ENOTSUP) { + output ("fchmod", rv, opts); + return; + } + + rv = ::fchmodat(AT_FDCWD, opts.pathname.c_str(), 0777, 0); + if (errno != ENOTSUP) { + output ("fchmodat", rv, opts); + return; + } + + rv = ::dup3(fd, 0, 0); + if (errno != ENOTSUP) { + output ("dup3", rv, opts); + return; + } + + // fcntl + rv = ::fcntl(fd, F_GETFD); + if (rv < 0) { + output ("fcntl, F_GETFD", rv, opts); + return; + } + + rv = ::fcntl(fd, F_GETFL); + if (rv < 0 || rv != O_RDWR) { + output ("fcntl, F_GETFL", rv, opts); + return; + } + + + rv = ::fcntl(fd, F_SETFD, 0); + if (rv < 0) { + output ("fcntl, F_SETFD", rv, opts); + return; + } + + rv = ::fcntl(fd, F_SETFL, 0); + if (errno != ENOTSUP) { + output ("fcntl, F_SETFL", rv, opts); + return; + } + + + rv = 0; + errno = 0; + json out = syscall_coverage_output{(int) rv, errno}; + fmt::print("{}\n", out.dump(2)); + return; +} + +void +syscall_coverage_init(CLI::App& app) { + + // Create the option and subcommand objects + auto opts = std::make_shared(); + auto* cmd = app.add_subcommand( + "syscall_coverage", + "Execute severals syscalls"); + + // Add options to cmd, binding them to opts + cmd->add_flag("-v,--verbose", opts->verbose, + "Produce human writeable output"); + + cmd->add_option("pathname", opts->pathname, "File name") + ->required() + ->type_name(""); + + cmd->callback([opts]() { syscall_coverage_exec(*opts); }); +} diff --git a/tests/integration/harness/gkfs.py b/tests/integration/harness/gkfs.py index 26db3b309..2ba4ae593 100644 --- a/tests/integration/harness/gkfs.py +++ b/tests/integration/harness/gkfs.py @@ -254,7 +254,8 @@ class Daemon: '--dbbackend', self._database, '--output-stats', self.logdir / 'stats.log', '--enable-collection', - '--enable-chunkstats' ] + '--enable-chunkstats', + '--enable-prometheus' ] if self._database == "parallaxdb" : args.append('--clean-rootdir-finish') diff --git a/tests/integration/harness/io.py b/tests/integration/harness/io.py index 7e553b314..2434edc4a 100644 --- a/tests/integration/harness/io.py +++ b/tests/integration/harness/io.py @@ -414,7 +414,25 @@ class GetcwdvalidateOutputSchema(Schema): def make_object(self, data, **kwargs): return namedtuple('GetcwdvalidateReturn', ['retval', 'path', 'errno'])(**data) +class DupValidateOutputSchema(Schema): + """Schema to deserialize the results of an dup, dup2, dup3 execution""" + retval = fields.Integer(required=True) + errno = Errno(data_key='errnum', required=True) + + @post_load + def make_object(self, data, **kwargs): + return namedtuple('DupValidateReturn', ['retval', 'errno'])(**data) + +class SyscallCoverageOutputSchema(Schema): + """Schema to deserialize the results of a syscall coverage execution""" + + retval = fields.Integer(required=True) + errno = Errno(data_key='errnum', required=True) + + @post_load + def make_object(self, data, **kwargs): + return namedtuple('SyscallCoverageReturn', ['retval', 'errno'])(**data) class SymlinkOutputSchema(Schema): """Schema to deserialize the results of an symlink execution""" @@ -479,6 +497,8 @@ class IOParser: 'chdir' : ChdirOutputSchema(), 'getcwd_validate' : GetcwdvalidateOutputSchema(), 'symlink' : SymlinkOutputSchema(), + 'dup_validate' : DupValidateOutputSchema(), + 'syscall_coverage' : SyscallCoverageOutputSchema(), } def parse(self, command, output): -- GitLab From ad5df517fb4b252f3d19957e1e3365a3ff2f4cd3 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Fri, 20 May 2022 09:31:48 +0200 Subject: [PATCH 10/16] fchdir SIGSEGV, add tests --- src/client/hooks.cpp | 4 +- .../harness/gkfs.io/syscall_coverage.cpp | 91 +++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/client/hooks.cpp b/src/client/hooks.cpp index 037d6c8ee..5917b80a7 100644 --- a/src/client/hooks.cpp +++ b/src/client/hooks.cpp @@ -712,8 +712,8 @@ hook_fchdir(unsigned int fd) { auto open_dir = CTX->file_map()->get_dir(fd); if(open_dir == nullptr) { // Cast did not succeeded: open_file is a regular file - LOG(ERROR, "{}() file descriptor refers to a normal file: '{}'", - __func__, open_dir->path()); + LOG(ERROR, "{}() file descriptor refers to a normal file", + __func__); return -EBADF; } diff --git a/tests/integration/harness/gkfs.io/syscall_coverage.cpp b/tests/integration/harness/gkfs.io/syscall_coverage.cpp index 6279fa65a..c05f5ec1b 100644 --- a/tests/integration/harness/gkfs.io/syscall_coverage.cpp +++ b/tests/integration/harness/gkfs.io/syscall_coverage.cpp @@ -36,11 +36,13 @@ #include #include + /* C includes */ #include #include #include #include +#include using json = nlohmann::json; @@ -76,6 +78,11 @@ void output (const std::string syscall, const int ret, const syscall_coverage_op json out = syscall_coverage_output{ret, errno}; fmt::print("{}\n", out.dump(2)); } + +/* + * system calls + * that are being tested. + */ void syscall_coverage_exec(const syscall_coverage_options& opts) { @@ -164,7 +171,91 @@ syscall_coverage_exec(const syscall_coverage_options& opts) { return; } + rv = ::fcntl(fd, F_DUPFD, 0); + if (rv < 0) { + output ("fcntl, F_DUPFD", rv, opts); + return; + } + + rv = ::fcntl(fd, F_DUPFD_CLOEXEC, 0); + if (rv < 0) { + output ("fcntl, F_DUPFD_CLOEXEC", rv, opts); + return; + } + + // Fstatfs + + struct statfs stfs; + rv = ::fstatfs(fd, &stfs); + if (rv < 0) { + output ("fstatfs", rv, opts); + return; + } + + // fsync + + rv = ::fsync(fd); + if (rv < 0) { + output ("fsync", rv, opts); + return; + } + + // getxattr + + char buf[1024]; + rv = ::getxattr(opts.pathname.c_str(), "user.test", buf, sizeof(buf)); + if (errno != ENOTSUP) { + output ("getxattr", rv, opts); + return; + } + // readlinkat + rv = ::readlinkat(AT_FDCWD, opts.pathname.c_str(), buf, sizeof(buf)); + if (errno != ENOTSUP) { + output ("readlinkat", rv, opts); + return; + } + + // fchdir + auto fddir = ::open(".", O_RDONLY); + if (fddir < 0) { + output ("fchdir", fddir, opts); + return; + } + + rv = ::fchdir(fddir); + if (rv < 0) { + output ("fchdir", rv, opts); + return; + } + + // ftruncate + rv = ::ftruncate(fd, 0); + if (rv < 0) { + output ("ftruncate", rv, opts); + return; + } + + // fchdir internal file + rv = ::fchdir(fd); + if (errno != EBADF) { + output ("fchdir", rv, opts); + return; + } + + + // fchdir directory from opts.pathname + auto fd2 = ::open(opts.pathname.substr(0,opts.pathname.find_last_of("/")).c_str(), O_RDONLY); + if (fd2 < 0) { + output ("fchdir", fd2, opts); + return; + } + rv = ::fchdir(fd2); + if (rv < 0) { + output ("fchdir", rv, opts); + return; + } + rv = 0; errno = 0; json out = syscall_coverage_output{(int) rv, errno}; -- GitLab From 916685254f9a52b3cfa0954d66997c8f628c295a Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Fri, 20 May 2022 12:20:42 +0200 Subject: [PATCH 11/16] more syscalls from hook, tested --- tests/integration/coverage/test_syscalls.py | 2 + .../harness/gkfs.io/syscall_coverage.cpp | 305 ++++++++++++++---- tests/integration/harness/io.py | 3 +- 3 files changed, 245 insertions(+), 65 deletions(-) diff --git a/tests/integration/coverage/test_syscalls.py b/tests/integration/coverage/test_syscalls.py index 88057a779..539593838 100644 --- a/tests/integration/coverage/test_syscalls.py +++ b/tests/integration/coverage/test_syscalls.py @@ -49,8 +49,10 @@ def test_syscalls(gkfs_daemon, gkfs_client): ret = gkfs_client.syscall_coverage(file) + assert ret.syscall == "ALLOK" assert ret.retval == 0 assert ret.errno == 0 + diff --git a/tests/integration/harness/gkfs.io/syscall_coverage.cpp b/tests/integration/harness/gkfs.io/syscall_coverage.cpp index c05f5ec1b..257311f14 100644 --- a/tests/integration/harness/gkfs.io/syscall_coverage.cpp +++ b/tests/integration/harness/gkfs.io/syscall_coverage.cpp @@ -44,6 +44,9 @@ #include #include +// Syscall numbers +#include + using json = nlohmann::json; struct syscall_coverage_options { @@ -58,9 +61,11 @@ struct syscall_coverage_options { struct syscall_coverage_output { int retval; int errnum; + std::string syscall; REFL_DECL_STRUCT(syscall_coverage_output, REFL_DECL_MEMBER(int, retval), - REFL_DECL_MEMBER(int, errnum)); + REFL_DECL_MEMBER(int, errnum), + REFL_DECL_MEMBER(std::string, syscall)); }; void @@ -68,14 +73,16 @@ to_json(json& record, const syscall_coverage_output& out) { record = serialize(out); } -void output (const std::string syscall, const int ret, const syscall_coverage_options& opts) { +void +output(const std::string syscall, const int ret, + const syscall_coverage_options& opts) { if(opts.verbose) { - fmt::print( - "syscall_coverage[{}](pathname=\"{}\") = {}, errno: {} [{}]\n", - syscall, opts.pathname, ret, errno, ::strerror(errno)); - } + fmt::print( + "syscall_coverage[{}](pathname=\"{}\") = {}, errno: {} [{}]\n", + syscall, opts.pathname, ret, errno, ::strerror(errno)); + } - json out = syscall_coverage_output{ret, errno}; + json out = syscall_coverage_output{ret, errno, syscall}; fmt::print("{}\n", out.dump(2)); } @@ -89,114 +96,200 @@ syscall_coverage_exec(const syscall_coverage_options& opts) { int fd = ::open(opts.pathname.c_str(), O_RDWR); if(fd == -1) { - output ("open", fd, opts); + output("open", fd, opts); return; } - // Internal + // create external + int fdext = ::open("tmpfile", O_RDWR | O_CREAT, 0666); + + // faccessat Internal auto rv = ::faccessat(AT_FDCWD, opts.pathname.c_str(), F_OK, 0); if(rv < 0) { - output ("faccessat", rv, opts); - + output("faccessat", rv, opts); return; } - // External + // faccessat External rv = ::faccessat(AT_FDCWD, "/tmp", F_OK, 0); if(rv < 0) { - output ("faccessat, external", rv, opts); - + output("faccessat, external", rv, opts); return; } // lstat - struct stat st; rv = ::lstat(opts.pathname.c_str(), &st); + if(rv < 0) { + output("lstat", rv, opts); + return; + } - if (rv < 0) { - output ("lstat", rv, opts); + rv = ::lstat("tmpfile", &st); + if(rv < 0) { + output("lstat", rv, opts); + return; + } + // pwrite external + rv = ::pwrite(fdext, "test", 4, 0); + if(rv < 0) { + output("pwrite", rv, opts); return; } + // pread external + char bufext[4]; + rv = ::pread(fdext, bufext, 4, 0); + if(rv < 0) { + output("pread", rv, opts); + return; + } - + // lssek external + rv = ::lseek(fdext, 0, SEEK_SET); + if(rv < 0) { + output("lseek", rv, opts); + return; + } + // ftruncate external + rv = ::ftruncate(fdext, 0); + if(rv < 0) { + output("ftruncate", rv, opts); + return; + } + + // truncate exterlan + rv = ::truncate("tmpfile", 0); + if(rv < 0) { + output("truncate", rv, opts); + return; + } + + + // dup external + int fdext2 = ::dup(fdext); + if(fdext2 < 0) { + output("dup", fdext2, opts); + return; + } + + // dup2 external + int ffdext3 = 0; + rv = ::dup2(fdext, ffdext3); + if(rv < 0) { + output("dup2", rv, opts); + return; + } + + + // fchmod internal rv = ::fchmod(fd, 0777); - if (errno != ENOTSUP) { - output ("fchmod", rv, opts); + if(errno != ENOTSUP) { + output("fchmod", rv, opts); + return; + } + + // fchmod external + rv = ::fchmod(fdext, 0777); + if(rv < 0) { + output("fchmod", rv, opts); return; } + // fchmodat internal rv = ::fchmodat(AT_FDCWD, opts.pathname.c_str(), 0777, 0); - if (errno != ENOTSUP) { - output ("fchmodat", rv, opts); + if(errno != ENOTSUP) { + output("fchmodat", rv, opts); + return; + } + // fchmodat external + rv = ::fchmodat(AT_FDCWD, "tmpfile", 0777, 0); + if(rv < 0) { + output("fchmodat, external", rv, opts); return; } + // dup3 internal rv = ::dup3(fd, 0, 0); - if (errno != ENOTSUP) { - output ("dup3", rv, opts); + if(errno != ENOTSUP) { + output("dup3", rv, opts); return; } + // dup3 external + int ffdext4 = 0; + rv = ::dup3(fdext, ffdext4, 0); + if(rv < 0) { + output("dup3", rv, opts); + return; + } + + // fcntl rv = ::fcntl(fd, F_GETFD); - if (rv < 0) { - output ("fcntl, F_GETFD", rv, opts); + if(rv < 0) { + output("fcntl, F_GETFD", rv, opts); return; } rv = ::fcntl(fd, F_GETFL); - if (rv < 0 || rv != O_RDWR) { - output ("fcntl, F_GETFL", rv, opts); + if(rv < 0 || rv != O_RDWR) { + output("fcntl, F_GETFL", rv, opts); return; } rv = ::fcntl(fd, F_SETFD, 0); - if (rv < 0) { - output ("fcntl, F_SETFD", rv, opts); + if(rv < 0) { + output("fcntl, F_SETFD", rv, opts); return; } rv = ::fcntl(fd, F_SETFL, 0); - if (errno != ENOTSUP) { - output ("fcntl, F_SETFL", rv, opts); + if(errno != ENOTSUP) { + output("fcntl, F_SETFL", rv, opts); return; } rv = ::fcntl(fd, F_DUPFD, 0); - if (rv < 0) { - output ("fcntl, F_DUPFD", rv, opts); + if(rv < 0) { + output("fcntl, F_DUPFD", rv, opts); return; } rv = ::fcntl(fd, F_DUPFD_CLOEXEC, 0); - if (rv < 0) { - output ("fcntl, F_DUPFD_CLOEXEC", rv, opts); + if(rv < 0) { + output("fcntl, F_DUPFD_CLOEXEC", rv, opts); return; } - // Fstatfs + // Fstatfs internal struct statfs stfs; rv = ::fstatfs(fd, &stfs); - if (rv < 0) { - output ("fstatfs", rv, opts); + if(rv < 0) { + output("fstatfs", rv, opts); + return; + } + + // Fstatfs external + rv = ::fstatfs(fdext, &stfs); + if(rv < 0) { + output("fstatfs", rv, opts); return; } // fsync rv = ::fsync(fd); - if (rv < 0) { - output ("fsync", rv, opts); + if(rv < 0) { + output("fsync", rv, opts); return; } @@ -204,61 +297,146 @@ syscall_coverage_exec(const syscall_coverage_options& opts) { char buf[1024]; rv = ::getxattr(opts.pathname.c_str(), "user.test", buf, sizeof(buf)); - if (errno != ENOTSUP) { - output ("getxattr", rv, opts); + if(errno != ENOTSUP) { + output("getxattr", rv, opts); return; } // readlinkat rv = ::readlinkat(AT_FDCWD, opts.pathname.c_str(), buf, sizeof(buf)); - if (errno != ENOTSUP) { - output ("readlinkat", rv, opts); + if(errno != ENOTSUP) { + output("readlinkat", rv, opts); + return; + } + + // chdir internal error + rv = ::chdir(opts.pathname.c_str()); + if(errno != ENOTDIR) { + output("chdir", rv, opts); + return; + } + + // chdir internal error + std::string nonexist = opts.pathname+"x2"; + rv = ::chdir(nonexist.c_str()); + if(rv >= 0) { + output("chdir", rv, opts); return; } // fchdir auto fddir = ::open(".", O_RDONLY); - if (fddir < 0) { - output ("fchdir", fddir, opts); + if(fddir < 0) { + output("fchdir", fddir, opts); return; } rv = ::fchdir(fddir); - if (rv < 0) { - output ("fchdir", rv, opts); + if(rv < 0) { + output("fchdir", rv, opts); return; } // ftruncate rv = ::ftruncate(fd, 0); - if (rv < 0) { - output ("ftruncate", rv, opts); + if(rv < 0) { + output("ftruncate", rv, opts); return; } // fchdir internal file rv = ::fchdir(fd); - if (errno != EBADF) { - output ("fchdir", rv, opts); + if(errno != EBADF) { + output("fchdir", rv, opts); return; } - + // fchdir directory from opts.pathname - auto fd2 = ::open(opts.pathname.substr(0,opts.pathname.find_last_of("/")).c_str(), O_RDONLY); - if (fd2 < 0) { - output ("fchdir", fd2, opts); + auto fd2 = ::open( + opts.pathname.substr(0, opts.pathname.find_last_of("/")).c_str(), + O_RDONLY); + if(fd2 < 0) { + output("fchdir", fd2, opts); return; } rv = ::fchdir(fd2); - if (rv < 0) { - output ("fchdir", rv, opts); + if(rv < 0) { + output("fchdir", rv, opts); + return; + } + + // renameat external + auto fdtmp = ::open("/tmp/test_rename", O_CREAT | O_WRONLY); + ::close(fdtmp); + + rv = ::renameat(AT_FDCWD, "/tmp/test_rename", AT_FDCWD, + opts.pathname.c_str()); + if(errno != ENOTSUP) { + output("renameat", rv, opts); + return; + } + + rv = ::renameat(AT_FDCWD, "/tmp/test_rename", AT_FDCWD, + "/tmp/test_rename2"); + if(rv < 0) { + output("renameat", rv, opts); + return; + } + // sys_open + rv = ::syscall(SYS_open, opts.pathname.c_str(), O_RDONLY, 0); + if(rv < 0) { + output("sys_open", rv, opts); + return; + } + + // sys_creat + rv = ::syscall(SYS_creat, opts.pathname.c_str(), 0777); + if(rv < 0) { + output("sys_creat", rv, opts); + return; + } + + // sys_unlinkat + rv = ::syscall(SYS_unlinkat, AT_FDCWD, opts.pathname.c_str(), 0); + if(errno != ENOTSUP) { + output("sys_unlinkat", rv, opts); + return; + } + + // sys_mkdirat + std::string path = opts.pathname + "path"; + rv = ::syscall(SYS_mkdirat, AT_FDCWD, opts.pathname.c_str(), 0777); + if(rv < 0) { + output("sys_mkdirat", rv, opts); return; } - + + // SYS_chmod + rv = ::syscall(SYS_chmod, opts.pathname.c_str(), 0777); + if(errno != ENOTSUP) { + output("sys_chmod", rv, opts); + return; + } + + // hook_faccessat coverage + rv = ::syscall(SYS_faccessat, AT_FDCWD, opts.pathname.c_str(), F_OK, 0); + if(rv < 0) { + output("sys_faccessat", rv, opts); + return; + } + + rv = ::syscall(SYS_faccessat, AT_FDCWD, "/tmp", F_OK, 0); + if(rv < 0) { + output("sys_faccessat", rv, opts); + return; + } + + rv = 0; errno = 0; - json out = syscall_coverage_output{(int) rv, errno}; + auto syscall = "ALLOK"; + json out = syscall_coverage_output{(int) rv, errno, syscall}; fmt::print("{}\n", out.dump(2)); return; } @@ -268,9 +446,8 @@ syscall_coverage_init(CLI::App& app) { // Create the option and subcommand objects auto opts = std::make_shared(); - auto* cmd = app.add_subcommand( - "syscall_coverage", - "Execute severals syscalls"); + auto* cmd = + app.add_subcommand("syscall_coverage", "Execute severals syscalls"); // Add options to cmd, binding them to opts cmd->add_flag("-v,--verbose", opts->verbose, diff --git a/tests/integration/harness/io.py b/tests/integration/harness/io.py index 2434edc4a..834174a41 100644 --- a/tests/integration/harness/io.py +++ b/tests/integration/harness/io.py @@ -429,10 +429,11 @@ class SyscallCoverageOutputSchema(Schema): retval = fields.Integer(required=True) errno = Errno(data_key='errnum', required=True) + syscall = fields.String(required=True) @post_load def make_object(self, data, **kwargs): - return namedtuple('SyscallCoverageReturn', ['retval', 'errno'])(**data) + return namedtuple('SyscallCoverageReturn', ['retval', 'errno', 'syscall'])(**data) class SymlinkOutputSchema(Schema): """Schema to deserialize the results of an symlink execution""" -- GitLab From 6c01b30f6851450da904194eb085122b8352c37f Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Mon, 23 May 2022 12:28:59 +0200 Subject: [PATCH 12/16] Disable function get_host_by_name (not used) --- include/common/rpc/rpc_util.hpp | 2 ++ src/common/rpc/rpc_util.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/common/rpc/rpc_util.hpp b/include/common/rpc/rpc_util.hpp index 0cc26e699..2cc3c5889 100644 --- a/include/common/rpc/rpc_util.hpp +++ b/include/common/rpc/rpc_util.hpp @@ -44,8 +44,10 @@ bool_to_merc_bool(bool state); std::string get_my_hostname(bool short_hostname = false); +#ifdef ENABLE_UNUSED_FUNCTIONS std::string get_host_by_name(const std::string& hostname); +#endif } // namespace gkfs::rpc diff --git a/src/common/rpc/rpc_util.cpp b/src/common/rpc/rpc_util.cpp index 604749b6d..8b6ae2652 100644 --- a/src/common/rpc/rpc_util.cpp +++ b/src/common/rpc/rpc_util.cpp @@ -73,7 +73,7 @@ get_my_hostname(bool short_hostname) { return ""s; } - +#ifdef ENABLE_UNUSED_FUNCTIONS string get_host_by_name(const string& hostname) { int err = 0; @@ -102,5 +102,6 @@ get_host_by_name(const string& hostname) { freeaddrinfo(addr); return addr_str; } +#endif } // namespace gkfs::rpc \ No newline at end of file -- GitLab From a8dd42c9fbb6ec20f1e9d61b6b6e03e38d7d788d Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Mon, 23 May 2022 12:40:11 +0200 Subject: [PATCH 13/16] CHANGELOG for !141 --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19c3d3960..a179156ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### New +- Additional tests to increase code coverage ([!141](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/141)). ### Changed - Support parallelism for path resolution tests ([!145](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/145)). - Support parallelism for symlink tests ([!147](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/147)). @@ -14,7 +15,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed - Using `unlink` now fails if it is a directory unless the `AT_REMOVEDIR` flag is used (POSIX compliance) ([!139](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/139)). - Support glibc-2.34 or newer with syscall_intercept [!146](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/146)). - +- Additional `#ifdef` to remove unused code ([!141](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/141)) +### Removed +### Fixed +- Using `unlink` now fails if it is a directory unless the `AT_REMOVEDIR` flag is used (POSIX compliance) ([!139](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/139)). +- fchdir generate a SIGSEV in debug mode (due to log) ([!141](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/141)) ## [0.9.1] - 2022-04-29 ### New -- GitLab From 2917d583ed82f65ecf4253c28f7bf127a67526e8 Mon Sep 17 00:00:00 2001 From: rnou Date: Wed, 25 May 2022 13:00:03 +0200 Subject: [PATCH 14/16] Added GKFS_ENABLE_UNUSED_FUNCTIONS changed coverage tests name --- CHANGELOG.md | 1 + CMakeLists.txt | 2 + include/common/rpc/rpc_util.hpp | 2 +- src/client/gkfs_functions.cpp | 4 +- src/common/rpc/rpc_util.cpp | 2 +- tests/integration/CMakeLists.txt | 6 +- .../syscalls/test_error_operations.py | 170 ++++++++++++++++++ tests/integration/syscalls/test_syscalls.py | 58 ++++++ tests/unit/test_example_00.cpp | 45 +++++ tests/unit/test_example_01.cpp | 73 ++++++++ 10 files changed, 356 insertions(+), 7 deletions(-) create mode 100644 tests/integration/syscalls/test_error_operations.py create mode 100644 tests/integration/syscalls/test_syscalls.py create mode 100644 tests/unit/test_example_00.cpp create mode 100644 tests/unit/test_example_01.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index a179156ab..2c93c2d17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### New - Additional tests to increase code coverage ([!141](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/141)). +- GKFS_ENABLE_UNUSED_FUNCTIONS added to disable code to increase code coverage. ### Changed - Support parallelism for path resolution tests ([!145](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/145)). - Support parallelism for symlink tests ([!147](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/147)). diff --git a/CMakeLists.txt b/CMakeLists.txt index 60cfe42ce..9a41ef5e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,8 @@ if (GKFS_ENABLE_AGIOS) find_package(AGIOS REQUIRED) endif () +option(GKFS_ENABLE_UNUSED_FUNCTIONS "Enable unused functions compilation" OFF) + option(GKFS_ENABLE_PARALLAX "Enable Parallax db backend" OFF) option(GKFS_ENABLE_ROCKSDB "Enable ROCKSDB backend" ON) diff --git a/include/common/rpc/rpc_util.hpp b/include/common/rpc/rpc_util.hpp index 2cc3c5889..eb595596c 100644 --- a/include/common/rpc/rpc_util.hpp +++ b/include/common/rpc/rpc_util.hpp @@ -44,7 +44,7 @@ bool_to_merc_bool(bool state); std::string get_my_hostname(bool short_hostname = false); -#ifdef ENABLE_UNUSED_FUNCTIONS +#ifdef GKFS_ENABLE_UNUSED_FUNCTIONS std::string get_host_by_name(const std::string& hostname); #endif diff --git a/src/client/gkfs_functions.cpp b/src/client/gkfs_functions.cpp index 1ae6bb95f..23db5e0f0 100644 --- a/src/client/gkfs_functions.cpp +++ b/src/client/gkfs_functions.cpp @@ -411,7 +411,7 @@ gkfs_statfs(struct statfs* buf) { return 0; } -#ifdef ENABLE_UNUSED_FUNCTIONS +#ifdef GKFS_ENABLE_UNUSED_FUNCTIONS /** * gkfs wrapper for statvfs() system calls * errno may be set @@ -1096,7 +1096,7 @@ gkfs_getdents64(unsigned int fd, struct linux_dirent64* dirp, #ifdef HAS_SYMLINKS -#ifdef ENABLE_UNUSED_FUNCTIONS +#ifdef GKFS_ENABLE_UNUSED_FUNCTIONS /** * gkfs wrapper for make symlink() system calls * errno may be set diff --git a/src/common/rpc/rpc_util.cpp b/src/common/rpc/rpc_util.cpp index 8b6ae2652..46970b82f 100644 --- a/src/common/rpc/rpc_util.cpp +++ b/src/common/rpc/rpc_util.cpp @@ -73,7 +73,7 @@ get_my_hostname(bool short_hostname) { return ""s; } -#ifdef ENABLE_UNUSED_FUNCTIONS +#ifdef GKFS_ENABLE_UNUSED_FUNCTIONS string get_host_by_name(const string& hostname) { int err = 0; diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index 7b0c2a677..775cfe4f3 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -121,10 +121,10 @@ gkfs_add_python_test( ) gkfs_add_python_test( - NAME test_coverage + NAME test_syscalls PYTHON_VERSION 3.6 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/integration - SOURCE coverage/ + SOURCE syscalls/ ) if(GKFS_INSTALL_TESTS) @@ -189,7 +189,7 @@ if(GKFS_INSTALL_TESTS) PATTERN ".pytest_cache" EXCLUDE ) - install(DIRECTORY coverage + install(DIRECTORY syscalls DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration FILES_MATCHING REGEX ".*\\.py" diff --git a/tests/integration/syscalls/test_error_operations.py b/tests/integration/syscalls/test_error_operations.py new file mode 100644 index 000000000..a5ce6bd94 --- /dev/null +++ b/tests/integration/syscalls/test_error_operations.py @@ -0,0 +1,170 @@ +################################################################################ +# Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain # +# Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany # +# # +# This software was partially supported by the # +# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # +# # +# This software was partially supported by the # +# ADA-FS project under the SPPEXA project funded by the DFG. # +# # +# This file is part of GekkoFS. # +# # +# GekkoFS is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# GekkoFS is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with GekkoFS. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + +from sre_parse import State +import harness +from pathlib import Path +import errno +import stat +import os +import ctypes +import sh +import sys +import pytest +from harness.logger import logger + +nonexisting = "nonexisting" + + +def test_open_error(gkfs_daemon, gkfs_client): + + file = gkfs_daemon.mountdir / "file" + file2 = gkfs_daemon.mountdir / "file2" + file3 = gkfs_daemon.mountdir / "file3" + + flags = [os.O_PATH, os.O_APPEND, os.O_CREAT | os.O_DIRECTORY] + # create a file in gekkofs + + for flag in flags: + ret = gkfs_client.open(file, + flag, + stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + + assert ret.retval == -1 + assert ret.errno == errno.ENOTSUP + + + # Create file and recreate + ret = gkfs_client.open(file, os.O_CREAT | os.O_EXCL | os.O_WRONLY) + assert ret.retval == 10000 + + ret = gkfs_client.open(file, os.O_CREAT | os.O_EXCL | os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.EEXIST + + + # Create file and recreate + ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + # Undefined in man + ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + # RDWR + ret = gkfs_client.open(file2, os.O_RDWR) + assert ret.retval == 10000 + + # RD + ret = gkfs_client.open(file2, os.O_RDONLY) + assert ret.retval == 10000 + + # Truncate the file + ret = gkfs_client.open(file2, os.O_TRUNC | os.O_WRONLY) + assert ret.retval == 10000 + + # Open unexistent file + ret = gkfs_client.open(file3, os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.ENOENT + + ret = gkfs_client.open(file3, os.O_CREAT | stat.S_IFSOCK | os.O_EXCL | os.O_WRONLY) + assert ret.retval == 10000 + +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 + + +def test_check_parents(gkfs_daemon, gkfs_client): + file = gkfs_daemon.mountdir / "dir" / "file" + file2 = gkfs_daemon.mountdir / "file2" + file3 = gkfs_daemon.mountdir / "file2" / "file3" + + # Parent directory does not exist + ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.ENOENT + + # Create file + ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + # Create file over a file + ret = gkfs_client.open(file3, os.O_CREAT | os.O_WRONLY) + assert ret.retval == -1 + assert ret.errno == errno.ENOTDIR + + +def test_dup(gkfs_daemon, gkfs_client): + file = gkfs_daemon.mountdir / "file" + + ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + ret = gkfs_client.dup_validate(file) + assert ret.retval == 0 + assert ret.errno == 0 + diff --git a/tests/integration/syscalls/test_syscalls.py b/tests/integration/syscalls/test_syscalls.py new file mode 100644 index 000000000..539593838 --- /dev/null +++ b/tests/integration/syscalls/test_syscalls.py @@ -0,0 +1,58 @@ +################################################################################ +# Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain # +# Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany # +# # +# This software was partially supported by the # +# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # +# # +# This software was partially supported by the # +# ADA-FS project under the SPPEXA project funded by the DFG. # +# # +# This file is part of GekkoFS. # +# # +# GekkoFS is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# GekkoFS is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with GekkoFS. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + +from sre_parse import State +import harness +from pathlib import Path +import errno +import stat +import os +import ctypes +import sys +import pytest +from harness.logger import logger +import ctypes +nonexisting = "nonexisting" + + +def test_syscalls(gkfs_daemon, gkfs_client): + + file = gkfs_daemon.mountdir / "file" + + ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) + assert ret.retval == 10000 + + + ret = gkfs_client.syscall_coverage(file) + assert ret.syscall == "ALLOK" + assert ret.retval == 0 + assert ret.errno == 0 + + + + diff --git a/tests/unit/test_example_00.cpp b/tests/unit/test_example_00.cpp new file mode 100644 index 000000000..1b615220b --- /dev/null +++ b/tests/unit/test_example_00.cpp @@ -0,0 +1,45 @@ +/* + Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#include +#include + +unsigned int Factorial( unsigned int number ) { + return number <= 1 ? number : Factorial(number-1)*number; +} + +TEST_CASE( "Factorials are computed", "[factorial]" ) { + REQUIRE( Factorial(1) == 1 ); + REQUIRE( Factorial(2) == 2 ); + REQUIRE( Factorial(3) == 6 ); + REQUIRE( Factorial(10) == 3628800 ); +} + +TEST_CASE( "Two and Two is Four", "[2+2=4]" ) { + REQUIRE( 2+2 == 4 ); +} diff --git a/tests/unit/test_example_01.cpp b/tests/unit/test_example_01.cpp new file mode 100644 index 000000000..bef585f44 --- /dev/null +++ b/tests/unit/test_example_01.cpp @@ -0,0 +1,73 @@ +/* + Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + This file is part of GekkoFS. + + GekkoFS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GekkoFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GekkoFS. If not, see . + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#include +#include + +SCENARIO( "vectors can be sized and resized", "[vector]" ) { + + GIVEN( "A vector with some items" ) { + std::vector 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 ); + } + } + } +} -- GitLab From 480afe8ff6e11fabf5df41cdbf16551aeed4a9ea Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Thu, 26 May 2022 06:06:37 +0000 Subject: [PATCH 15/16] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 27394eee5..4c5f83afe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -137,7 +137,7 @@ gkfs:integration: needs: ['gkfs'] parallel: matrix: - - SUBTEST: [ data, status, coverage, directories, operations, position, shell ] + - SUBTEST: [ data, status, syscalls, directories, operations, position, shell ] script: ## run tests -- GitLab From b1b3e5198e78c8fdcc81af553b56709c03270ae1 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Thu, 26 May 2022 07:01:23 +0000 Subject: [PATCH 16/16] Deleted tests/integration/coverage/test_error_operations.py, tests/integration/coverage/test_syscalls.py files --- .../coverage/test_error_operations.py | 170 ------------------ tests/integration/coverage/test_syscalls.py | 58 ------ 2 files changed, 228 deletions(-) delete mode 100644 tests/integration/coverage/test_error_operations.py delete mode 100644 tests/integration/coverage/test_syscalls.py diff --git a/tests/integration/coverage/test_error_operations.py b/tests/integration/coverage/test_error_operations.py deleted file mode 100644 index a5ce6bd94..000000000 --- a/tests/integration/coverage/test_error_operations.py +++ /dev/null @@ -1,170 +0,0 @@ -################################################################################ -# Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain # -# Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany # -# # -# This software was partially supported by the # -# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # -# # -# This software was partially supported by the # -# ADA-FS project under the SPPEXA project funded by the DFG. # -# # -# This file is part of GekkoFS. # -# # -# GekkoFS is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# GekkoFS is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with GekkoFS. If not, see . # -# # -# SPDX-License-Identifier: GPL-3.0-or-later # -################################################################################ - -from sre_parse import State -import harness -from pathlib import Path -import errno -import stat -import os -import ctypes -import sh -import sys -import pytest -from harness.logger import logger - -nonexisting = "nonexisting" - - -def test_open_error(gkfs_daemon, gkfs_client): - - file = gkfs_daemon.mountdir / "file" - file2 = gkfs_daemon.mountdir / "file2" - file3 = gkfs_daemon.mountdir / "file3" - - flags = [os.O_PATH, os.O_APPEND, os.O_CREAT | os.O_DIRECTORY] - # create a file in gekkofs - - for flag in flags: - ret = gkfs_client.open(file, - flag, - stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) - - assert ret.retval == -1 - assert ret.errno == errno.ENOTSUP - - - # Create file and recreate - ret = gkfs_client.open(file, os.O_CREAT | os.O_EXCL | os.O_WRONLY) - assert ret.retval == 10000 - - ret = gkfs_client.open(file, os.O_CREAT | os.O_EXCL | os.O_WRONLY) - assert ret.retval == -1 - assert ret.errno == errno.EEXIST - - - # Create file and recreate - ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) - assert ret.retval == 10000 - # Undefined in man - ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) - assert ret.retval == 10000 - - # RDWR - ret = gkfs_client.open(file2, os.O_RDWR) - assert ret.retval == 10000 - - # RD - ret = gkfs_client.open(file2, os.O_RDONLY) - assert ret.retval == 10000 - - # Truncate the file - ret = gkfs_client.open(file2, os.O_TRUNC | os.O_WRONLY) - assert ret.retval == 10000 - - # Open unexistent file - ret = gkfs_client.open(file3, os.O_WRONLY) - assert ret.retval == -1 - assert ret.errno == errno.ENOENT - - ret = gkfs_client.open(file3, os.O_CREAT | stat.S_IFSOCK | os.O_EXCL | os.O_WRONLY) - assert ret.retval == 10000 - -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 - - -def test_check_parents(gkfs_daemon, gkfs_client): - file = gkfs_daemon.mountdir / "dir" / "file" - file2 = gkfs_daemon.mountdir / "file2" - file3 = gkfs_daemon.mountdir / "file2" / "file3" - - # Parent directory does not exist - ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) - assert ret.retval == -1 - assert ret.errno == errno.ENOENT - - # Create file - ret = gkfs_client.open(file2, os.O_CREAT | os.O_WRONLY) - assert ret.retval == 10000 - - # Create file over a file - ret = gkfs_client.open(file3, os.O_CREAT | os.O_WRONLY) - assert ret.retval == -1 - assert ret.errno == errno.ENOTDIR - - -def test_dup(gkfs_daemon, gkfs_client): - file = gkfs_daemon.mountdir / "file" - - ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) - assert ret.retval == 10000 - - ret = gkfs_client.dup_validate(file) - assert ret.retval == 0 - assert ret.errno == 0 - diff --git a/tests/integration/coverage/test_syscalls.py b/tests/integration/coverage/test_syscalls.py deleted file mode 100644 index 539593838..000000000 --- a/tests/integration/coverage/test_syscalls.py +++ /dev/null @@ -1,58 +0,0 @@ -################################################################################ -# Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain # -# Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany # -# # -# This software was partially supported by the # -# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # -# # -# This software was partially supported by the # -# ADA-FS project under the SPPEXA project funded by the DFG. # -# # -# This file is part of GekkoFS. # -# # -# GekkoFS is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# GekkoFS is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with GekkoFS. If not, see . # -# # -# SPDX-License-Identifier: GPL-3.0-or-later # -################################################################################ - -from sre_parse import State -import harness -from pathlib import Path -import errno -import stat -import os -import ctypes -import sys -import pytest -from harness.logger import logger -import ctypes -nonexisting = "nonexisting" - - -def test_syscalls(gkfs_daemon, gkfs_client): - - file = gkfs_daemon.mountdir / "file" - - ret = gkfs_client.open(file, os.O_CREAT | os.O_WRONLY) - assert ret.retval == 10000 - - - ret = gkfs_client.syscall_coverage(file) - assert ret.syscall == "ALLOK" - assert ret.retval == 0 - assert ret.errno == 0 - - - - -- GitLab