From 194a5daa780e9b0d9520cb1e54e4c8caf6cf85a0 Mon Sep 17 00:00:00 2001 From: msteinsto <66729213+msteinsto@users.noreply.github.com> Date: Tue, 29 Mar 2022 14:10:18 +0200 Subject: [PATCH] Non URI file scheme equal type name support (#688) * Removed file scheme check * Allow proxyfmu URI scheme * Removed URI authority check * Check model relative path for OspModelDescription with fmuproxy * Fixed fmuproxy model path * File path fix * Added logging for debugging * Fix prototype * Absolute path query file support * Added some tests * Final testing implementation with logging * Temporary removal of Linux file query uri tests * Edited invalid tests * Reintroduced non Windows tests * Non Windows tests corrections * UNIX filesystem compatible function rewrite * Removed scheme assertion * Changed input parameter from baseUri to baseParentUri * Moved file_query_uri_to_path function from uri to osp_config_parser * Removed unused proxyfmu client dependency for tests Co-authored-by: msteinsto --- include/cosim/uri.hpp | 4 +- src/cosim/osp_config_parser.cpp | 31 ++++++---- tests/CMakeLists.txt | 3 + .../data/msmi/OspSystemStructure_proxyfmu.xml | 45 ++++++++++++++ tests/proxyfmu_osp_config_parser_test.cpp | 58 +++++++++++++++++++ 5 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 tests/data/msmi/OspSystemStructure_proxyfmu.xml create mode 100644 tests/proxyfmu_osp_config_parser_test.cpp diff --git a/include/cosim/uri.hpp b/include/cosim/uri.hpp index 6436cd797..f8bf727de 100644 --- a/include/cosim/uri.hpp +++ b/include/cosim/uri.hpp @@ -266,7 +266,7 @@ uri path_to_file_uri(const cosim::filesystem::path& path); * * \param [in] fileUri * An URI where the scheme component is equal to `file` and the `authority` - * component is either empty or equel to `localhost` (but not undefined). + * component is either empty or equal to `localhost` (but not undefined). * * \returns * The path that corresponds to `fileUri`. @@ -275,4 +275,4 @@ cosim::filesystem::path file_uri_to_path(const uri& fileUri); } // namespace cosim -#endif // header guard +#endif // header guard \ No newline at end of file diff --git a/src/cosim/osp_config_parser.cpp b/src/cosim/osp_config_parser.cpp index 87cbf7777..ebaf31784 100644 --- a/src/cosim/osp_config_parser.cpp +++ b/src/cosim/osp_config_parser.cpp @@ -890,6 +890,20 @@ void connect_vector_sum_functions( } } +cosim::filesystem::path file_query_uri_to_path( + const cosim::uri& baseParentUri, + const cosim::uri& queryUri) +{ + const auto query = queryUri.query(); + if (query && query->find("file=") < query->size()) { + if (query->find("file=file:///") < query->size()) { + return file_uri_to_path(std::string(query->substr(5))); + } + return file_uri_to_path(std::string(baseParentUri.view()) + "/" + std::string(query->substr(5))); + } + return file_uri_to_path(baseParentUri); +} + } // namespace osp_config load_osp_config( @@ -938,19 +952,12 @@ osp_config load_osp_config( const auto modelUri = resolve_reference(baseURI, simulator.source); cosim::filesystem::path msmiFilePath; - if (modelUri.scheme() == "file") { - msmiFilePath = file_uri_to_path(modelUri).remove_filename() / msmiFileName; - if (cosim::filesystem::exists(msmiFilePath)) { - emds.emplace(simulator.name, msmiFilePath); - } else { - msmiFilePath = configFile.parent_path() / msmiFileName; - if (cosim::filesystem::exists(msmiFilePath)) { - emds.emplace(simulator.name, msmiFilePath); - } - } + msmiFilePath = (modelUri.scheme() == "file") + ? file_uri_to_path(modelUri).remove_filename() / msmiFileName + : file_query_uri_to_path(cosim::path_to_file_uri(cosim::file_uri_to_path(baseURI).parent_path()), modelUri).remove_filename() / msmiFileName; + if (cosim::filesystem::exists(msmiFilePath)) { + emds.emplace(simulator.name, msmiFilePath); } else { - // Makes it possible to keep OspModelDescription at configuration path - // even when there are FMUs with other URI than file (fmu-proxy). msmiFilePath = configFile.parent_path() / msmiFileName; if (cosim::filesystem::exists(msmiFilePath)) { emds.emplace(simulator.name, msmiFilePath); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e91361715..e4250a133 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,6 +37,9 @@ if(LIBCOSIM_WITH_PROXYFMU) "proxyfmu_integration_unittest" "proxyfmu_library_unittest" ) + list(APPEND tests + "proxyfmu_osp_config_parser_test" + ) endif() include("AddTestExecutable") diff --git a/tests/data/msmi/OspSystemStructure_proxyfmu.xml b/tests/data/msmi/OspSystemStructure_proxyfmu.xml new file mode 100644 index 000000000..c6d5c6849 --- /dev/null +++ b/tests/data/msmi/OspSystemStructure_proxyfmu.xml @@ -0,0 +1,45 @@ + + + 0.0 + 1e-4 + fixedStep + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/proxyfmu_osp_config_parser_test.cpp b/tests/proxyfmu_osp_config_parser_test.cpp new file mode 100644 index 000000000..5fc898f6d --- /dev/null +++ b/tests/proxyfmu_osp_config_parser_test.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define REQUIRE(test) \ + if (!(test)) throw std::runtime_error("Requirement not satisfied: " #test) + +void test(const cosim::filesystem::path& configPath, size_t expectedNumConnections) +{ + auto resolver = cosim::default_model_uri_resolver(); + const auto config = cosim::load_osp_config(configPath, *resolver); + auto execution = cosim::execution( + config.start_time, + std::make_shared(config.step_size)); + + const auto entityMaps = cosim::inject_system_structure( + execution, config.system_structure, config.initial_values); + REQUIRE(entityMaps.simulators.size() == 4); + REQUIRE(boost::size(config.system_structure.connections()) == expectedNumConnections); + + auto obs = std::make_shared(); + execution.add_observer(obs); + + auto result = execution.simulate_until(cosim::to_time_point(1e-3)); + REQUIRE(result.get()); + + const auto simIndex = entityMaps.simulators.at("CraneController"); + const auto varReference = + config.system_structure.get_variable_description({"CraneController", "cl1_min"}).reference; + double realValue = -1.0; + obs->get_real(simIndex, gsl::make_span(&varReference, 1), gsl::make_span(&realValue, 1)); + + double magicNumberFromConf = 2.2; + REQUIRE(std::fabs(realValue - magicNumberFromConf) < 1e-9); +} + +int main() +{ + try { + cosim::log::setup_simple_console_logging(); + cosim::log::set_global_output_level(cosim::log::info); + + const auto testDataDir = std::getenv("TEST_DATA_DIR"); + REQUIRE(testDataDir); + test(cosim::filesystem::path(testDataDir) / "msmi" / "OspSystemStructure_proxyfmu.xml", 9); + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what(); + return 1; + } + return 0; +} \ No newline at end of file