Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/docker/ddsrouter/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ RUN pip3 install \
colcon-mixin \
lxml \
vcstool \
GitPython \
pyyaml \
jsonschema
GitPython

WORKDIR /ddsrouter

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ log/
docs/rst/_static/css/eprosima-furo.css
docs/rst/_static/eprosima-logo-white.png
docs/rst/_templates/sidebar/
docs/resources/examples/


### Python ###
Expand Down
28 changes: 28 additions & 0 deletions ddsrouter_yaml/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,34 @@ compile_test_library(
"${PROJECT_SOURCE_DIR}/test" # Test directory
)

###############################################################################
# Resources
###############################################################################
file(READ "${PROJECT_SOURCE_DIR}/../resources/configurations/ddsrouter_config_schema.json"
DDSROUTER_CONFIG_SCHEMA_CONTENT)

# Split into <=16000-char chunks to work around MSVC C2026 string literal size limit.
# Adjacent string literals are concatenated by the compiler.
string(LENGTH "${DDSROUTER_CONFIG_SCHEMA_CONTENT}" _schema_len)
set(_chunk_size 16000)
set(DDSROUTER_CONFIG_SCHEMA_CHUNKS "")
set(_offset 0)
while(_offset LESS _schema_len)
string(SUBSTRING "${DDSROUTER_CONFIG_SCHEMA_CONTENT}" ${_offset} ${_chunk_size} _chunk)
string(APPEND DDSROUTER_CONFIG_SCHEMA_CHUNKS " R\"json(${_chunk})json\"\n")
math(EXPR _offset "${_offset} + ${_chunk_size}")
endwhile()

configure_file(
"${PROJECT_SOURCE_DIR}/include/ddsrouter_yaml/DdsRouterConfigSchema.hpp.in"
"${CMAKE_CURRENT_BINARY_DIR}/include/ddsrouter_yaml/DdsRouterConfigSchema.hpp"
@ONLY
)

target_include_directories(${MODULE_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
)

###############################################################################
# Packaging
###############################################################################
Expand Down
18 changes: 18 additions & 0 deletions ddsrouter_yaml/include/ddsrouter_yaml/DdsRouterConfigSchema.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2026 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

static const char* DDSROUTER_CONFIG_SCHEMA =
@DDSROUTER_CONFIG_SCHEMA_CHUNKS@;
38 changes: 26 additions & 12 deletions ddsrouter_yaml/src/cpp/YamlReaderConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
#include <ddspipe_yaml/Yaml.hpp>
#include <ddspipe_yaml/YamlManager.hpp>
#include <ddspipe_yaml/YamlReader.hpp>
#include <ddspipe_yaml/YamlValidator.hpp>

#include <ddsrouter_core/configuration/DdsRouterConfiguration.hpp>

#include <ddsrouter_yaml/YamlReaderConfiguration.hpp>
#include <ddsrouter_yaml/DdsRouterConfigSchema.hpp>

namespace eprosima {
namespace ddsrouter {
Expand All @@ -30,6 +32,15 @@ YamlReaderConfiguration::load_ddsrouter_configuration(
const Yaml& yml,
const CommandlineArgsRouter* args /*= nullptr*/)
{
// Ensure the Yaml is valid
ddspipe::yaml::YamlValidator validator = ddspipe::yaml::YamlValidator(
ddspipe::yaml::YamlValidator::from_string(DDSROUTER_CONFIG_SCHEMA));
if (!validator.validate_YAML(yml))
{
throw eprosima::utils::ConfigurationException(
utils::Formatter() << "Error, the provided yaml file is not a valid ddsrouter configuration.\n");
}

try
{
ddspipe::yaml::YamlReaderVersion version;
Expand All @@ -52,15 +63,16 @@ YamlReaderConfiguration::load_ddsrouter_configuration(
default:

throw eprosima::utils::ConfigurationException(
utils::Formatter() <<
"The yaml configuration version " << version <<
" is no longer supported. Please update to v5.0.");
utils::Formatter()
<< "The yaml configuration version " << version
<< " is no longer supported. Please update to v5.0.");
break;

case ddspipe::yaml::YamlReaderVersion::V_4_0:
EPROSIMA_LOG_WARNING(DDSROUTER_YAML,
"The yaml configuration version " << version <<
" is deprecated and will be removed in a future release. Please update to v5.0.");
"The yaml configuration version "
<< version
<< " is deprecated and will be removed in a future release. Please update to v5.0.");
break;
}
}
Expand All @@ -69,9 +81,11 @@ YamlReaderConfiguration::load_ddsrouter_configuration(
// Get default version
version = default_yaml_version();
EPROSIMA_LOG_WARNING(DDSROUTER_YAML,
"No version of yaml configuration given. Using version " << version << " by default. " <<
"Add " << ddspipe::yaml::VERSION_TAG << " tag to your configuration in order to not break compatibility " <<
"in future releases.");
"No version of yaml configuration given. Using version "
<< version << " by default. "
<< "Add " << ddspipe::yaml::VERSION_TAG
<< " tag to your configuration in order to not break compatibility "
<< "in future releases.");
}

EPROSIMA_LOG_INFO(DDSROUTER_YAML, "Loading DDSRouter configuration with version: " << version << ".");
Expand Down Expand Up @@ -111,15 +125,15 @@ YamlReaderConfiguration::load_ddsrouter_configuration_from_file(
catch (const std::exception& e)
{
throw eprosima::utils::ConfigurationException(
utils::Formatter() << "Error loading DDSRouter configuration from file: <" << file_path <<
"> :\n " << e.what());
utils::Formatter() << "Error loading DDSRouter configuration from file: <" << file_path
<< "> :\n " << e.what());
}

if (yml.IsNull())
{
throw eprosima::utils::ConfigurationException(
utils::Formatter() << "Error loading DDSRouter configuration from file: <" << file_path <<
"> :\n " << "yaml node is null.");
utils::Formatter() << "Error loading DDSRouter configuration from file: <" << file_path
<< "> :\n " << "yaml node is null.");
}

