Skip to content

Commit

Permalink
[?] Add test for delay rule locking API.
Browse files Browse the repository at this point in the history
  • Loading branch information
korydraughn committed Nov 29, 2024
1 parent 052aff7 commit 6f6c57f
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ set(
data_object_modify_info
data_object_proxy
delay_hints_parser
delay_rule_locking_api
dns_cache
dstream
environment_variables
Expand Down
11 changes: 11 additions & 0 deletions unit_tests/cmake/test_config/irods_delay_rule_locking_api.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
set(IRODS_TEST_TARGET irods_delay_rule_locking_api)

set(IRODS_TEST_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/test_delay_rule_locking_api.cpp)

set(IRODS_TEST_INCLUDE_PATH ${IRODS_EXTERNALS_FULLPATH_BOOST}/include)

set(IRODS_TEST_LINK_LIBRARIES irods_client
irods_common
fmt::fmt
nlohmann_json::nlohmann_json)
149 changes: 149 additions & 0 deletions unit_tests/src/test_delay_rule_locking_api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include <catch2/catch.hpp>

#include "irods/client_connection.hpp"
#include "irods/delay_rule_lock.h"
#include "irods/delay_rule_unlock.h"
#include "irods/genquery2.h"
#include "irods/getRodsEnv.h"
#include "irods/irods_at_scope_exit.hpp"
#include "irods/irods_query.hpp"
#include "irods/rcMisc.h"
#include "irods/rodsClient.h"
#include "irods/rodsDef.h"
#include "irods/rodsErrorTable.h"

#include <boost/asio/ip/host_name.hpp>
#include <fmt/format.h>
#include <nlohmann/json.hpp>

#include <unistd.h>

#include <cstdlib>
#include <cstring>
#include <string>
#include <utility>

auto delete_all_delay_rules() -> int;
auto create_delay_rule(const std::string& _rule) -> int;

// NOLINTNEXTLINE(readability-function-cognitive-complexity)
TEST_CASE("lock and unlock delay rule")
{
load_client_api_plugins();

irods::experimental::client_connection conn;

// Delete all existing delay rules to avoid issues with the tests.
REQUIRE(delete_all_delay_rules() == 0);

// Delete the delay rule regardless of the test results.
irods::at_scope_exit_unsafe delete_delay_rules{[] { delete_all_delay_rules(); }};

// Schedule a delay rule for execution in the distant future. The delay rule
// MUST NOT be executed by the delay server. It is just a placeholder to test
// the delay rule locking API.
constexpr const char* rule = R"___(writeLine("serverLog", "SHOULD NOT EXECUTE BEFORE TEST COMPLETES"))___";
REQUIRE(create_delay_rule(rule) == 0);

std::string rule_id;
{
// Show the delay rule is not locked using GenQuery1.
irods::query query{static_cast<RcComm*>(conn), "select RULE_EXEC_ID where RULE_EXEC_LOCK_HOST = ''"};
REQUIRE_FALSE(query.empty());
// Capture the delay rule's ID so we can prove the locking API works as intended.
rule_id = std::move(query.front()[0]);
CHECK_FALSE(rule_id.empty());

// Show the delay rule is not locked using GenQuery2.
Genquery2Input input{};
irods::at_scope_exit_unsafe free_gq2_string{[&input] { clearGenquery2Input(&input); }};
input.query_string = strdup("select DELAY_RULE_ID where DELAY_RULE_LOCK_HOST = ''");

char* output{};
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory, cppcoreguidelines-no-malloc)
irods::at_scope_exit_unsafe free_output{[&output] { std::free(output); }};

CHECK(rc_genquery2(static_cast<RcComm*>(conn), &input, &output) == 0);
const auto rows = nlohmann::json::parse(output);
REQUIRE_FALSE(rows.empty());
CHECK(rows[0][0].get_ref<const std::string&>() == rule_id);
}

// Lock the delay rule.
DelayRuleLockInput lock_input{};
rule_id.copy(lock_input.rule_id, sizeof(DelayRuleLockInput::rule_id) - 1);
boost::asio::ip::host_name().copy(lock_input.lock_host, sizeof(DelayRuleLockInput::lock_host) - 1);
lock_input.lock_host_pid = getpid();
REQUIRE(rc_delay_rule_lock(static_cast<RcComm*>(conn), &lock_input) == 0);

{
// Show the delay rule is now locked using GenQuery1.
const auto query_string = fmt::format("select RULE_EXEC_LOCK_HOST, RULE_EXEC_LOCK_HOST_PID, RULE_EXEC_LOCK_TIME where RULE_EXEC_ID = '{}'", rule_id);
irods::query query{static_cast<RcComm*>(conn), query_string};
REQUIRE_FALSE(query.empty());
const auto row = query.front();
CHECK(row[0] == boost::asio::ip::host_name());
CHECK(row[1] == std::to_string(getpid()));
CHECK_FALSE(row[2].empty());

// Show the delay rule is now locked using GenQuery2.
Genquery2Input input{};
irods::at_scope_exit_unsafe free_gq2_string{[&input] { clearGenquery2Input(&input); }};
input.query_string = strdup(fmt::format("select DELAY_RULE_LOCK_HOST, DELAY_RULE_LOCK_HOST_PID, DELAY_RULE_LOCK_TIME where DELAY_RULE_ID = '{}'", rule_id).c_str());

char* output{};
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory, cppcoreguidelines-no-malloc)
irods::at_scope_exit_unsafe free_output{[&output] { std::free(output); }};

CHECK(rc_genquery2(static_cast<RcComm*>(conn), &input, &output) == 0);
const auto rows = nlohmann::json::parse(output);
REQUIRE_FALSE(rows.empty());
CHECK(rows[0][0].get_ref<const std::string&>() == boost::asio::ip::host_name());
CHECK(rows[0][1].get_ref<const std::string&>() == std::to_string(getpid()));
CHECK_FALSE(rows[0][2].get_ref<const std::string&>().empty());
}

