Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable testing with out-of-tree builds #692

Merged
merged 10 commits into from
Dec 27, 2023
Merged
4 changes: 2 additions & 2 deletions .github/workflows/test_and_validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,8 @@ jobs:
- name: run_bmi_python_tests
run: |
. .venv/bin/activate
cd ./cmake_build/test/
./test_bmi_python
cd ./cmake_build/
./test/test_bmi_python
cd ../../
timeout-minutes: 15

Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ if(NGEN_WITH_PYTHON)
add_compile_definitions(ACTIVATE_PYTHON=true)
find_package(Python 3.6.8 REQUIRED COMPONENTS Interpreter Development NumPy)
set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) # Case-sensitive difference
add_subdirectory(extern/pybind11)
add_subdirectory(extern/pybind11 pybind11)
endif()

# -----------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion include/bmi/AbstractCLibBmiAdapter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ namespace models {
this->init_exception_msg =
"Can't init " + this->model_name + "; library file path is empty";
throw std::runtime_error(this->init_exception_msg);
}
}
if(bmi_lib_file.substr(idx) == ".so"){
alt_bmi_lib_file = bmi_lib_file.substr(0,idx) + ".dylib";
} else if(bmi_lib_file.substr(idx) == ".dylib"){
Expand Down
4 changes: 4 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ if(NOT NGEN_ROOT_DIR STREQUAL PROJECT_BINARY_DIR)

# Create a symlink between the test data directory in the source tree and the build tree
file(CREATE_LINK "${CMAKE_CURRENT_LIST_DIR}/data" "${PROJECT_BINARY_DIR}/test/data" SYMBOLIC)

# Create a symlink between the extern directory in the source tree and the build tree
file(CREATE_LINK "${NGEN_ROOT_DIR}/extern" "${PROJECT_BINARY_DIR}/extern" SYMBOLIC)
file(CREATE_LINK "${NGEN_ROOT_DIR}/extern" "${PROJECT_BINARY_DIR}/test/extern" SYMBOLIC)
endif()

# =============================================================================
Expand Down
46 changes: 5 additions & 41 deletions test/bmi/Bmi_Py_Adapter_Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,6 @@ class Bmi_Py_Adapter_Test : public ::testing::Test {
*/
static std::string py_dir_search(const std::vector<std::string> &dir_options);

/**
* Find the repo root directory, starting from the current directory and working upward.
*
* @return The absolute path of the repo root, as a string.
*/
static std::string py_find_repo_root();

/**
* Find the virtual environment site packages directory, starting from an assumed valid venv directory.
*
Expand Down Expand Up @@ -128,13 +121,10 @@ std::shared_ptr<InterpreterUtil> Bmi_Py_Adapter_Test::interperter = InterpreterU
py::object Bmi_Py_Adapter_Test::Path = InterpreterUtil::getPyModule(std::vector<std::string> {"pathlib", "Path"});

void Bmi_Py_Adapter_Test::SetUp() {

std::string repo_root = py_find_repo_root();

example_scenario template_ex_struct;
// These should be safe for all examples
template_ex_struct.module_name = "test_bmi_py.bmi_model";
template_ex_struct.module_directory = repo_root + "/extern/";
template_ex_struct.module_directory = "./extern/";

// Now generate the examples vector based on the above template example
size_t num_example_scenarios = 1;
Expand All @@ -143,11 +133,11 @@ void Bmi_Py_Adapter_Test::SetUp() {
examples[i] = template_ex_struct;
}

examples[0].forcing_file = repo_root + "/data/forcing/cat-27_2015-12-01 00_00_00_2015-12-30 23_00_00.csv";
examples[0].forcing_file = "./data/forcing/cat-27_2015-12-01 00_00_00_2015-12-30 23_00_00.csv";

// We can handle setting the right init config and initializing the adapter in a loop
for (int i = 0; i < examples.size(); ++i) {
examples[i].bmi_init_config = repo_root + "/test/data/bmi/test_bmi_python/test_bmi_python_config_"
examples[i].bmi_init_config = "./test/data/bmi/test_bmi_python/test_bmi_python_config_"
+ std::to_string(i) + ".yml";

examples[i].adapter = std::make_shared<Bmi_Py_Adapter>(examples[i].module_name, examples[i].bmi_init_config,
Expand All @@ -160,15 +150,8 @@ void Bmi_Py_Adapter_Test::TearDown() {
}

void Bmi_Py_Adapter_Test::SetUpTestSuite() {
std::string repo_root = py_find_repo_root();
std::string module_directory = repo_root + "/extern/";

// Add the package dir from a local virtual environment directory also, if there is one
std::string venv_dir = py_dir_search({repo_root + "/.venv", repo_root + "/venv"});
if (!venv_dir.empty()) {
InterpreterUtil::addToPyPath(py_find_venv_site_packages_dir(venv_dir));
}
// Also add the extern dir with our test lib to Python system path
// Add the extern dir with our test lib to Python system path
std::string module_directory = "./extern/";
InterpreterUtil::addToPyPath(module_directory);
}

Expand Down Expand Up @@ -232,25 +215,6 @@ std::string Bmi_Py_Adapter_Test::py_dir_search(const std::vector<std::string> &d
return "";
}

/**
* Find the repo root directory, starting from the current directory and working upward.
*
* @return The absolute path of the repo root, as a string.
*/
std::string Bmi_Py_Adapter_Test::py_find_repo_root() {
py::object dir = Path(".").attr("resolve")();
while (!dir.equal(dir.attr("parent"))) {
// If there is a child .git dir and a child .github dir, then dir is the root
py::bool_ is_git_dir = py::bool_(dir.attr("joinpath")(".git").attr("is_dir")());
py::bool_ is_github_dir = py::bool_(dir.attr("joinpath")(".github").attr("is_dir")());
if (is_git_dir && is_github_dir) {
return py::str(dir);
}
dir = dir.attr("parent");
}
throw std::runtime_error("Can't find repo root starting at " + std::string(py::str(Path(".").attr("resolve")())));
}

/**
* Find the virtual environment site packages directory, starting from an assumed valid venv directory.
*
Expand Down
29 changes: 1 addition & 28 deletions test/realizations/catchments/Bmi_Multi_Formulation_Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,32 +403,6 @@ class Bmi_Multi_Formulation_Test : public ::testing::Test {
"formulations").begin()->second.get_child("params");
}

/**
* Find the repo root directory using Python, starting from the current directory and working upward.
*
* This will throw a runtime error if Python functionality is not active.
*
* @return The absolute path of the repo root, as a string.
*/
static std::string py_find_repo_root() {
#ifdef ACTIVATE_PYTHON
py::object Path = InterpreterUtil::getPyModule(std::vector<std::string> {"pathlib", "Path"});
py::object dir = Path(".").attr("resolve")();
while (!dir.equal(dir.attr("parent"))) {
// If there is a child .git dir and a child .github dir, then dir is the root
py::bool_ is_git_dir = py::bool_(dir.attr("joinpath")(".git").attr("is_dir")());
py::bool_ is_github_dir = py::bool_(dir.attr("joinpath")(".github").attr("is_dir")());
if (is_git_dir && is_github_dir) {
return py::str(dir);
}
dir = dir.attr("parent");
}
throw std::runtime_error("Can't find repo root starting at " + std::string(py::str(Path(".").attr("resolve")())));
#else // (i.e., if not ACTIVATE_PYTHON)
throw std::runtime_error("Can't use Python-based test helper function 'py_find_repo_root'; Python not active!");
#endif // ACTIVATE_PYTHON
}

inline void initializeTestExample(const int ex_index, const std::string &cat_id,
const std::vector<std::string> &nested_types, const std::vector<std::string> &output_variables) {
catchment_ids[ex_index] = cat_id;
Expand Down Expand Up @@ -467,8 +441,7 @@ std::shared_ptr<InterpreterUtil> Bmi_Multi_Formulation_Test::interperter = Inter

void Bmi_Multi_Formulation_Test::SetUpTestSuite() {
#ifdef ACTIVATE_PYTHON
std::string repo_root = py_find_repo_root();
std::string module_directory = repo_root + "/extern/";
std::string module_directory = "./extern/";

// Add the extern dir with our test lib to Python system path
InterpreterUtil::addToPyPath(module_directory);
Expand Down
47 changes: 5 additions & 42 deletions test/realizations/catchments/Bmi_Py_Formulation_Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,6 @@ class Bmi_Py_Formulation_Test : public ::testing::Test {
return diff.ticks() / boost::posix_time::time_duration::rep_type::ticks_per_second;
}

/**
* Find the repo root directory, starting from the current directory and working upward.
*
* @return The absolute path of the repo root, as a string.
*/
static std::string py_find_repo_root();

/**
* Search for and return the first existing example of a collection of directories, using Python to perform search.
*
Expand Down Expand Up @@ -182,13 +175,12 @@ std::shared_ptr<InterpreterUtil> Bmi_Py_Formulation_Test::interperter = Interpre
void Bmi_Py_Formulation_Test::SetUp() {
Path = InterpreterUtil::getPyModule(std::vector<std::string> {"pathlib", "Path"});

std::string repo_root = py_find_repo_root();
std::string forcing_data_dir = repo_root + "/data/forcing/";
std::string forcing_data_dir = "./data/forcing/";

py_formulation_example_scenario template_ex_struct;
// These should be safe for all examples
template_ex_struct.module_name = "test_bmi_py.bmi_model";
template_ex_struct.module_directory = repo_root + "/extern/";
template_ex_struct.module_directory = "./extern/";
template_ex_struct.main_output_variable = "OUTPUT_VAR_1";
template_ex_struct.uses_forcing_file = false;

Expand All @@ -205,7 +197,7 @@ void Bmi_Py_Formulation_Test::SetUp() {
// We can handle setting the rest up in a loop
std::string forcing_file;
for (size_t i = 0; i < examples.size(); ++i) {
examples[i].bmi_init_config = repo_root + "/test/data/bmi/test_bmi_python/test_bmi_python_config_"
examples[i].bmi_init_config = "./test/data/bmi/test_bmi_python/test_bmi_python_config_"
+ std::to_string(i) + ".yml";
forcing_file = forcing_data_dir + examples[i].catchment_id + "_2015-12-01 00_00_00_2015-12-30 23_00_00.csv";
examples[i].forcing_params = std::make_shared<forcing_params>(forcing_file, "legacy", "2015-12-01 00:00:00",
Expand All @@ -226,18 +218,9 @@ void Bmi_Py_Formulation_Test::SetUp() {
}

void Bmi_Py_Formulation_Test::SetUpTestSuite() {
std::string repo_root = py_find_repo_root();
std::string module_directory = repo_root + "/extern/";

// Add the package dir from a local virtual environment directory also, if there is one
std::string venv_dir = py_dir_search({repo_root + "/.venv", repo_root + "/venv"});
if (!venv_dir.empty()) {
InterpreterUtil::addToPyPath(py_find_venv_site_packages_dir(venv_dir));
}
// Also add the extern dir with our test lib to Python system path
// Add the extern dir with our test lib to Python system path
std::string module_directory = "./extern/";
InterpreterUtil::addToPyPath(module_directory);


}

void Bmi_Py_Formulation_Test::TearDown() {
Expand Down Expand Up @@ -351,26 +334,6 @@ std::string Bmi_Py_Formulation_Test::py_dir_search(const std::vector<std::string
return "";
}

/**
* Find the repo root directory, starting from the current directory and working upward.
*
* @return The absolute path of the repo root, as a string.
*/
std::string Bmi_Py_Formulation_Test::py_find_repo_root() {
py::object Path = InterpreterUtil::getPyModule(std::vector<std::string> {"pathlib", "Path"});
py::object dir = Path(".").attr("resolve")();
while (!dir.equal(dir.attr("parent"))) {
// If there is a child .git dir and a child .github dir, then dir is the root
py::bool_ is_git_dir = py::bool_(dir.attr("joinpath")(".git").attr("is_dir")());
py::bool_ is_github_dir = py::bool_(dir.attr("joinpath")(".github").attr("is_dir")());
if (is_git_dir && is_github_dir) {
return py::str(dir);
}
dir = dir.attr("parent");
}
throw std::runtime_error("Can't find repo root starting at " + std::string(py::str(Path(".").attr("resolve")())));
}

/**
* Find the virtual environment site packages directory, starting from an assumed valid venv directory.
*
Expand Down