return YamlReaderConfiguration::load_ddsrouter_configuration(yml, args);
Expand Down
1 change: 1 addition & 0 deletions ddsrouter_yaml/test/unittest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
# TODO uncomment when new API applied
add_subdirectory(configuration)
add_subdirectory(participants)
add_subdirectory(ddsrouter_yaml_validator)
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright 2026 Proyectos y Sistemas de Mantenimiento SL (eProsima).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#################################
# DdsRouter Yaml Validator Test #
#################################

set(TEST_NAME YamlValidatorDdsRouterTest)


set(TEST_SOURCES
YamlValidatorDdsRouterTest.cpp
)

set(TEST_LIST
validation_passed
validation_failed
)

set(TEST_EXTRA_LIBRARIES
yaml-cpp
fastcdr
fastdds
cpp_utils
ddspipe_core
ddspipe_participants
ddspipe_yaml
)

configure_file(
"${PROJECT_SOURCE_DIR}/../resources/configurations/ddsrouter_config_schema.json"
"${CMAKE_CURRENT_BINARY_DIR}/ddsrouter_config_schema.json"
COPYONLY
)

file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/valid_config_files_router/")
file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/invalid_config_files_router/")

file(GLOB_RECURSE TEST_NEEDED_SOURCES
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
"invalid_config_files_router/*.yaml"
"valid_config_files_router/*.yaml"
)

file(GLOB GETTING_STARTED_YAMLS
"${PROJECT_SOURCE_DIR}/../docs/resources/getting_started/*.yaml"
)
file(COPY ${GETTING_STARTED_YAMLS}
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/valid_config_files_router/"
)

file(GLOB EXAMPLES_YAMLS
"${PROJECT_SOURCE_DIR}/../resources/configurations/examples/*.yaml"
)
file(COPY ${EXAMPLES_YAMLS}
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/valid_config_files_router/"
)

add_unittest_executable(
"${TEST_NAME}"
"${TEST_SOURCES}"
"${TEST_LIST}"
"${TEST_EXTRA_LIBRARIES}"
"${TEST_NEEDED_SOURCES}"
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2026 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <filesystem>
#include <fstream>
#include <iostream>

#include <cpp_utils/testing/gtest_aux.hpp>
#include <gtest/gtest.h>

#include <ddspipe_yaml/YamlManager.hpp>
#include <ddspipe_yaml/YamlValidator.hpp>

using namespace eprosima;
using namespace eprosima::ddspipe::yaml;

namespace test {
// Paths and files for the tests
std::string schema_path = "./ddsrouter_config_schema.json";

// Vectors with the valid and invalid YAML files
std::vector<std::string> valid_files = []()
{
std::vector<std::string> files;
for (const auto& entry : std::filesystem::directory_iterator("./valid_config_files_router/"))
{
if (entry.path().extension() == ".yaml")
{
files.push_back(entry.path().generic_string());
}
}
return files;
}();

std::vector<std::string> invalid_files = []()
{
std::vector<std::string> files;
for (const auto& entry : std::filesystem::directory_iterator("./invalid_config_files_router/"))
{
if (entry.path().extension() == ".yaml")
{
files.push_back(entry.path().generic_string());
}
}
return files;
}();
} // namespace test

/**
* Test that a set of valid YAML configurations pass the validation
*/
TEST(YamlValidatorDdsRouterTest, validation_passed)
{
YamlValidator validator = YamlValidator(YamlValidator::from_file(test::schema_path));

// valid files
{
for (std::string st : test::valid_files)
{
Yaml yml = YamlManager::load_file(st);
ASSERT_TRUE(validator.validate_YAML(yml)) << "Failed for file: " << st;
}
}

}

/**
* Test that a set of invalid YAML configurations don't pass the validation
*/
TEST(YamlValidatorDdsRouterTest, validation_failed)
{
YamlValidator validator = YamlValidator(YamlValidator::from_file(test::schema_path));

// invalid files
{
for (std::string st : test::invalid_files)
{
Yaml yml = YamlManager::load_file(st);
// Validate is called with false to prevent filling the output with the specific errors
ASSERT_FALSE(validator.validate_YAML(yml, false)) << "Failed for file: " << st;
}
}
}

int main(
int argc,
char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
version: v4.1

allowlist:
- name: HelloWorldTopic
type: HelloWorld
Expand Down
Loading
Loading