// Unlock the delay rule.
DelayRuleUnlockInput unlock_input{};
rule_id.copy(unlock_input.rule_id, sizeof(DelayRuleUnlockInput::rule_id) - 1);
REQUIRE(rc_delay_rule_unlock(static_cast<RcComm*>(conn), &unlock_input) == 0);

{
// Show the delay rule is now unlocked using GenQuery1.
const auto query_string = fmt::format("select RULE_EXEC_LOCK_HOST, RULE_EXEC_LOCK_HOST_PID, RULE_EXEC_LOCK_TIME where RULE_EXEC_ID = '{}'", rule_id);
irods::query query{static_cast<RcComm*>(conn), query_string};
REQUIRE_FALSE(query.empty());
const auto row = query.front();
CHECK(row[0].empty());
CHECK(row[1].empty());
CHECK(row[2].empty());

// Show the delay rule is now unlocked using GenQuery2.
Genquery2Input input{};
irods::at_scope_exit_unsafe free_gq2_string{[&input] { clearGenquery2Input(&input); }};
input.query_string = strdup(fmt::format("select DELAY_RULE_LOCK_HOST, DELAY_RULE_LOCK_HOST_PID, DELAY_RULE_LOCK_TIME where DELAY_RULE_ID = '{}'", rule_id).c_str());

char* output{};
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory, cppcoreguidelines-no-malloc)
irods::at_scope_exit_unsafe free_output{[&output] { std::free(output); }};

CHECK(rc_genquery2(static_cast<RcComm*>(conn), &input, &output) == 0);
const auto rows = nlohmann::json::parse(output);
REQUIRE_FALSE(rows.empty());
CHECK(rows[0][0].get_ref<const std::string&>().empty());
CHECK(rows[0][1].get_ref<const std::string&>().empty());
CHECK(rows[0][2].get_ref<const std::string&>().empty());
}
}

auto delete_all_delay_rules() -> int
{
// NOLINTNEXTLINE(cert-env33-c)
return std::system("iqdel -a");
} // delete_all_delay_rules

auto create_delay_rule(const std::string& _rule) -> int
{
// NOLINTNEXTLINE(cert-env33-c)
return std::system(fmt::format(R"___(irule -r irods_rule_engine_plugin-irods_rule_language-instance 'delay("<PLUSET>100000</PLUSET>") {{ {} }}' null null)___", _rule).c_str());
} // create_delay_rule
1 change: 1 addition & 0 deletions unit_tests/unit_tests_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"irods_data_object_modify_info",
"irods_data_object_proxy",
"irods_delay_hints_parser",
"irods_delay_rule_locking_api",
"irods_dns_cache",
"irods_dstream",
"irods_environment_variables",
Expand Down

0 comments on commit 6f6c57f

Please sign in to comment.