Rework datastore tests
Sysrepo now supports parallelized tests. Use the new environmental
variables to implement this in netconf-cli. All of the tests now get
their own clean environment:
- Fresh repository and separate shm prefix. These get cleaned before and
after tests. The only thing that gets left are some empty directories.
- Its own model to test on.
- Separate Netopeer2 daemon: only for netconf tests - that means no
`sleep 5` for sysrepo-only tests. So no useless waiting. Wow! The daemon
also runs with its argv[0] changed to something recognizable for
`pkill`. That means that if Netopeer2 crashes for some reason, pkill
will notify me.
Side note: These changes somehow changed some of the linking, so hopefully I got
those right.
Change-Id: Ib0e582ef03fc559b24203af8afb2a295a6318ca9
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d6b26ff..3ecbe0b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -102,7 +102,7 @@
src/sysrepo_access.cpp
)
-target_link_libraries(sysrepoaccess PUBLIC datastoreaccess ast_values PRIVATE PkgConfig::SYSREPO)
+target_link_libraries(sysrepoaccess PUBLIC datastoreaccess ast_values PRIVATE PkgConfig::SYSREPO PkgConfig::LIBYANG)
add_library(netconfaccess STATIC
src/netconf-client.cpp
@@ -207,34 +207,12 @@
message(FATAL_ERROR "Unable to find netopeer2-server, set NETOPEER2_EXECUTABLE manually.")
endif()
- set(NETOPEER_SOCKET_PATH "${CMAKE_CURRENT_BINARY_DIR}/netopeer2-server.sock")
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/start_daemons.sh.in ${CMAKE_CURRENT_BINARY_DIR}/start_daemons.sh @ONLY)
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/netopeer_vars.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/netopeer_vars.hpp @ONLY)
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/yang_access_test_vars.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/yang_access_test_vars.hpp @ONLY)
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/manage_nacm.sh.in ${CMAKE_CURRENT_BINARY_DIR}/manage_nacm.sh @ONLY)
+ pkg_get_variable(SYSREPO_SR_REPO_PATH sysrepo SR_REPO_PATH)
- function(setup_datastore_tests)
- add_test(NAME example-schema_init
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/sysrepoctl-manage-module.sh ${SYSREPOCTL_EXECUTABLE} ${SYSREPOCFG_EXECUTABLE} install ${CMAKE_CURRENT_SOURCE_DIR}/tests/example-schema.yang)
- add_test(NAME example-schema_cleanup
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/sysrepoctl-manage-module.sh ${SYSREPOCTL_EXECUTABLE} ${SYSREPOCFG_EXECUTABLE} uninstall ${CMAKE_CURRENT_SOURCE_DIR}/tests/example-schema.yang)
- add_test(NAME disable_nacm COMMAND ${CMAKE_CURRENT_BINARY_DIR}/manage_nacm.sh disable)
- add_test(NAME enable_nacm COMMAND ${CMAKE_CURRENT_BINARY_DIR}/manage_nacm.sh enable)
- add_test(NAME setup_netopeer COMMAND ${SYSREPOCFG_EXECUTABLE} --import=${CMAKE_CURRENT_SOURCE_DIR}/tests/netopeer-test-config.xml --datastore=startup --format=xml --module=ietf-netconf-server)
- add_test(NAME start_daemons COMMAND ${CMAKE_CURRENT_BINARY_DIR}/start_daemons.sh)
- add_test(NAME kill_daemons COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/kill_daemons.sh)
- set_tests_properties(disable_nacm PROPERTIES FIXTURES_SETUP nacm_disabled)
- set_tests_properties(enable_nacm PROPERTIES FIXTURES_CLEANUP nacm_disabled)
- set_tests_properties(example-schema_init PROPERTIES FIXTURES_SETUP example-schema_setup)
- set_tests_properties(setup_netopeer PROPERTIES FIXTURES_SETUP netopeer_configured)
- set_tests_properties(example-schema_cleanup PROPERTIES FIXTURES_CLEANUP example-schema_setup)
- set_tests_properties(setup_netopeer start_daemons kill_daemons example-schema_init example-schema_cleanup disable_nacm enable_nacm PROPERTIES RESOURCE_LOCK sysrepo)
- set_property(TEST setup_netopeer APPEND PROPERTY FIXTURES_REQUIRED nacm_disabled)
- set_property(TEST setup_netopeer APPEND PROPERTY FIXTURES_REQUIRED example-schema_setup)
- set_tests_properties(start_daemons PROPERTIES FIXTURES_REQUIRED netopeer_configured FIXTURES_SETUP netopeer_running)
- set_property(TEST example-schema_cleanup APPEND PROPERTY DEPENDS kill_daemons)
- set_property(TEST kill_daemons APPEND PROPERTY FIXTURES_CLEANUP netopeer_running)
- endfunction()
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test_repositories)
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test_sockets)
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/yang_access_test_vars.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/yang_access_test_vars.hpp @ONLY)
function(cli_test name)
if (${ARGC} GREATER 1) # this is how CMake does optional arguments
@@ -255,9 +233,8 @@
function(datastore_test_impl name model backend)
set(TESTNAME test_${name}_${backend})
+
cli_test(${name}_${backend} ${name}.cpp)
- set_tests_properties(${TESTNAME} PROPERTIES FIXTURES_REQUIRED ${model}_setup RESOURCE_LOCK sysrepo)
- set_property(TEST ${TESTNAME} APPEND PROPERTY FIXTURES_REQUIRED netopeer_running)
target_include_directories(${TESTNAME} PRIVATE ${PROJECT_SOURCE_DIR}/tests/mock)
if (${backend} STREQUAL "sysrepo")
target_link_libraries(${TESTNAME} sysrepoaccess)
@@ -271,6 +248,19 @@
target_link_libraries(${TESTNAME} yangschema sysreposubscription proxydatastore PkgConfig::SYSREPO)
target_compile_definitions(${TESTNAME} PRIVATE ${backend}_BACKEND)
+ set_tests_properties(${TESTNAME} PROPERTIES FIXTURES_REQUIRED ${TESTNAME}_setup)
+
+ add_test(NAME ${TESTNAME}_init COMMAND ${CMAKE_CURRENT_BINARY_DIR}/init_datastore.bash "${model}" "${backend}")
+ set_tests_properties(${TESTNAME}_init PROPERTIES FIXTURES_SETUP ${TESTNAME}_setup)
+ add_test(NAME ${TESTNAME}_cleanup COMMAND ${CMAKE_CURRENT_BINARY_DIR}/cleanup_datastore.bash "${backend}")
+ set_tests_properties(${TESTNAME}_cleanup PROPERTIES FIXTURES_CLEANUP ${TESTNAME}_setup)
+
+ set_property(TEST ${TESTNAME} ${TESTNAME}_init ${TESTNAME}_cleanup APPEND PROPERTY ENVIRONMENT
+ "SYSREPO_REPOSITORY_PATH=${CMAKE_CURRENT_BINARY_DIR}/test_repositories/${TESTNAME}"
+ "SYSREPO_SHM_PREFIX=netconf-cli_${TESTNAME}"
+ "NETOPEER_SOCKET=${CMAKE_CURRENT_BINARY_DIR}/test_sockets/${TESTNAME}.sock"
+ )
+
endfunction()
function(datastore_test name model)
@@ -298,9 +288,14 @@
target_link_libraries(test_path_utils path)
cli_test(keyvalue_completion)
- setup_datastore_tests()
- datastore_test(datastore_access example-schema)
- datastore_test(data_query example-schema)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/init_datastore.bash.in
+ ${CMAKE_CURRENT_BINARY_DIR}/init_datastore.bash @ONLY)
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/cleanup_datastore.bash.in
+ ${CMAKE_CURRENT_BINARY_DIR}/cleanup_datastore.bash @ONLY)
+
+ datastore_test(datastore_access ${CMAKE_CURRENT_SOURCE_DIR}/tests/example-schema.yang)
+ datastore_test(data_query ${CMAKE_CURRENT_SOURCE_DIR}/tests/example-schema.yang)
endif()
option(WITH_PYTHON_BINDINGS "Create and install Python3 bindings for accessing datastores" OFF)
@@ -315,11 +310,21 @@
target_link_libraries(sysrepo_subscription_py PUBLIC sysreposubscription utils)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/python_netconfaccess.py
- ${CMAKE_CURRENT_BINARY_DIR}/tests_python_netconfaccess.py @ONLY)
+ ${CMAKE_CURRENT_BINARY_DIR}/tests_python_netconfaccess.py COPYONLY)
+
add_test(NAME test_netconf_cli_py COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/tests_python_netconfaccess.py)
- set_tests_properties(test_netconf_cli_py PROPERTIES RESOURCE_LOCK sysrepo)
- set_property(TEST test_netconf_cli_py APPEND PROPERTY FIXTURES_REQUIRED netopeer_running)
- set_property(TEST test_netconf_cli_py APPEND PROPERTY FIXTURES_REQUIRED example-schema_setup)
+ set_tests_properties(test_netconf_cli_py PROPERTIES FIXTURES_REQUIRED test_netconf_cli_py_setup)
+
+ add_test(NAME test_netconf_cli_py_init COMMAND ${CMAKE_CURRENT_BINARY_DIR}/init_datastore.bash ${CMAKE_CURRENT_SOURCE_DIR}/tests/example-schema.yang "netconf")
+ set_tests_properties(test_netconf_cli_py_init PROPERTIES FIXTURES_SETUP test_netconf_cli_py_setup)
+ add_test(NAME test_netconf_cli_py_cleanup COMMAND ${CMAKE_CURRENT_BINARY_DIR}/cleanup_datastore.bash "netconf")
+ set_tests_properties(test_netconf_cli_py_cleanup PROPERTIES FIXTURES_CLEANUP test_netconf_cli_py_setup)
+
+ set_property(TEST test_netconf_cli_py test_netconf_cli_py_init test_netconf_cli_py_cleanup APPEND PROPERTY ENVIRONMENT
+ "SYSREPO_REPOSITORY_PATH=${CMAKE_CURRENT_BINARY_DIR}/test_repositories/test_netconf_cli_py"
+ "SYSREPO_SHM_PREFIX=netconf-cli_test_netconf_cli_py"
+ "NETOPEER_SOCKET=${CMAKE_CURRENT_BINARY_DIR}/test_sockets/test_netconf_cli_py.sock"
+ )
set(sanitizer_active OFF)
# FIXME: this just sucks. The detection is very unreliable (one could use something like
diff --git a/tests/cleanup_datastore.bash.in b/tests/cleanup_datastore.bash.in
new file mode 100755
index 0000000..66df88c
--- /dev/null
+++ b/tests/cleanup_datastore.bash.in
@@ -0,0 +1,25 @@
+set -eux
+
+if [[ $(dirname "$(dirname "$(realpath "$SYSREPO_REPOSITORY_PATH")")") != "@CMAKE_CURRENT_BINARY_DIR@" ]]; then
+ echo "\$SYSREPO_REPOSITORY_PATH is not inside the build dir! Aborting. ($SYSREPO_REPOSITORY_PATH)"
+ exit 1
+fi
+
+if [[ -z "$SYSREPO_SHM_PREFIX" ]]; then
+ echo '$SYSREPO_SHM_PREFIX is empty! Aborting.'
+ exit 1
+fi
+
+BACKEND="$1"
+shift
+if [[ "$BACKEND" = "netconf" ]]; then
+ # The `-f` argument is neccessary so that pkill matches the whole command
+ # line, including stuff set by `exec -a`. Otherwise it matches the name in
+ # /proc/{pid}/stat and that is usually limited to 15 characters, so
+ # netopeer2-server appears as netopeer2-serve
+ pkill -f "${SYSREPO_SHM_PREFIX}_netopeer2-server"
+ rm "$NETOPEER_SOCKET"
+fi
+
+rm -r "$SYSREPO_REPOSITORY_PATH"
+rm "/dev/shm/$SYSREPO_SHM_PREFIX"*
diff --git a/tests/data_query.cpp b/tests/data_query.cpp
index d6435a8..4aa597e 100644
--- a/tests/data_query.cpp
+++ b/tests/data_query.cpp
@@ -13,7 +13,6 @@
#include "sysrepo_access.hpp"
#elif defined(netconf_BACKEND)
#include "netconf_access.hpp"
-#include "netopeer_vars.hpp"
#elif defined(yang_BACKEND)
#include "yang_access.hpp"
#include "yang_access_test_vars.hpp"
@@ -40,7 +39,8 @@
#ifdef sysrepo_BACKEND
SysrepoAccess datastore(Datastore::Running);
#elif defined(netconf_BACKEND)
- NetconfAccess datastore(NETOPEER_SOCKET_PATH);
+ const auto NETOPEER_SOCKET = getenv("NETOPEER_SOCKET");
+ NetconfAccess datastore(NETOPEER_SOCKET);
#elif defined(yang_BACKEND)
YangAccess datastore;
datastore.addSchemaDir(schemaDir);
diff --git a/tests/datastore_access.cpp b/tests/datastore_access.cpp
index 68eac3a..cc97aa9 100644
--- a/tests/datastore_access.cpp
+++ b/tests/datastore_access.cpp
@@ -27,7 +27,6 @@
using OnKeyNotFound = std::runtime_error;
using OnExec = void;
#include "netconf_access.hpp"
-#include "netopeer_vars.hpp"
#elif defined(yang_BACKEND)
#include <fstream>
#include "yang_access.hpp"
@@ -122,7 +121,8 @@
#ifdef sysrepo_BACKEND
SysrepoAccess datastore(Datastore::Running);
#elif defined(netconf_BACKEND)
- NetconfAccess datastore(NETOPEER_SOCKET_PATH);
+ const auto NETOPEER_SOCKET = getenv("NETOPEER_SOCKET");
+ NetconfAccess datastore(NETOPEER_SOCKET);
#elif defined(yang_BACKEND)
TestYangAccess datastore;
datastore.addSchemaDir(schemaDir);
@@ -896,7 +896,8 @@
#ifdef sysrepo_BACKEND
auto datastore = std::make_shared<SysrepoAccess>(Datastore::Running);
#elif defined(netconf_BACKEND)
- auto datastore = std::make_shared<NetconfAccess>(NETOPEER_SOCKET_PATH);
+ const auto NETOPEER_SOCKET = getenv("NETOPEER_SOCKET");
+ auto datastore = std::make_shared<NetconfAccess>(NETOPEER_SOCKET);
#elif defined(yang_BACKEND)
auto datastore = std::make_shared<YangAccess>();
datastore->addSchemaDir(schemaDir);
diff --git a/tests/enable-nacm.xml b/tests/enable-nacm.xml
deleted file mode 100644
index 4a2f36a..0000000
--- a/tests/enable-nacm.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
- <enable-nacm>true</enable-nacm>
-</nacm>
diff --git a/tests/init_datastore.bash.in b/tests/init_datastore.bash.in
new file mode 100755
index 0000000..5aec0c0
--- /dev/null
+++ b/tests/init_datastore.bash.in
@@ -0,0 +1,43 @@
+set -eux
+export UBSAN_OPTIONS=halt_on_error=1 # UBSan doesn't stop on errors by default.
+
+if [[ $(dirname "$(dirname "$(realpath "$SYSREPO_REPOSITORY_PATH")")") != "@CMAKE_CURRENT_BINARY_DIR@" ]]; then
+ echo "\$SYSREPO_REPOSITORY_PATH is not inside the build dir! Aborting. ($SYSREPO_REPOSITORY_PATH)"
+ exit 1
+fi
+
+if [[ -z "$SYSREPO_SHM_PREFIX" ]]; then
+ echo '$SYSREPO_SHM_PREFIX is empty! Aborting.'
+ exit 1
+fi
+
+rm -rf "$SYSREPO_REPOSITORY_PATH"
+rm -rf "/dev/shm/$SYSREPO_SHM_PREFIX"*
+cp -r "@SYSREPO_SR_REPO_PATH@" "$SYSREPO_REPOSITORY_PATH"
+
+SYSREPOCTL="@SYSREPOCTL_EXECUTABLE@"
+SYSREPOCFG="@SYSREPOCFG_EXECUTABLE@"
+
+MODULE="$1"
+YANG_DIR=$(dirname "$1")
+shift
+
+# Install the module
+"$SYSREPOCTL" --search-dirs "$YANG_DIR" --install "$MODULE" -a
+
+BACKEND="$1"
+shift
+if [[ "$BACKEND" = "netconf" ]]; then
+ NETOPEER2="@NETOPEER2_EXECUTABLE@"
+ # Setup netopeer config
+ "$SYSREPOCFG" --import --datastore=running --format=xml --module=ietf-netconf-server <<< ""
+
+ # Disable nacm
+ for datastore in startup running; do
+ "$SYSREPOCFG" --import="@CMAKE_CURRENT_SOURCE_DIR@/tests/disable-nacm.xml" --datastore="$datastore" --format=xml --module=ietf-netconf-acm
+ done
+
+ # Run netopeer. Use exec -a, so that each process has a recognizable name for `pkill`.
+ (exec -a "${SYSREPO_SHM_PREFIX}_netopeer2-server" "$NETOPEER2" -v2 "-U$NETOPEER_SOCKET")
+ sleep 5
+fi
diff --git a/tests/manage_nacm.sh.in b/tests/manage_nacm.sh.in
deleted file mode 100755
index db8d611..0000000
--- a/tests/manage_nacm.sh.in
+++ /dev/null
@@ -1,7 +0,0 @@
-if [ $1 != "enable" -a $1 != "disable" ]; then
- echo 'Argument must be "enable" or "disable."'
- exit 1
-fi
-for datastore in startup running; do
- @SYSREPOCFG_EXECUTABLE@ --import=@CMAKE_CURRENT_SOURCE_DIR@/tests/"$1-nacm.xml" --datastore="$datastore" --format=xml --module=ietf-netconf-acm
-done
diff --git a/tests/mock/sysrepo_subscription.cpp b/tests/mock/sysrepo_subscription.cpp
index 5527c41..03be075 100644
--- a/tests/mock/sysrepo_subscription.cpp
+++ b/tests/mock/sysrepo_subscription.cpp
@@ -23,7 +23,7 @@
int operator()(
sysrepo::S_Session sess,
- const char *module_name,
+ [[maybe_unused]] const char *module_name,
[[maybe_unused]] const char *xpath,
[[maybe_unused]] sr_event_t event,
[[maybe_unused]] uint32_t request_id)
diff --git a/tests/netopeer-test-config.xml b/tests/netopeer-test-config.xml
deleted file mode 100644
index e69de29..0000000
--- a/tests/netopeer-test-config.xml
+++ /dev/null
diff --git a/tests/netopeer_vars.hpp.in b/tests/netopeer_vars.hpp.in
deleted file mode 100644
index 6036e70..0000000
--- a/tests/netopeer_vars.hpp.in
+++ /dev/null
@@ -1 +0,0 @@
-#define NETOPEER_SOCKET_PATH "@NETOPEER_SOCKET_PATH@"
diff --git a/tests/python_netconfaccess.py b/tests/python_netconfaccess.py
index ae317ee..d686cd0 100644
--- a/tests/python_netconfaccess.py
+++ b/tests/python_netconfaccess.py
@@ -1,7 +1,8 @@
+import os
import sysrepo_subscription_py as sr_sub
import netconf_cli_py as nc
-c = nc.NetconfAccess(socketPath = "@NETOPEER_SOCKET_PATH@")
+c = nc.NetconfAccess(socketPath = os.environ['NETOPEER_SOCKET'])
data = c.getItems("/ietf-netconf-monitoring:netconf-state/datastores")
for (k, v) in data:
print(f"{k}: {type(v)} {v}", flush=True)
diff --git a/tests/start_daemons.sh.in b/tests/start_daemons.sh.in
deleted file mode 100755
index 5343441..0000000
--- a/tests/start_daemons.sh.in
+++ /dev/null
@@ -1,9 +0,0 @@
-set -eux -o pipefail
-shopt -s failglob
-export ASAN_OPTIONS=verify_asan_link_order=false
-export UBSAN_OPTIONS=halt_on_error=1
-
-@CMAKE_CURRENT_SOURCE_DIR@/tests/kill_daemons.sh || true
-
-@NETOPEER2_EXECUTABLE@ -v2 -U@NETOPEER_SOCKET_PATH@
-sleep 5
diff --git a/tests/sysrepoctl-manage-module.sh b/tests/sysrepoctl-manage-module.sh
deleted file mode 100755
index b618fec..0000000
--- a/tests/sysrepoctl-manage-module.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env bash
-
-set -eux -o pipefail
-shopt -s failglob
-
-SYSREPOCTL="${1}"
-shift
-if [[ ! -x "${SYSREPOCTL}" ]]; then
- echo "Cannot locate \$SYSREPOCTL"
- exit 1
-fi
-
-SYSREPOCFG="${1}"
-shift
-if [[ ! -x "${SYSREPOCFG}" ]]; then
- echo "Cannot locate \$SYSREPOCFG"
- exit 1
-fi
-
-MODE="${1}"
-shift
-
-if [[ ! -f "${1}" ]]; then
- echo "No YANG file specified"
- exit 1
-fi
-
-MODULE=$(basename --suffix .yang "${1}")
-YANG_DIR=$(dirname "${1}")
-
-if [[ "${MODE}" == "install" ]]; then
- ${SYSREPOCTL} -C
- ${SYSREPOCTL} --uninstall "${MODULE}" -a || true
- ${SYSREPOCTL} -C
- ${SYSREPOCTL} --search-dirs "${YANG_DIR}" --install "${1}" -a
- JSON_DATA="${YANG_DIR}/${MODULE}.json"
- XML_DATA="${YANG_DIR}/${MODULE}.startup.xml"
- if [[ -f "${JSON_DATA}" ]] ;then
- ${SYSREPOCFG} -d startup -f json "${MODULE}" -i "${JSON_DATA}" -a
- elif [[ -f "${XML_DATA}" ]]; then
- ${SYSREPOCFG} -d startup -f xml "${MODULE}" -i "${XML_DATA}" -a
- fi
-elif [[ "${MODE}" == "uninstall" ]]; then
- ${SYSREPOCTL} --uninstall "${MODULE}" -a
-else
- echo "Mode of operation not specified"
- exit 1
-fi