Files
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

389 lines
19 KiB
C++

// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <catch2/catch_all.hpp>
#include <framework/runtime.hpp>
#include <tests/helpers.hpp>
#include <utils/config.hpp>
namespace fs = std::filesystem;
SCENARIO("Check ManagerSettings Constructor", "[!throws]") {
auto bin_dir = Everest::tests::get_bin_dir().string() + "/";
GIVEN("An invalid prefix, but a valid config file") {
THEN("It should throw BootException") {
CHECK_THROWS_AS(
Everest::ManagerSettings(bin_dir + "non-valid-prefix/", bin_dir + "valid_config/config.yaml"),
Everest::BootException);
}
}
GIVEN("A valid prefix, but a non existing config file") {
THEN("It should throw BootException") {
CHECK_THROWS_AS(Everest::ManagerSettings(bin_dir + "valid_config/", bin_dir + "non-existing-config.yaml"),
Everest::BootException);
}
}
GIVEN("A valid prefix and a valid config file") {
THEN("It should not throw") {
CHECK_NOTHROW(Everest::ManagerSettings(bin_dir + "valid_config/", bin_dir + "valid_config/config.yaml"));
}
}
GIVEN("A valid prefix and a valid config file with a custom prefix") {
THEN("It should not throw") {
auto ms = Everest::ManagerSettings(bin_dir + "valid_config_custom_prefix/usr",
bin_dir + "valid_config_custom_prefix/usr/config.yaml");
CHECK(ms.runtime_settings.etc_dir == bin_dir + "valid_config_custom_prefix/etc/everest");
}
}
GIVEN("A broken yaml file") {
// FIXME (aw): this also throws, if the folder doesn't even exists or some other things fail
THEN("It should throw") {
CHECK_THROWS(Everest::ManagerSettings(bin_dir + "broken_yaml/", bin_dir + "broken_yaml/config.yaml"));
}
}
GIVEN("A empty yaml file") {
THEN("It shouldn't throw") {
CHECK_NOTHROW(Everest::ManagerSettings(bin_dir + "empty_yaml/", bin_dir + "empty_yaml/config.yaml"));
}
}
GIVEN("A empty yaml object file") {
THEN("It shouldn't throw") {
CHECK_NOTHROW(
Everest::ManagerSettings(bin_dir + "empty_yaml_object/", bin_dir + "empty_yaml_object/config.yaml"));
}
}
GIVEN("A null yaml file") {
THEN("It shouldn't throw") {
CHECK_NOTHROW(Everest::ManagerSettings(bin_dir + "null_yaml/", bin_dir + "null_yaml/config.yaml"));
}
}
GIVEN("A string yaml file") {
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerSettings(bin_dir + "string_yaml/", bin_dir + "string_yaml/config.yaml"),
Everest::BootException);
}
}
GIVEN("A non-exsiting database file with ConfigurationBootMode::DatabaseInit") {
THEN("It should not throw and create the file") {
CHECK_NOTHROW(Everest::ManagerSettings(bin_dir + "valid_config/", bin_dir + "valid_config/config.yaml",
"valid_config/non_existing.db"));
}
}
}
SCENARIO("Check ManagerConfig Constructor", "[!throws]") {
auto bin_dir = Everest::tests::get_bin_dir().string() + "/";
GIVEN("A config without modules") {
auto ms = Everest::ManagerSettings(bin_dir + "empty_config/", bin_dir + "empty_config/config.yaml");
auto config = Everest::ManagerConfig(ms);
THEN("It should not contain the module some_module") {
CHECK(!config.contains("some_module"));
}
}
GIVEN("A config file referencing a non existent module") {
auto ms = Everest::ManagerSettings(bin_dir + "missing_module/", bin_dir + "missing_module/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file using a module with broken manifest (missing meta data)") {
auto ms = Everest::ManagerSettings(bin_dir + "broken_manifest_1/", bin_dir + "broken_manifest_1/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file using a module with broken manifest (empty file)") {
auto ms = Everest::ManagerSettings(bin_dir + "broken_manifest_2/", bin_dir + "broken_manifest_2/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
// FIXME: an empty manifest breaks the test?
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file using a module with broken manifest (broken module config)") {
auto ms = Everest::ManagerSettings(bin_dir + "broken_manifest_3/", bin_dir + "broken_manifest_3/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file using a module with broken manifest (broken implementation config)") {
auto ms = Everest::ManagerSettings(bin_dir + "broken_manifest_4/", bin_dir + "broken_manifest_4/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file with an unknown implementation config") {
auto ms = Everest::ManagerSettings(bin_dir + "unknown_impls/", bin_dir + "unknown_impls/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file with an missing config entry") {
auto ms =
Everest::ManagerSettings(bin_dir + "missing_config_entry/", bin_dir + "missing_config_entry/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file with an missing implementation config entry") {
auto ms = Everest::ManagerSettings(bin_dir + "missing_impl_config_entry/",
bin_dir + "missing_impl_config_entry/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file with an invalid type of an implementation config entry") {
auto ms = Everest::ManagerSettings(bin_dir + "invalid_config_entry_type/",
bin_dir + "invalid_config_entry_type/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A config file using a module with an invalid interface (missing "
"interface)") {
auto ms = Everest::ManagerSettings(bin_dir + "missing_interface/", bin_dir + "missing_interface/config.yaml");
THEN("It should throw Everest::EverestConfigError") {
CHECK_THROWS_AS(Everest::ManagerConfig(ms), Everest::EverestConfigError);
}
}
GIVEN("A valid config") {
auto ms = Everest::ManagerSettings(bin_dir + "valid_config/", bin_dir + "valid_config/config.yaml");
THEN("It should not throw at all") {
CHECK_NOTHROW(Everest::ManagerConfig(ms));
}
}
GIVEN("A valid config with a valid module") {
auto ms =
Everest::ManagerSettings(bin_dir + "valid_module_config/", bin_dir + "valid_module_config/config.yaml");
THEN("It should not throw at all") {
CHECK_NOTHROW(Everest::ManagerConfig(ms));
}
}
GIVEN("A valid config with a valid module and a user-config applied") {
auto ms = Everest::ManagerSettings(bin_dir + "valid_module_config_userconfig/",
bin_dir + "valid_module_config_userconfig/config.yaml");
THEN("It should not throw at all") {
CHECK_NOTHROW([&]() {
auto mc = Everest::ManagerConfig(ms);
auto module_configs = mc.get_module_configurations();
bool found = false;
const auto config_params = module_configs.at("valid_module").configuration_parameters;
for (const auto& param : config_params.at("!module")) {
if (param.name == "valid_config_entry") {
found = true;
CHECK(std::get<std::string>(param.value) == "hi");
}
}
if (!found) {
FAIL("Expected configuration parameter 'valid_config_entry' not found.");
}
}());
}
}
GIVEN("A valid config with a valid module and enabled schema validation") {
auto ms = Everest::ManagerSettings(bin_dir + "valid_module_config_validate/",
bin_dir + "valid_module_config_validate/config.yaml");
THEN("It should not throw at all") {
CHECK_NOTHROW([&]() {
auto mc = Everest::ManagerConfig(ms);
auto interfaces = mc.get_interfaces();
CHECK(interfaces.size() == 1);
CHECK(interfaces.contains("TESTValidManifestCmdVar"));
CHECK(interfaces.at("TESTValidManifestCmdVar").at("main") == "test_interface_cmd_var");
auto types = mc.get_types();
CHECK(types.size() == 1);
CHECK(types.contains("/test_type"));
}());
}
}
GIVEN("A valid config in legacy json format with a valid module") {
auto ms = Everest::ManagerSettings(bin_dir + "valid_module_config_json/",
bin_dir + "valid_module_config_json/config.json");
THEN("It should not throw at all") {
CHECK_NOTHROW(Everest::ManagerConfig(ms));
}
}
GIVEN("A config file that does not exist") {
THEN("It should throw Everest::BootException") {
CHECK_THROWS_AS(Everest::ManagerSettings(bin_dir + "valid_module_config_json/",
bin_dir + "valid_module_config_json/config.yaml"),
Everest::BootException);
}
}
GIVEN("A valid config in legacy json format with multiple connected valid modules") {
auto ms =
Everest::ManagerSettings(bin_dir + "valid_complete_config/", bin_dir + "valid_complete_config/config.json");
THEN("It should not throw at all") {
CHECK_NOTHROW(Everest::ManagerConfig(ms));
}
}
GIVEN("ManagerSettings are instantiated two times - first with fallback to init from config file, second with "
"database") {
auto db_path = bin_dir + "valid_config/everest.db";
// Clean up before test
if (fs::exists(db_path)) {
fs::remove(db_path);
}
auto ms = Everest::ManagerSettings(bin_dir + "valid_config/", bin_dir + "valid_config/config.yaml", db_path);
CHECK(ms.storage->contains_valid_config() == false);
THEN("In the first intstantiation the database is not initialized") {
CHECK_NOTHROW(Everest::ManagerConfig(ms));
THEN("In the second instantiation the database is initialized and valid") {
ms = Everest::ManagerSettings(bin_dir + "valid_config/", bin_dir + "valid_config/config.yaml", db_path);
CHECK(ms.storage->contains_valid_config() == true);
CHECK_NOTHROW(Everest::ManagerConfig(ms));
}
THEN("It should be possible to construct the ManagerSettings with a database path") {
CHECK_NOTHROW(Everest::ManagerSettings(bin_dir + "valid_config/", db_path, Everest::DatabaseTag{}));
}
}
}
}
SCENARIO("Check everest config parsing", "[!throws]") {
auto bin_dir = Everest::tests::get_bin_dir().string() + "/";
auto valid_complete_config_json = bin_dir + "valid_complete_config/config.json";
GIVEN("A complete and valid config") {
auto config = Everest::load_yaml(valid_complete_config_json);
THEN("It should not throw") {
CHECK_NOTHROW(everest::config::parse_module_configs(config.value("active_modules", json::object())));
}
}
GIVEN("A valid config that misses module connections") {
auto config = Everest::load_yaml(valid_complete_config_json);
config["active_modules"]["valid_module_requires"].erase("connections");
THEN("It should not throw") {
CHECK_NOTHROW(everest::config::parse_module_configs(config.value("active_modules", json::object())));
}
}
GIVEN("A valid config that misses a mapping") {
auto config = Everest::load_yaml(valid_complete_config_json);
config["active_modules"]["valid_module"].erase("mapping");
THEN("It should not throw") {
CHECK_NOTHROW(everest::config::parse_module_configs(config.value("active_modules", json::object())));
}
}
GIVEN("A config where a module is missing the 'module' field") {
auto config = Everest::load_yaml(valid_complete_config_json);
config["active_modules"]["valid_module"].erase("module");
THEN("It should throw ConfigParseException for missing 'module'") {
CHECK_THROWS_AS(everest::config::parse_module_configs(config.value("active_modules", json::object())),
ConfigParseException);
}
}
GIVEN("A config with only 'active_modules' and no 'settings'") {
json config;
config["active_modules"] = {{"valid_module", {{"module", "TESTValidManifest"}}}};
THEN("It should not throw and parse default settings") {
CHECK_NOTHROW(everest::config::parse_module_configs(config.value("active_modules", json::object())));
}
}
GIVEN("A config with empty 'active_modules'") {
json config;
config["active_modules"] = json::object(); // empty object
THEN("It should not throw and result in no modules") {
auto result = everest::config::parse_module_configs(config.value("active_modules", json::object()));
CHECK(result.empty());
}
}
GIVEN("A config with unsupported JSON type in configuration parameter") {
json config;
config["active_modules"] = {
{"test_module", {{"module", "test"}, {"config_module", {{"param1", json::array({1, 2, 3})}}}}}};
THEN("It should throw due to unsupported config parameter type") {
CHECK_THROWS(everest::config::parse_module_configs(config.value("active_modules", json::object())));
}
}
}
json complete_serialized_mod_config(json& serialized_mod_config, Everest::ManagerConfig& mc) {
serialized_mod_config["interface_definitions"] = mc.get_interface_definitions();
serialized_mod_config["types"] = mc.get_types();
serialized_mod_config["module_provides"] = mc.get_interfaces();
serialized_mod_config["settings"] = mc.get_settings();
serialized_mod_config["schemas"] = mc.get_schemas();
serialized_mod_config["module_names"] = mc.get_module_names();
serialized_mod_config["manifests"] = mc.get_manifests();
serialized_mod_config["error_map"] = mc.get_error_types();
return serialized_mod_config;
}
SCENARIO("Check config constructor and functions", "[!throws]") {
auto bin_dir = Everest::tests::get_bin_dir().string() + "/";
auto ms = Everest::ManagerSettings(bin_dir + "two_module_test/", bin_dir + "two_module_test/config.yaml");
GIVEN("A config with two connected modules") {
THEN("It should not throw") {
CHECK_NOTHROW([&]() {
auto mc = Everest::ManagerConfig(ms);
auto serialized_mod_config =
Everest::get_serialized_module_config("module_a", mc.get_module_configurations());
complete_serialized_mod_config(serialized_mod_config, mc);
Everest::MQTTSettings mqtt_settings;
const auto config = Everest::Config(mqtt_settings, serialized_mod_config);
config.get_requirement_initialization("module_a");
}());
}
}
}
SCENARIO("Config constructor throws on missing required fields in serialized config", "[Config][throws]") {
GIVEN("A serialized config missing required fields") {
Everest::MQTTSettings mqtt_settings;
Everest::json serialized_config = Everest::json::object();
serialized_config["module_config"] = Everest::json::object();
serialized_config["module_config"]["module_a"] = Everest::json::object();
THEN("It should throw an exception") {
CHECK_THROWS_AS(Everest::Config(mqtt_settings, serialized_config), json::exception);
}
}
}
SCENARIO("Config returns correct module info", "[Config]") {
auto bin_dir = Everest::tests::get_bin_dir().string() + "/";
auto ms = Everest::ManagerSettings(bin_dir + "two_module_test/", bin_dir + "two_module_test/config.yaml");
auto mc = Everest::ManagerConfig(ms);
auto serialized = Everest::get_serialized_module_config("module_a", mc.get_module_configurations());
complete_serialized_mod_config(serialized, mc);
Everest::MQTTSettings mqtt_settings;
GIVEN("A valid serialized config") {
Everest::Config config(mqtt_settings, serialized);
WHEN("Calling get_module_info") {
auto info = config.get_module_info("module_a");
THEN("It should return the correct name and license") {
CHECK(info.id == "module_a");
CHECK(info.name == "TESTModuleA");
CHECK(info.license == "https://opensource.org/licenses/Apache-2.0");
CHECK(info.authors.at(0) == "author@example.com");
}
}
}
}
SCENARIO("Config returns parsed module configs", "[Config]") {
auto bin_dir = Everest::tests::get_bin_dir().string() + "/";
auto ms = Everest::ManagerSettings(bin_dir + "two_module_test/", bin_dir + "two_module_test/config.yaml");
auto mc = Everest::ManagerConfig(ms);
auto serialized = Everest::get_serialized_module_config("module_a", mc.get_module_configurations());
complete_serialized_mod_config(serialized, mc);
Everest::MQTTSettings mqtt_settings;
Everest::Config config(mqtt_settings, serialized);
GIVEN("A valid config for module_a") {
auto configs = config.get_module_configs("module_a");
THEN("It should contain the correct config values") {
CHECK(configs.find("main") != configs.end());
CHECK(configs.find("!module") != configs.end());
CHECK(std::get<std::string>(configs["!module"]["valid_module_config_entry"]) == "test");
CHECK(std::get<int>(configs["main"]["valid_impl_config_entry"]) == 42);
}
}
}