diff --git a/contrib/atf/atf-c/tc.h b/contrib/atf/atf-c/tc.h --- a/contrib/atf/atf-c/tc.h +++ b/contrib/atf/atf-c/tc.h @@ -106,6 +106,7 @@ ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2); void atf_tc_pass(void) ATF_DEFS_ATTRIBUTE_NORETURN; +void atf_tc_require_kld(const char *); void atf_tc_require_prog(const char *); void atf_tc_skip(const char *, ...) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2) diff --git a/contrib/atf/atf-c/tc.c b/contrib/atf/atf-c/tc.c --- a/contrib/atf/atf-c/tc.c +++ b/contrib/atf/atf-c/tc.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -103,6 +104,7 @@ static void errno_test(struct context *, const char *, const size_t, const int, const char *, const bool, void (*)(struct context *, atf_dynstr_t *)); +static atf_error_t check_kld(struct context *, const char *); static atf_error_t check_prog_in_dir(const char *, void *); static atf_error_t check_prog(struct context *, const char *); @@ -460,6 +462,19 @@ } } +static atf_error_t +check_kld(struct context *ctx, const char *kld) +{ + if (!kld_isloaded(kld)) { + atf_dynstr_t reason; + + format_reason_fmt(&reason, NULL, 0, "The required kld %s " + "is not loaded", kld); + fail_requirement(ctx, &reason); + } + return atf_no_error(); +} + struct prog_found_pair { const char *prog; bool found; @@ -829,6 +844,7 @@ static void _atf_tc_fail_requirement(struct context *, const char *, const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; +static void _atf_tc_require_kld(struct context *, const char *); static void _atf_tc_require_prog(struct context *, const char *); static void _atf_tc_skip(struct context *, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; @@ -908,6 +924,12 @@ UNREACHABLE; } +static void +_atf_tc_require_kld(struct context *ctx, const char *kld) +{ + check_fatal_error(check_kld(ctx, kld)); +} + static void _atf_tc_require_prog(struct context *ctx, const char *prog) { @@ -1154,6 +1176,14 @@ _atf_tc_pass(&Current); } +void +atf_tc_require_kld(const char *kld) +{ + PRE(Current.tc != NULL); + + _atf_tc_require_kld(&Current, kld); +} + void atf_tc_require_prog(const char *prog) { diff --git a/contrib/atf/atf-sh/libatf-sh.subr b/contrib/atf/atf-sh/libatf-sh.subr --- a/contrib/atf/atf-sh/libatf-sh.subr +++ b/contrib/atf/atf-sh/libatf-sh.subr @@ -353,6 +353,18 @@ esac } +# +# atf_require_kld kld +# +# Checks that the given kernel module is loaded. If it is not, +# automatically skips the test case with an appropriate message. +# +atf_require_kld() +{ + kldstat -q "${1}" || \ + atf_skip "The required module ${1} is not loaded" +} + # # atf_set varname val1 [.. valN] # diff --git a/contrib/kyua/engine/atf_list.cpp b/contrib/kyua/engine/atf_list.cpp --- a/contrib/kyua/engine/atf_list.cpp +++ b/contrib/kyua/engine/atf_list.cpp @@ -129,6 +129,8 @@ mdbuilder.set_string("required_configs", value); } else if (name == "require.files") { mdbuilder.set_string("required_files", value); + } else if (name == "require.klds") { + mdbuilder.set_string("required_modules", value); } else if (name == "require.machine") { mdbuilder.set_string("allowed_platforms", value); } else if (name == "require.memory") { diff --git a/contrib/kyua/engine/requirements.cpp b/contrib/kyua/engine/requirements.cpp --- a/contrib/kyua/engine/requirements.cpp +++ b/contrib/kyua/engine/requirements.cpp @@ -41,6 +41,8 @@ #include "utils/sanity.hpp" #include "utils/units.hpp" +#include + namespace config = utils::config; namespace fs = utils::fs; namespace passwd = utils::passwd; @@ -220,6 +222,24 @@ } +/// Checks if all required modules are loaded. +/// +/// \param required_programs Set of modules. +/// +/// \return Empty if the required modules are all loaded or an error +/// message otherwise. +static std::string +check_required_modules(const model::strings_set& required_modules) +{ + for (model::strings_set::const_iterator iter = required_modules.begin(); + iter != required_modules.end(); iter++) { + if (!kld_isloaded((*iter).c_str())) + return F("Required module '%s' not loaded") % *iter; + } + return ""; +} + + /// Checks if the current system has the specified amount of memory. /// /// \param required_memory Amount of required physical memory, or zero if not @@ -312,6 +332,10 @@ if (!reason.empty()) return reason; + reason = check_required_modules(md.required_modules()); + if (!reason.empty()) + return reason; + reason = check_required_memory(md.required_memory()); if (!reason.empty()) return reason; diff --git a/contrib/kyua/model/metadata.hpp b/contrib/kyua/model/metadata.hpp --- a/contrib/kyua/model/metadata.hpp +++ b/contrib/kyua/model/metadata.hpp @@ -76,6 +76,7 @@ const utils::units::bytes& required_disk_space(void) const; const paths_set& required_files(void) const; const utils::units::bytes& required_memory(void) const; + const strings_set& required_modules(void) const; const paths_set& required_programs(void) const; const std::string& required_user(void) const; const utils::datetime::delta& timeout(void) const; @@ -121,6 +122,7 @@ metadata_builder& set_required_disk_space(const utils::units::bytes&); metadata_builder& set_required_files(const paths_set&); metadata_builder& set_required_memory(const utils::units::bytes&); + metadata_builder& set_required_modules(const strings_set&); metadata_builder& set_required_programs(const paths_set&); metadata_builder& set_required_user(const std::string&); metadata_builder& set_string(const std::string&, const std::string&); diff --git a/contrib/kyua/model/metadata.cpp b/contrib/kyua/model/metadata.cpp --- a/contrib/kyua/model/metadata.cpp +++ b/contrib/kyua/model/metadata.cpp @@ -256,6 +256,7 @@ tree.define< bytes_node >("required_disk_space"); tree.define< paths_set_node >("required_files"); tree.define< bytes_node >("required_memory"); + tree.define< config::strings_set_node >("required_modules"); tree.define< paths_set_node >("required_programs"); tree.define< user_node >("required_user"); tree.define< delta_node >("timeout"); @@ -282,6 +283,7 @@ tree.set< bytes_node >("required_disk_space", units::bytes(0)); tree.set< paths_set_node >("required_files", model::paths_set()); tree.set< bytes_node >("required_memory", units::bytes(0)); + tree.set< config::strings_set_node >("required_modules", model::strings_set()); tree.set< paths_set_node >("required_programs", model::paths_set()); tree.set< user_node >("required_user", ""); // TODO(jmmv): We shouldn't be setting a default timeout like this. See @@ -597,6 +599,20 @@ } +/// Returns the list of modules needed by the test. +/// +/// \return Set of strings. +const model::strings_set& +model::metadata::required_modules(void) const +{ + if (_pimpl->props.is_set("required_modules")) { + return _pimpl->props.lookup< config::strings_set_node >("required_modules"); + } else { + return get_defaults().lookup< config::strings_set_node >("required_modules"); + } +} + + /// Returns the list of programs needed by the test. /// /// \return Set of paths. diff --git a/lib/atf/libatf-c/Makefile b/lib/atf/libatf-c/Makefile --- a/lib/atf/libatf-c/Makefile +++ b/lib/atf/libatf-c/Makefile @@ -31,6 +31,7 @@ LIB= atf-c PRIVATELIB= true SHLIB_MAJOR= 1 +LIBADD= util ATF= ${SRCTOP}/contrib/atf .PATH: ${ATF} diff --git a/tests/sys/fs/tarfs/tarfs_test.sh b/tests/sys/fs/tarfs/tarfs_test.sh --- a/tests/sys/fs/tarfs/tarfs_test.sh +++ b/tests/sys/fs/tarfs/tarfs_test.sh @@ -48,7 +48,6 @@ } tarfs_setup() { - kldload -n tarfs || atf_skip "This test requires tarfs and could not load it" mkdir "${mnt}" } @@ -60,6 +59,7 @@ tarfs_basic_head() { atf_set "descr" "Basic function test" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_basic_body() { tarfs_setup @@ -87,6 +87,7 @@ tarfs_basic_gnu_head() { atf_set "descr" "Basic function test using GNU tar" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" atf_set "require.progs" "gtar" } tarfs_basic_gnu_body() { @@ -101,6 +102,7 @@ tarfs_notdir_device_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_notdir_device_body() { tarfs_setup @@ -121,6 +123,7 @@ tarfs_notdir_device_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_device_gnu_body() { @@ -135,6 +138,7 @@ tarfs_notdir_dot_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_notdir_dot_body() { tarfs_setup @@ -155,6 +159,7 @@ tarfs_notdir_dot_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_dot_gnu_body() { @@ -169,6 +174,7 @@ tarfs_notdir_dotdot_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_notdir_dotdot_body() { tarfs_setup @@ -189,6 +195,7 @@ tarfs_notdir_dotdot_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_dotdot_gnu_body() { @@ -203,6 +210,7 @@ tarfs_notdir_file_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_notdir_file_body() { tarfs_setup @@ -223,6 +231,7 @@ tarfs_notdir_file_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_file_gnu_body() { @@ -237,6 +246,7 @@ tarfs_emptylink_head() { atf_set "descr" "Regression test for PR 277360: empty link target" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_emptylink_body() { tarfs_setup @@ -256,6 +266,7 @@ tarfs_linktodir_head() { atf_set "descr" "Regression test for PR 277360: link to directory" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_linktodir_body() { tarfs_setup @@ -276,6 +287,7 @@ tarfs_linktononexistent_head() { atf_set "descr" "Regression test for PR 277360: link to nonexistent target" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_linktononexistent_body() { tarfs_setup @@ -293,6 +305,7 @@ tarfs_checksum_head() { atf_set "descr" "Verify that the checksum covers header padding" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_checksum_body() { tarfs_setup @@ -313,6 +326,7 @@ tarfs_long_names_head() { atf_set "descr" "Verify that tarfs supports long file names" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_long_names_body() { tarfs_setup @@ -337,6 +351,7 @@ tarfs_long_paths_head() { atf_set "descr" "Verify that tarfs supports long paths" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" } tarfs_long_paths_body() { tarfs_setup @@ -361,6 +376,7 @@ tarfs_git_archive_head() { atf_set "descr" "Verify that tarfs supports archives created by git" atf_set "require.user" "root" + atf_set "require.klds" "tarfs" atf_set "require.progs" "git" } tarfs_git_archive_body() { diff --git a/tests/sys/net/if_wg.sh b/tests/sys/net/if_wg.sh --- a/tests/sys/net/if_wg.sh +++ b/tests/sys/net/if_wg.sh @@ -34,6 +34,7 @@ { atf_set descr 'Create a wg(4) tunnel over an epair and pass traffic between jails' atf_set require.user root + atf_set require.klds if_wg } wg_basic_body() @@ -41,8 +42,6 @@ local epair pri1 pri2 pub1 pub2 wg1 wg2 local endpoint1 endpoint2 tunnel1 tunnel2 - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - pri1=$(wg genkey) pri2=$(wg genkey) @@ -97,6 +96,7 @@ { atf_set descr 'Create a wg(4) tunnel over an epair and pass traffic between jails with netmap' atf_set require.user root + atf_set require.klds if_wg netmap } wg_basic_netmap_body() @@ -105,9 +105,6 @@ local endpoint1 endpoint2 tunnel1 tunnel2 tunnel3 tunnel4 local pid status - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - kldload -n netmap || atf_skip "This test requires netmap and could not load it" - pri1=$(wg genkey) pri2=$(wg genkey) @@ -190,6 +187,7 @@ { atf_set descr 'Create a wg(4) interface with a shared pubkey between device and a peer' atf_set require.user root + atf_set require.klds if_wg } wg_key_peerdev_shared_body() @@ -197,8 +195,6 @@ local epair pri1 pub1 wg1 local endpoint1 tunnel1 - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - pri1=$(wg genkey) endpoint1=192.168.2.1 @@ -238,8 +234,6 @@ local epair pri1 pub1 pri2 wg1 wg2 local endpoint1 tunnel1 - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - pri1=$(wg genkey) pri2=$(wg genkey) @@ -283,6 +277,7 @@ { atf_set descr 'Create a wg(4) tunnel without epairs and pass traffic between jails' atf_set require.user root + atf_set require.klds if_wg } wg_vnet_parent_routing_body() @@ -290,8 +285,6 @@ local pri1 pri2 pub1 pub2 wg1 wg2 local tunnel1 tunnel2 - kldload -n if_wg - pri1=$(wg genkey) pri2=$(wg genkey) diff --git a/usr.bin/kyua/Makefile b/usr.bin/kyua/Makefile --- a/usr.bin/kyua/Makefile +++ b/usr.bin/kyua/Makefile @@ -13,7 +13,7 @@ PACKAGE= tests PROG_CXX= kyua SRCS= main.cpp -LIBADD= lutok sqlite3 +LIBADD= lutok sqlite3 util MAN= kyua-about.1 \ kyua-config.1 \