├── RustDDS ├── .gitignore ├── README.md ├── Cargo.toml ├── logging-config.yaml └── src │ └── main.rs ├── resource ├── DDS-logo.jpg └── _md │ └── img │ ├── img1.png │ ├── img2.png │ ├── img3.png │ ├── img4.png │ ├── img5.png │ ├── img6.png │ ├── img7.png │ ├── img8.png │ ├── img9.png │ ├── img10.png │ ├── img11.png │ ├── img12.png │ ├── img13.png │ ├── img14.png │ ├── img15.png │ ├── img16.png │ ├── img17.png │ ├── img18.png │ ├── img19.png │ ├── img20.png │ └── img21.png ├── doc ├── _static │ ├── img │ │ ├── favicon.ico │ │ ├── DDS-logo-nobg.png │ │ ├── show_pretty_output.png │ │ └── show_all_test_suites.png │ └── css │ │ └── custom.css ├── index.rst ├── copyright.rst ├── vars.rst ├── test_results.template.rst ├── detailed_report.template.rst ├── introduction.rst ├── test_description.template.rst └── conf.py ├── requirements.txt ├── requirements_doc.txt ├── srcCxx ├── shape.idl ├── opendds-cmake │ └── CMakeLists.txt ├── intercom-dds-cmake │ └── CMakeLists.txt ├── shape_configurator_rti_connext_dds.h ├── shape_configurator_toc_coredx_dds.h ├── fast-dds-cmake │ └── CMakeLists.txt ├── shape_configurator_intercom_dds.h ├── makefile_rti_connext_dds_linux ├── shape_configurator_eprosima_fast_dds.h └── shape_configurator_opendds.h ├── CONTRIBUTING.md ├── srcRs └── DustDDS │ ├── Cargo.toml │ ├── build.rs │ └── Cargo.lock ├── COPYRIGHT.md ├── .github ├── ISSUE_TEMPLATE │ └── interoperability-issue-template.md └── workflows │ ├── ci_dustdds.yml │ ├── 4_publish_doc.yml │ ├── 3_generate_doc.yml │ ├── 2_upload_artifact.yml │ ├── ci_opendds.yml │ └── 1_run_interoperability_tests.yml ├── .gitignore ├── LICENSE.md ├── rtps_test_utilities.py ├── run_tests.sh ├── CLA ├── CLA_TEMPLATE.md ├── CLA_Atostek.md ├── CLA_ObjectComputing.md ├── CLA_OpenDDSFoundation.md ├── CLA_Real-Time_Innovations.md ├── CLA_S2E_Software_Systems.md ├── CLA_TwinOaksComputing.md ├── CLA_eProsima.md └── CLA_Kongsberg.md ├── get_latest_file_urls.py └── test_suite_functions.py /RustDDS/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /resource/DDS-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/DDS-logo.jpg -------------------------------------------------------------------------------- /resource/_md/img/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img1.png -------------------------------------------------------------------------------- /resource/_md/img/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img2.png -------------------------------------------------------------------------------- /resource/_md/img/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img3.png -------------------------------------------------------------------------------- /resource/_md/img/img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img4.png -------------------------------------------------------------------------------- /resource/_md/img/img5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img5.png -------------------------------------------------------------------------------- /resource/_md/img/img6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img6.png -------------------------------------------------------------------------------- /resource/_md/img/img7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img7.png -------------------------------------------------------------------------------- /resource/_md/img/img8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img8.png -------------------------------------------------------------------------------- /resource/_md/img/img9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img9.png -------------------------------------------------------------------------------- /doc/_static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/doc/_static/img/favicon.ico -------------------------------------------------------------------------------- /resource/_md/img/img10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img10.png -------------------------------------------------------------------------------- /resource/_md/img/img11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img11.png -------------------------------------------------------------------------------- /resource/_md/img/img12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img12.png -------------------------------------------------------------------------------- /resource/_md/img/img13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img13.png -------------------------------------------------------------------------------- /resource/_md/img/img14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img14.png -------------------------------------------------------------------------------- /resource/_md/img/img15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img15.png -------------------------------------------------------------------------------- /resource/_md/img/img16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img16.png -------------------------------------------------------------------------------- /resource/_md/img/img17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img17.png -------------------------------------------------------------------------------- /resource/_md/img/img18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img18.png -------------------------------------------------------------------------------- /resource/_md/img/img19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img19.png -------------------------------------------------------------------------------- /resource/_md/img/img20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img20.png -------------------------------------------------------------------------------- /resource/_md/img/img21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/resource/_md/img/img21.png -------------------------------------------------------------------------------- /doc/_static/img/DDS-logo-nobg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/doc/_static/img/DDS-logo-nobg.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | argcomplete==2.0.0 2 | pexpect==4.8.0 3 | junitparser==3.1.0 4 | XlsxWriter==3.1.9 5 | lxml==5.1.0 6 | -------------------------------------------------------------------------------- /doc/_static/img/show_pretty_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/doc/_static/img/show_pretty_output.png -------------------------------------------------------------------------------- /doc/_static/img/show_all_test_suites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omg-dds/dds-rtps/HEAD/doc/_static/img/show_all_test_suites.png -------------------------------------------------------------------------------- /requirements_doc.txt: -------------------------------------------------------------------------------- 1 | google-auth==2.29.0 2 | google-auth-httplib2==0.2.0 3 | google-api-python-client==2.127.0 4 | sphinx==7.3.7 5 | sphinx_rtd_theme==2.0.0 6 | -------------------------------------------------------------------------------- /srcCxx/shape.idl: -------------------------------------------------------------------------------- 1 | @appendable 2 | struct ShapeType { 3 | @key 4 | string<128> color; 5 | int32 x; 6 | int32 y; 7 | int32 shapesize; 8 | sequence additional_payload_size; 9 | }; 10 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: vars.rst 2 | 3 | Welcome to |INTEROPERABILITY_TESTS| 4 | *********************************** 5 | 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | :numbered: 10 | :glob: 11 | :caption: Contents 12 | 13 | introduction 14 | test_results 15 | test_description 16 | detailed_report 17 | copyright 18 | -------------------------------------------------------------------------------- /RustDDS/README.md: -------------------------------------------------------------------------------- 1 | # RustDDS interoperability test application 2 | 3 | ## Installation 4 | 5 | * Install [Rust development tools](https://www.rust-lang.org/tools/install) 6 | * Build the application in the normal way, using `cargo build` 7 | * Run using cargo, e.g. 8 | ** `cargo run -- --help` or 9 | ** `cargo run -- -P -t Triangle` 10 | 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | When submitting a pull request for the first time, you will need to agree to the Contributor License Agreement (CLA). To do this, please use the [CLA Template](CLA/CLA_TEMPLATE.md) to create a new file, fill in your details and include it in your pull request. You should name the file name CLA_{CompanyName}.md and place in inside the [CLA](CLA) directory alongside the other similar files there. 4 | 5 | -------------------------------------------------------------------------------- /srcCxx/opendds-cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(opendds_shape_main CXX) 3 | 4 | find_package(OpenDDS REQUIRED) 5 | 6 | add_executable(shape_main 7 | ../shape_main.cxx 8 | ) 9 | 10 | target_compile_definitions(shape_main 11 | PRIVATE OPENDDS 12 | ) 13 | 14 | opendds_target_sources(shape_main 15 | ../shape.idl 16 | OPENDDS_IDL_OPTIONS --no-default-nested 17 | ) 18 | 19 | target_link_libraries(shape_main OpenDDS::Rtps_Udp) 20 | -------------------------------------------------------------------------------- /RustDDS/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustdds_interop_test" 3 | version = "0.5.0" 4 | authors = ["Juhana Helovuo "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | clap = "2.33" 11 | rustdds = { version = "0.6" } 12 | #rustdds = { path ="../../RustDDS" } 13 | serde = { version="1", features=["derive"] } 14 | ctrlc = "3" 15 | mio = "0.6" 16 | mio-extras = "2" 17 | log = "0.4" 18 | log4rs = "1" 19 | rand = "0.8" 20 | 21 | -------------------------------------------------------------------------------- /doc/_static/css/custom.css: -------------------------------------------------------------------------------- 1 | .wy-nav-content { 2 | max-width: none !important; 3 | } 4 | 5 | table { 6 | width: 100% !important; 7 | } 8 | 9 | table a { 10 | color: #a1ae14 !important; 11 | font-weight: bold !important; 12 | font-size: 18px !important; 13 | } 14 | 15 | table p { 16 | white-space: normal !important; 17 | margin-bottom: 0 !important; 18 | display: inline-block; 19 | } 20 | 21 | table input { 22 | float: right !important; 23 | } 24 | 25 | .icon { 26 | height: auto !important; 27 | width: auto !important; 28 | } 29 | -------------------------------------------------------------------------------- /srcRs/DustDDS/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dust_dds_shape_main_linux" 3 | version = "0.1.0" 4 | description = "OMG DDS_RTPS Interoperability" 5 | edition = "2024" 6 | rust-version = "1.85" 7 | authors = [ 8 | "Joao Rebelo ", 9 | "Stefan Kimmer ", 10 | ] 11 | homepage = "https://s2e-systems.com/products/dust-dds" 12 | repository = "https://github.com/s2e-systems/dust-dds.git" 13 | readme = false 14 | publish = false 15 | 16 | [dependencies] 17 | clap = { version = "4.5.47", features = ["derive", "string"] } 18 | rand = "0.8.5" 19 | ctrlc = "3.4" 20 | dust_dds = "0.14.0" 21 | 22 | [build-dependencies] 23 | dust_dds_gen = "0.14.0" 24 | -------------------------------------------------------------------------------- /srcCxx/intercom-dds-cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16.3) 2 | 3 | project(intercom-dds_shape_main_linux LANGUAGES CXX) 4 | 5 | find_package(InterCOM REQUIRED) 6 | 7 | cidl_generate( ${CMAKE_CURRENT_LIST_DIR}/../shape.idl DESTINATION gen ) 8 | set(EXECUTABLE_NAME "intercom_dds-${InterCOM_VERSION}_shape_main_linux") 9 | add_executable(${EXECUTABLE_NAME} 10 | ${CMAKE_CURRENT_LIST_DIR}/../shape_main.cxx 11 | ${CIDL_GENERATE_OUTPUTS} 12 | ) 13 | target_compile_definitions(${EXECUTABLE_NAME} PRIVATE INTERCOM_DDS=1) 14 | target_link_libraries(${EXECUTABLE_NAME} InterCOM::intercom_static) 15 | target_include_directories(${EXECUTABLE_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/gen) -------------------------------------------------------------------------------- /doc/copyright.rst: -------------------------------------------------------------------------------- 1 | .. include:: vars.rst 2 | 3 | .. _section-copyright: 4 | 5 | Copyrights 6 | ********** 7 | 8 | |COPYRIGHT_HEADER| |br| 9 | All rights reserved. |br| 10 | Printed in U.S.A. First printing. |br| 11 | May |COPYRIGHT_YEAR|. 12 | 13 | .. rubric:: Trademarks 14 | 15 | All products or company names mentioned are used for identification purposes 16 | only, and may be trademarks of their respective owners. 17 | 18 | 19 | .. rubric:: Copy and Use Restrictions 20 | 21 | Use and redistribution is source and binary forms is permitted subject to the 22 | OMG-DDS INTEROPERABILITY TESTING LICENSE found at the following URL: 23 | 24 | https://github.com/omg-dds/dds-rtps/blob/master/LICENSE.md 25 | 26 | -------------------------------------------------------------------------------- /COPYRIGHT.md: -------------------------------------------------------------------------------- 1 | Copyright and license policy 2 | ============================ 3 | 4 | License 5 | ------- 6 | 7 | Use and redistribution is source and binary forms is permitted subject to the 8 | OMG-DDS INTEROPERABILITY TESTING LICENSE found at the following URL: 9 | 10 | https://github.com/omg-dds/dds-rtps/blob/master/LICENSE.md 11 | 12 | Copyright holders 13 | ----------------- 14 | 15 | © 2024 Real-Time Innovations, Inc. 16 | 17 | © 2024 Atostek Oy. 18 | 19 | © 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). 20 | 21 | © 2024 Kongsberg Defence & Aerospace. 22 | 23 | © 2024 Object Computing, Inc. 24 | 25 | © 2024 OpenDDS Foundation. 26 | 27 | © 2024 Twin Oaks Computing, Inc. 28 | © 2024 S2E Software Systems B.V. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/interoperability-issue-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Interoperability issue template 3 | about: Report an interoperability problem 4 | title: 'Problem with QoS/parameter' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | - **Please, modify the Title accordingly to show the problem** 11 | 12 | ### Executable's name 13 | 14 | - **Publisher**: 15 | - **Subscriber**: 16 | 17 | ### Reproducing the problem 18 | 19 | - **Test Suite**: 20 | - **Test Case**: 21 | - **Link to the GitHub Action workflow run**: 22 | 23 | ### What is the problem? 24 | 25 | - **Publisher expected code**: 26 | - **Publisher produced code**: 27 | - **Subscriber expected code**: 28 | - **Subscriber produced code**: 29 | 30 | ### Suggestions about why this problem exists 31 | 32 | - 33 | 34 | ### Other comments 35 | -------------------------------------------------------------------------------- /RustDDS/logging-config.yaml: -------------------------------------------------------------------------------- 1 | # configuration for log4rs crate 2 | refresh_rate: 10 seconds # interval for checking config changes 3 | appenders: 4 | stdout: 5 | kind: console 6 | root: 7 | level: info 8 | # level: error 9 | appenders: 10 | - stdout 11 | loggers: 12 | # mio: 13 | # level: warn 14 | mio_extras: 15 | level: warn 16 | # rustdds::dds::qos: 17 | # level: trace 18 | # rustdds::network::udp_listener: 19 | # level: trace 20 | # rustdds::discovery::discovery: 21 | # level: warn 22 | # rustdds::dds::dp_event_loop: 23 | # level: error 24 | # rustdds::discovery::discovery_db: 25 | # level: info 26 | # rustdds::dds::with_key::datareader: 27 | # level: debug 28 | # rustdds::dds::reader: 29 | # level: info 30 | # rustdds::dds::writer: 31 | # level: info 32 | 33 | -------------------------------------------------------------------------------- /srcRs/DustDDS/build.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fs::{self, File}, 3 | io::Write, 4 | path::Path, 5 | }; 6 | 7 | fn main() { 8 | let cargo_target_dir = std::env::var("OUT_DIR").unwrap(); 9 | let cargo_manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); 10 | let cargo_target_path = Path::new(&cargo_target_dir); 11 | let cargo_manifest_path = Path::new(&cargo_manifest_dir); 12 | let build_path = cargo_target_path.join("idl"); 13 | let idl_path = cargo_manifest_path.join("..").join("..").join("srcCxx").join("shape.idl"); 14 | let compiled_idl = dust_dds_gen::compile_idl(&idl_path).expect("Couldn't parse IDL file"); 15 | let compiled_idl_path = build_path.as_path().join("shape.rs"); 16 | fs::create_dir_all(build_path).expect("Creating build path failed"); 17 | let mut file = File::create(compiled_idl_path).expect("Failed to create file"); 18 | file.write_all(compiled_idl.as_bytes()) 19 | .expect("Failed to write to file"); 20 | } 21 | -------------------------------------------------------------------------------- /srcCxx/shape_configurator_rti_connext_dds.h: -------------------------------------------------------------------------------- 1 | #include "shape.h" 2 | #include "shapeSupport.h" 3 | #include "ndds/ndds_namespace_cpp.h" 4 | 5 | #define LISTENER_STATUS_MASK_ALL (DDS_STATUS_MASK_ALL) 6 | 7 | void StringSeq_push(DDS::StringSeq &string_seq, const char *elem) 8 | { 9 | string_seq.ensure_length(string_seq.length()+1, string_seq.length()+1); 10 | string_seq[string_seq.length()-1] = DDS_String_dup(elem); 11 | } 12 | 13 | const char *get_qos_policy_name(DDS_QosPolicyId_t policy_id) 14 | { 15 | return DDS_QosPolicyId_to_string(policy_id); // not standard... 16 | } 17 | 18 | void configure_participant_announcements_period( 19 | DDS::DomainParticipantQos &dp_qos, 20 | useconds_t announcement_period_us) { 21 | if (announcement_period_us == 0) { 22 | return; 23 | } 24 | dp_qos.discovery_config.participant_liveliness_assert_period.sec = 25 | announcement_period_us / 1000000; 26 | dp_qos.discovery_config.participant_liveliness_assert_period.nanosec = 27 | (announcement_period_us % 1000000) * 1000; 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/ci_dustdds.yml: -------------------------------------------------------------------------------- 1 | name: CI DustDDS 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | paths: 7 | - 'srcRs/DustDDS/**' 8 | 9 | jobs: 10 | create_bin_release: 11 | name: Create binary release 12 | runs-on: ubuntu-latest 13 | defaults: 14 | run: 15 | working-directory: srcRs/DustDDS 16 | steps: 17 | - name: Checkout sources 18 | uses: actions/checkout@v4 19 | - name: Build executable 20 | run: cargo build --package dust_dds_shape_main_linux --release 21 | - name: Rename executable 22 | run: | 23 | version=$( cargo tree --package dust_dds --depth 0 --prefix none | tr -d 'dust_dds v' ) 24 | cp ./target/release/dust_dds_shape_main_linux ./dust_dds-${version}_shape_main_linux 25 | mkdir artifacts 26 | zip --junk-paths artifacts/dust_dds-${version}_shape_main_linux.zip ./dust_dds-${version}_shape_main_linux 27 | - name: Upload executable artifact 28 | uses: actions/upload-artifact@v4 29 | with: 30 | name: interoperability_executable 31 | path: srcRs/DustDDS/artifacts/ 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | shape_main 31 | *shape_main_linux 32 | 33 | # Generated Makefiles 34 | .depend.* 35 | GNUmakefile* 36 | 37 | # Bin and Object directories 38 | bin/ 39 | objs/ 40 | 41 | # Other 42 | *~ 43 | GeneratedCode 44 | 45 | # Python files 46 | .venv/ 47 | *.pyc 48 | 49 | # Generated files 50 | srcCxx/shape.* 51 | srcCxx/shapePlugin.* 52 | srcCxx/shapeSupport.* 53 | 54 | # VSCode default folders 55 | .vscode/ 56 | build/ 57 | .cache/ 58 | 59 | # Generated reports 60 | *.xlsx 61 | *.xml 62 | *.zip 63 | *.html 64 | 65 | # Do not ignore templates 66 | !doc/_templates/*.html 67 | 68 | .DS_Store 69 | 70 | # Generated documentation files 71 | gdrive_url.py 72 | html/ 73 | doc/detailed_report.rst 74 | doc/test_results.rst 75 | test_description.rst 76 | doc/test_description.rst 77 | -------------------------------------------------------------------------------- /srcCxx/shape_configurator_toc_coredx_dds.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "shape.hh" 4 | #include "shapeTypeSupport.hh" 5 | #include "shapeDataReader.hh" 6 | #include "shapeDataWriter.hh" 7 | 8 | #define CONFIGURE_PARTICIPANT_FACTORY config_type_lookup(); 9 | #define LISTENER_STATUS_MASK_ALL (ALL_STATUS) 10 | 11 | #define DDS_UInt8Seq_get_length DDS_seq_get_length 12 | #define DDS_UInt8Seq_ensure_length(s,l,x) do { (s)->reserve(l); (s)->size(l); } while(0) 13 | #define DDS_UInt8Seq_get_reference(s,l) &( (*s)[l] ) 14 | #define Duration_from_micros(usec) Duration_t( usec / USEC_PER_SEC, ( usec % USEC_PER_SEC ) * 1000 ) 15 | 16 | #define DDS_BOOLEAN_TRUE (1) 17 | #define DDS_BOOLEAN_FALSE (0) 18 | 19 | void StringSeq_push(DDS::StringSeq &string_seq, const char *elem) 20 | { 21 | char * e = NULL; 22 | if ( elem ) 23 | { 24 | e = new char[strlen(elem)+1]; 25 | if ( e ) 26 | { 27 | strcpy( e, elem ); 28 | string_seq.push_back(e); 29 | } 30 | } 31 | } 32 | 33 | const char *get_qos_policy_name(DDS_QosPolicyId_t policy_id) 34 | { 35 | return DDS_qos_policy_str(policy_id); 36 | } 37 | 38 | static void config_type_lookup() 39 | { 40 | /* turn off Type Lookup Service (not the focus of the test) 41 | */ 42 | setenv( "COREDX_DO_TLS", "0", 1 ); 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/4_publish_doc.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: 4 - Publish Test Report (GitHub pages) 3 | 4 | on: workflow_dispatch 5 | 6 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 7 | permissions: 8 | contents: read 9 | pages: write 10 | id-token: write 11 | 12 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 13 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 14 | concurrency: 15 | group: "pages" 16 | cancel-in-progress: false 17 | 18 | jobs: 19 | # Single deploy job since we're just deploying 20 | deploy: 21 | environment: 22 | name: github-pages 23 | url: ${{ steps.deployment.outputs.page_url }} 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Get Artifact 27 | uses: dawidd6/action-download-artifact@v6 28 | with: 29 | name: documentation 30 | workflow: 3_generate_doc.yml 31 | - run: | 32 | mkdir html 33 | unzip documentation.zip -d html 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v5 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v3 38 | with: 39 | path: './html/' 40 | - name: Deploy to GitHub Pages 41 | id: deployment 42 | uses: actions/deploy-pages@v4 43 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # OMG-DDS INTEROPERABILITY TESTING LICENSE 2 | 3 | **Use in source and binary forms, with or without modification, is permitted solely for the testing and debugging of interoperability between implementations of the OMG DDS standard under the restrictions below. No other use of the software is permitted.** 4 | 5 | *Restrictions:* 6 | 7 | 1. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | 2. Reverse engineering of binary components is not permitted. 10 | 11 | 3. Use for competitive purposes such as evaluating performance or functionality is not permitted. 12 | 13 | 4. Redistribution of the source and binary forms is not permitted. 14 | 15 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.* 16 | 17 | -------------------------------------------------------------------------------- /doc/vars.rst: -------------------------------------------------------------------------------- 1 | .. |br| raw:: html 2 | 3 |
4 | 5 | .. |SHAPE_APP| replace:: ``Shape Application`` 6 | .. |SHAPE_APPS| replace:: ``Shape Applications`` 7 | .. |INTEROPERABILITY_TESTS_CP| replace:: OMG® DDS® Interoperability Testsuite 8 | .. |INTEROPERABILITY_TESTS| replace:: OMG DDS Interoperability Testsuite 9 | .. |COPYRIGHT_YEAR| replace:: 2024 10 | .. |COPYRIGHT_HEADER_RTI| replace:: © |COPYRIGHT_YEAR| Real-Time Innovations, Inc. 11 | .. |COPYRIGHT_HEADER_ATOSTEK| replace:: © |COPYRIGHT_YEAR| Atostek Oy. 12 | .. |COPYRIGHT_HEADER_EPROSIMA| replace:: © |COPYRIGHT_YEAR| Proyectos y Sistemas de Mantenimiento SL (eProsima). 13 | .. |COPYRIGHT_HEADER_KONGSBERG| replace:: © |COPYRIGHT_YEAR| Kongsberg Defence & Aerospace. 14 | .. |COPYRIGHT_HEADER_OCI| replace:: © |COPYRIGHT_YEAR| Object Computing, Inc. 15 | .. |COPYRIGHT_HEADER_OPENDDS| replace:: © |COPYRIGHT_YEAR| OpenDDS Foundation. 16 | .. |COPYRIGHT_HEADER_TOC| replace:: © |COPYRIGHT_YEAR| Twin Oaks Computing, Inc. 17 | .. |COPYRIGHT_HEADER_S2E| replace:: © |COPYRIGHT_YEAR| S2E Software Systems B.V. 18 | .. |COPYRIGHT_HEADER| replace:: |COPYRIGHT_HEADER_RTI| |br| 19 | |COPYRIGHT_HEADER_ATOSTEK| |br| 20 | |COPYRIGHT_HEADER_EPROSIMA| |br| 21 | |COPYRIGHT_HEADER_KONGSBERG| |br| 22 | |COPYRIGHT_HEADER_OCI| |br| 23 | |COPYRIGHT_HEADER_OPENDDS| |br| 24 | |COPYRIGHT_HEADER_TOC| |br| 25 | |COPYRIGHT_HEADER_S2E| |br| 26 | 27 | -------------------------------------------------------------------------------- /doc/test_results.template.rst: -------------------------------------------------------------------------------- 1 | .. include:: vars.rst 2 | 3 | .. _section-test-results: 4 | 5 | 6 | Test Results 7 | ============ 8 | 9 | The test results are presented in a spreadsheet containing multiple tabs. 10 | 11 | The first tab presents a summary of the tests per product: 12 | 13 | * The first table shows the number of passed tests versus total tests, offering 14 | a quick overview of vendor compliance. The result is reported using the notation 15 | (NumberPassedTests / NumberTotalTests). Colors are also used to highlight the 16 | level of interoperability (green being the best and red the worst) 17 | * The second table shows more detail on the interoperability between each pair 18 | of products: One product acting as **Publishers** (rows) and one as **Subscriber** 19 | (columns). The result is again reported using the notation 20 | (NumberPassedTests / NumberTotalTests). 21 | 22 | The second tab contains a summary of the test descriptions. The full details can 23 | be found in the `Test Descriptions section `__. 24 | 25 | The remaining tabs in the spreadsheet (see tab selection at the bottom of the 26 | spreadsheet) contain the individual test case results per product. Each tab 27 | is named after the respective product and contains two tables: 28 | 29 | * Left-side table: Current product as publisher and all products as subscribers. 30 | * Right-side table: Current product as subscriber and all products as publishers. 31 | 32 | Access the report at: |LINK_XLSX_URL| 33 | 34 | .. raw:: html 35 | 36 | 37 | -------------------------------------------------------------------------------- /.github/workflows/3_generate_doc.yml: -------------------------------------------------------------------------------- 1 | name: 3 - Generate Test Report 2 | run-name: ${{ github.actor }} is generating doc in GitHub Actions 🚀 3 | on: workflow_dispatch 4 | jobs: 5 | generate_doc: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout repository 9 | uses: actions/checkout@v4 10 | 11 | - name: Get Artifact 12 | uses: dawidd6/action-download-artifact@v6 13 | with: 14 | name: detailed_report 15 | workflow: 2_upload_artifact.yml 16 | 17 | - name: Move the detailed report to output folder 18 | run: | 19 | mkdir -p doc/_static/html/ 20 | mv *.html doc/_static/html/ 21 | ls doc/_static/html 22 | 23 | - name: Set up Python 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: '3.11.4' 27 | 28 | - name: Create virtual environment 29 | run: | 30 | python -m venv .venv 31 | source .venv/bin/activate 32 | 33 | - name: Setting up environment 34 | run: | 35 | pip install -r requirements_doc.txt 36 | pip install -r requirements.txt 37 | 38 | - name: Get latest XLSX and ZIP urls 39 | env: 40 | GCP_CREDENTIAL_STR: ${{ secrets.GCP_CREDENTIAL_STR }} 41 | DRIVE_FOLDER_ID: ${{ secrets.DRIVE_FOLDER_ID }} 42 | run: python get_latest_file_urls.py gdrive_url.py 43 | 44 | - name: Build documentation 45 | run: sphinx-build -b html doc html 46 | 47 | - name: Zip the documentation 48 | run: | 49 | cd html 50 | zip -r ../documentation.zip . 51 | 52 | - name: Attach html documentation 53 | uses: actions/upload-artifact@v4 54 | with: 55 | name: documentation 56 | path: documentation.zip 57 | -------------------------------------------------------------------------------- /.github/workflows/2_upload_artifact.yml: -------------------------------------------------------------------------------- 1 | name: 2 - Upload Test Results to Drive 2 | run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 3 | on: workflow_dispatch 4 | jobs: 5 | upload_artifact: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Get Artifact 9 | uses: dawidd6/action-download-artifact@v6 10 | with: 11 | name: interoperability_report_complete 12 | workflow: 1_run_interoperability_tests.yml 13 | workflow_conclusion: completed 14 | - name: Create files to upload 15 | run: | 16 | current_date=$(cat timestamp) 17 | mv index.html interoperability_report.html 18 | for file in *; do \ 19 | mv "$file" "${file%.*}_$current_date.${file##*.}"; \ 20 | done 21 | zip interoperability_report_$current_date.zip * 22 | mkdir report_$current_date 23 | mv *.zip report_$current_date/ 24 | mv *.xlsx report_$current_date/ 25 | - name: Upload zip artifact 26 | uses: adityak74/google-drive-upload-git-action@main 27 | with: 28 | credentials: ${{ secrets.GCP_CREDENTIAL }} 29 | filename: report_*/*.zip 30 | folderId: ${{ secrets.DRIVE_FOLDER_ID }} 31 | overwrite: "true" 32 | mirrorDirectoryStructure: "true" 33 | - name: Upload spreadsheet 34 | uses: adityak74/google-drive-upload-git-action@main 35 | with: 36 | credentials: ${{ secrets.GCP_CREDENTIAL }} 37 | filename: report_*/*.xlsx 38 | folderId: ${{ secrets.DRIVE_FOLDER_ID }} 39 | overwrite: "true" 40 | mirrorDirectoryStructure: "true" 41 | mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" 42 | - name: Attach detailed report html 43 | uses: actions/upload-artifact@v4 44 | with: 45 | name: detailed_report 46 | path: | 47 | ./interoperability_report*.html 48 | -------------------------------------------------------------------------------- /doc/detailed_report.template.rst: -------------------------------------------------------------------------------- 1 | .. include:: vars.rst 2 | 3 | .. _section-detailed-report: 4 | 5 | Detailed Report 6 | =============== 7 | 8 | This test report displays individual test results for all products regarding 9 | DDS interoperability. By default, it only shows test suites containing 10 | tests with errors. For each test, the report includes detailed information 11 | about the test case. If the test has failed, it also shows the observed error 12 | and the corresponding program output. 13 | 14 | |br| 15 | 16 | .. raw:: html 17 | 18 |
Using the Detailed Report
19 | 20 | |br| 21 | 22 | To display all test suites, click on ``Advanced Filter`` / ``Suites`` / 23 | ``Empty hidden``. As shown in the image: 24 | 25 | |br| 26 | 27 | .. image:: _static/img/show_all_test_suites.png 28 | :alt: Show All Tests 29 | :align: center 30 | 31 | |br| 32 | 33 | The name of the test suite contains two product names separated by 3 dashes. It 34 | represents the product used as a **Publisher** (on the left) and the 35 | product used as a **Subscriber** (on the right): 36 | 37 | * \\-\-\-\ 38 | 39 | |br| 40 | 41 | By default, in case of an error in a test case, the |SHAPE_APP| output is shown 42 | as raw HTML code. You can enable a pretty print of that text by clicking the 43 | ``raw`` button. However, you may want to enable this option for all test output 44 | by clicking the option ``raw`` in ``Advanced Filter`` / ``Tests`` / ``All`` row. 45 | 46 | |br| 47 | 48 | .. image:: _static/img/show_pretty_output.png 49 | :alt: Show All Tests 50 | :align: center 51 | 52 | |br| 53 | 54 | .. raw:: html 55 | 56 |
Detailed Report HTML
57 | 58 | |br| 59 | 60 | The following section is the HTML report that you can interact with: 61 | 62 | |br| 63 | 64 | .. raw:: html 65 | :file: |INDEX_HTML_PATH| 66 | -------------------------------------------------------------------------------- /srcCxx/fast-dds-cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 3.16.3) 16 | 17 | project(eprosima-fastdds_shape_main_linux LANGUAGES CXX) 18 | 19 | # Find requirements 20 | set(FASTDDS_STATIC ON) 21 | find_package(fastcdr REQUIRED) 22 | find_package(fastdds REQUIRED) 23 | find_program(FASTDDSGEN fastddsgen) 24 | 25 | # Generate code from IDL 26 | file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/../GeneratedCode) 27 | set( 28 | GENERATED_TYPE_SUPPORT_SOURCES 29 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapePubSubTypes.cxx 30 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapeTypeObjectSupport.cxx 31 | ) 32 | set( 33 | GENERATED_TYPE_SUPPORT_FILES 34 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shape.hpp 35 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapeCdrAux.hpp 36 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapeCdrAux.ipp 37 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapePubSubTypes.cxx 38 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapePubSubTypes.hpp 39 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapeTypeObjectSupport.cxx 40 | ${CMAKE_SOURCE_DIR}/../GeneratedCode/shapeTypeObjectSupport.hpp 41 | ) 42 | add_custom_command( 43 | OUTPUT ${GENERATED_TYPE_SUPPORT_FILES} 44 | COMMAND ${FASTDDSGEN} 45 | -replace 46 | -d ${CMAKE_SOURCE_DIR}/../GeneratedCode 47 | -flat-output-dir 48 | ${CMAKE_SOURCE_DIR}/../shape.idl 49 | DEPENDS ${CMAKE_SOURCE_DIR}/../shape.idl 50 | COMMENT "Generating code with Fast DDS Gen" VERBATIM 51 | ) 52 | 53 | message(STATUS "Configuring application...") 54 | set(EXECUTABLE_NAME "eprosima_fastdds-${fastdds_VERSION}_shape_main_linux") 55 | add_executable(${EXECUTABLE_NAME} 56 | ../shape_main.cxx 57 | ${GENERATED_TYPE_SUPPORT_SOURCES} 58 | ) 59 | target_compile_definitions(${EXECUTABLE_NAME} PRIVATE EPROSIMA_FAST_DDS=1) 60 | target_link_libraries(${EXECUTABLE_NAME} fastdds) 61 | -------------------------------------------------------------------------------- /rtps_test_utilities.py: -------------------------------------------------------------------------------- 1 | ################################################################# 2 | # Use and redistribution is source and binary forms is permitted 3 | # subject to the OMG-DDS INTEROPERABILITY TESTING LICENSE found 4 | # at the following URL: 5 | # 6 | # https://github.com/omg-dds/dds-rtps/blob/master/LICENSE.md 7 | # 8 | ################################################################# 9 | import re 10 | 11 | from enum import Enum 12 | class ReturnCode(Enum): 13 | """" 14 | Codes to give information about Shape Applications' behavior. 15 | 16 | OK : Publisher/Subscriber sent/received data correctly 17 | TOPIC_NOT_CREATED : Publisher/Subscriber does not create the topic 18 | READER_NOT_CREATED : Subscriber does not create the Data Reader 19 | WRITER_NOT_CREATED : Publisher does not create the Data Writer 20 | FILTER_NOT_CREATED : Subscriber does not create the content filter 21 | INCOMPATIBLE_QOS : Publisher/Subscriber with incompatible QoS. 22 | READER_NOT_MATCHED : Publisher does not find any compatible Data Reader 23 | DATA_NOT_RECEIVED : Subscriber does not receive the data 24 | DATA_NOT_SENT : Publisher does not send the data 25 | DATA_NOT_CORRECT : Subscriber does not find the data expected 26 | RECEIVING_FROM_ONE : Subscriber receives from one Publisher 27 | RECEIVING_FROM_BOTH : Subscriber receives from two Publishers 28 | DEADLINE_MISSED : Publisher/Subscriber missed the deadline period 29 | ORDERED_ACCESS_INSTANCE : Subscriber reading with ordered access and access scope INSTANCE 30 | ORDERED_ACCESS_TOPIC : Subscriber reading with ordered access and access scope TOPIC 31 | """ 32 | OK = 0 33 | TOPIC_NOT_CREATED = 1 34 | READER_NOT_CREATED = 2 35 | WRITER_NOT_CREATED = 3 36 | FILTER_NOT_CREATED = 4 37 | INCOMPATIBLE_QOS = 5 38 | READER_NOT_MATCHED = 6 39 | DATA_NOT_RECEIVED = 9 40 | DATA_NOT_SENT = 10 41 | DATA_NOT_CORRECT = 11 42 | RECEIVING_FROM_ONE = 12 43 | RECEIVING_FROM_BOTH = 13 44 | DEADLINE_MISSED = 14 45 | ORDERED_ACCESS_INSTANCE = 15 46 | ORDERED_ACCESS_TOPIC = 16 47 | 48 | def log_message(message, verbosity): 49 | if verbosity: 50 | print(message) 51 | 52 | def remove_ansi_colors(text): 53 | ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') 54 | cleaned_str = ansi_escape.sub('', text) 55 | return cleaned_str 56 | 57 | def no_check(child_sub, samples_sent, last_sample_saved, timeout): 58 | return ReturnCode.OK 59 | -------------------------------------------------------------------------------- /srcCxx/shape_configurator_intercom_dds.h: -------------------------------------------------------------------------------- 1 | #include "shape.h" 2 | #include 3 | #include 4 | 5 | #define StringSeq_push(seq, val) seq.push_back(val) 6 | #define LISTENER_STATUS_MASK_ALL STATUS_MASK_ALL 7 | #define REGISTER_TYPE ShapeTypeTypeSupport::get_instance()->register_type 8 | #define STRING_IN .c_str() 9 | #define STRING_ASSIGN(a, b) a = b 10 | #define STRING_FREE static_cast 11 | 12 | #define DDS_UInt8Seq_get_length(s) (s)->size() 13 | #define DDS_UInt8Seq_ensure_length(s,l,x) (s)->resize(l) 14 | #define DDS_UInt8Seq_get_reference(s,l) &( (*s)[l] ) 15 | 16 | #define DDS_BOOLEAN_TRUE true 17 | #define DDS_BOOLEAN_FALSE false 18 | 19 | inline const char *get_qos_policy_name(DDS::QosPolicyId_t policy_id) { 20 | switch (policy_id) { 21 | case DDS::USERDATA_QOS_POLICY_ID: 22 | return "USERDATA"; 23 | case DDS::DURABILITY_QOS_POLICY_ID: 24 | return "DURABILITY"; 25 | case DDS::PRESENTATION_QOS_POLICY_ID: 26 | return "PRESENTATION"; 27 | case DDS::DEADLINE_QOS_POLICY_ID: 28 | return "DEADLINE"; 29 | case DDS::LATENCYBUDGET_QOS_POLICY_ID: 30 | return "LATENCYBUDGET"; 31 | case DDS::OWNERSHIP_QOS_POLICY_ID: 32 | return "OWNERSHIP"; 33 | case DDS::OWNERSHIPSTRENGTH_QOS_POLICY_ID: 34 | return "OWNERSHIPSTRENGTH"; 35 | case DDS::LIVELINESS_QOS_POLICY_ID: 36 | return "LIVELINESS"; 37 | case DDS::TIMEBASEDFILTER_QOS_POLICY_ID: 38 | return "TIMEBASEDFILTER"; 39 | case DDS::PARTITION_QOS_POLICY_ID: 40 | return "PARTITION"; 41 | case DDS::RELIABILITY_QOS_POLICY_ID: 42 | return "RELIABILITY"; 43 | case DDS::DESTINATIONORDER_QOS_POLICY_ID: 44 | return "DESTINATIONORDER"; 45 | case DDS::HISTORY_QOS_POLICY_ID: 46 | return "HISTORY"; 47 | case DDS::RESOURCELIMITS_QOS_POLICY_ID: 48 | return "RESOURCELIMITS"; 49 | case DDS::ENTITYFACTORY_QOS_POLICY_ID: 50 | return "ENTITYFACTORY"; 51 | case DDS::WRITERDATALIFECYCLE_QOS_POLICY_ID: 52 | return "WRITERDATALIFECYCLE"; 53 | case DDS::READERDATALIFECYCLE_QOS_POLICY_ID: 54 | return "READERDATALIFECYCLE"; 55 | case DDS::TOPICDATA_QOS_POLICY_ID: 56 | return "TOPICDATA"; 57 | case DDS::GROUPDATA_QOS_POLICY_ID: 58 | return "GROUPDATA"; 59 | case DDS::TRANSPORTPRIORITY_QOS_POLICY_ID: 60 | return "TRANSPORTPRIORITY"; 61 | case DDS::LIFESPAN_QOS_POLICY_ID: 62 | return "LIFESPAN"; 63 | case DDS::DURABILITYSERVICE_QOS_POLICY_ID: 64 | return "DURABILITYSERVICE"; 65 | case DDS::DATA_REPRESENTATION_QOS_POLICY_ID: 66 | return "DATAREPRESENTATION"; 67 | default: 68 | return "Unknown"; 69 | } 70 | } -------------------------------------------------------------------------------- /srcCxx/makefile_rti_connext_dds_linux: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # To compile, type: 3 | # make -f makefile_rti_connext_dds_linux 4 | # To compile with the Debug option, use: 5 | # make -f makefile_rti_connext_dds_linux DEBUG=1 6 | # 7 | # This makefile assumes that your build environment is already correctly 8 | # configured. (For example, the correct version of your compiler and 9 | # linker should be on your PATH.) 10 | # 11 | # You should set the environemnt variable NDDSHOME to point to where 12 | # RTI Connext DDS is installed. 13 | # 14 | ###################################################################### 15 | 16 | # If undefined in the environment default NDDSHOME to install dir 17 | ifndef NDDSHOME 18 | $(error NDDSHOME not defined) 19 | endif 20 | 21 | ifndef CONNEXTDDS_ARCH 22 | $(error CONNEXTDDS_ARCH not defined) 23 | endif 24 | 25 | COMPILER_FLAGS = -m64 26 | LINKER_FLAGS = -m64 -static-libgcc 27 | 28 | split_path_name = $(subst /rti_, , $(NDDSHOME)) 29 | 30 | version_name = $(lastword $(split_path_name)) 31 | common_name = "_shape_main_linux" 32 | executable_name = $(version_name)$(common_name) 33 | 34 | TARGET_ARCH = $(CONNEXTDDS_ARCH) 35 | 36 | ifndef COMPILER 37 | COMPILER = g++ 38 | endif 39 | 40 | ifndef LINKER 41 | LINKER = g++ 42 | endif 43 | 44 | SYSLIBS = -ldl -lnsl -lm -lpthread -lrt 45 | 46 | ifeq ($(DEBUG),1) 47 | COMPILER_FLAGS += -g -O0 48 | LINKER_FLAGS += -g 49 | LIBS = -L$(NDDSHOME)/lib/$(TARGET_ARCH) \ 50 | -lnddscppzd -lnddsczd -lnddscorezd $(SYSLIBS) 51 | else 52 | # This option strips the executable symbols 53 | LINKER_FLAGS += -s 54 | LIBS = -L$(NDDSHOME)/lib/$(TARGET_ARCH) \ 55 | -lnddscppz -lnddscz -lnddscorez $(SYSLIBS) 56 | endif 57 | 58 | DEFINES = -DRTI_UNIX -DRTI_LINUX -DRTI_CONNEXT_DDS 59 | 60 | INCLUDES = -I. -I$(NDDSHOME)/include -I$(NDDSHOME)/include/ndds 61 | 62 | OBJDIR := objs/$(TARGET_ARCH) 63 | 64 | CDRSOURCES := shape.idl 65 | AUTOGENSOURCES := shapeSupport.cxx shapePlugin.cxx shape.cxx 66 | 67 | EXEC := $(executable_name) 68 | AUTOGENOBJS := $(addprefix $(OBJDIR)/, $(AUTOGENSOURCES:%.cxx=%.o)) 69 | 70 | $(OBJDIR)/$(EXEC) : $(AUTOGENSOURCES) $(AUTOGENOBJS) $(OBJDIR)/shape_main.o 71 | $(LINKER) $(LINKER_FLAGS) -o $@ $(OBJDIR)/shape_main.o $(AUTOGENOBJS) $(LIBS) 72 | 73 | $(OBJDIR)/%.o : %.cxx 74 | $(COMPILER) $(COMPILER_FLAGS) -Wextra -Wall -pedantic -o $@ $(DEFINES) $(INCLUDES) -c $< 75 | 76 | shape_main.cxx : shape_configurator_rti_connext_dds.h 77 | 78 | # Generate type-specific sources 79 | $(AUTOGENSOURCES) : $(CDRSOURCES) 80 | $(NDDSHOME)/bin/rtiddsgen $(CDRSOURCES) -replace -language C++ -unboundedSupport 81 | 82 | $(AUTOGENOBJS): | objs/$(TARGET_ARCH) 83 | 84 | objs/$(TARGET_ARCH): 85 | echo "Making directory objs/$(TARGET_ARCH)"; 86 | mkdir -p objs/$(TARGET_ARCH) 87 | -------------------------------------------------------------------------------- /doc/introduction.rst: -------------------------------------------------------------------------------- 1 | .. include:: vars.rst 2 | 3 | .. _section-introduction: 4 | 5 | Introduction 6 | ============ 7 | 8 | The |INTEROPERABILITY_TESTS_CP| is a collection of test cases that validate the 9 | wire protocol interoperability of implementations of the Data Distribution Service® 10 | (DDS) standard. The test suite verifies that different DDS implementations communicate as 11 | expected across a variety of scenarios, including various Quality of Service (QoS) 12 | settings. 13 | 14 | The |INTEROPERABILITY_TESTS| are publicly available on this repository: 15 | https://github.com/omg-dds/dds-rtps/ 16 | 17 | Test Descriptions 18 | ----------------- 19 | 20 | The test cases are implemented on using an application, called |SHAPE_APP|, that is compiled 21 | against each of the DDS implementations, resulting in a different binary executable for each 22 | DDS implementation. 23 | 24 | The |SHAPE_APP| has a set of command-line parameters controlling its behavior (e.g. publish versus subscribe), 25 | the Qos settings (e.g. reliability, durability, ownership), and the use of various other features (e.g. Content Filters). 26 | More information on the the command-line options can be found in this README file: 27 | `Shape Application Parameters Section in README 28 | `__. 29 | 30 | Each test case is is defined in terms of a specific deployment of the |SHAPE_APP| executables, 31 | the parameters used to run each executable, and the expected test result (return code). The produced return code 32 | depends on the output of the |SHAPE_APP|. More information is available in the 33 | README file's Return Code section: 34 | `Return Code Section in README 35 | `__ 36 | 37 | A test case minimally runs two instances of the |SHAPE_APP|, one acting as a **Publisher** or a **Subscriber** application. 38 | Some test cases may run additional instances when it is required to exercise a particular behavior. 39 | 40 | For example, a specific test case may specify running the binary for Implementation1 with parameters 41 | that configure it to publish data with a certain Qos against the binary for Implementation2 with parameters 42 | that cause it to subscribe data with a different Qos. The expected result may state that all 43 | data published by one application should be received by the other one in the correct order without any duplicates. 44 | 45 | A test case *passes* if the communication between the **Publisher** and **Subscriber** application(s) 46 | matches what is expected for that scenario. The "expected" behavior may involve receiving all samples sent, 47 | or specific subsets (e.g. when using content filters or exclusive ownership Qos), it may also involve verifying 48 | that samples are received in specific order, or not received at all (e.g. when the Qos is incompatible). Where needed, 49 | a test case defines a ``check_function`` to parse the output printed by the |SHAPE_APP| and determine 50 | whether the test case *passes* or *fails*. 51 | 52 | The test cases included in the |INTEROPERABILITY_TESTS| are defined in a 53 | `test suite `__ 54 | that is part of this repository. 55 | 56 | Test Performed 57 | -------------- 58 | 59 | The |INTEROPERABILITY_TESTS| runs the test cases using all permutations of DDS implementations as **Publisher** and as **Subscriber** 60 | applications. The products included in the tests are the |SHAPE_APPS| uploaded to the 61 | `latest release of the repository `__. -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Default values 4 | input="." 5 | publisher="" 6 | subscriber="" 7 | output="" 8 | 9 | # Function to display usage information 10 | usage() { 11 | echo "Run the interoperability_report script for the specified applications." 12 | echo "If a publisher/subscriber is provided only that publisher/subscriber" 13 | echo "is used as a publisher or subscriber application. If a publisher or" 14 | echo "subscriber is not provided, this script will find and use all " 15 | echo "'*_shape_main_linux' applications in the input directory as publisher and" 16 | echo "subscribers." 17 | echo "Usage: $0 [-p publisher] [-s subscriber] [-o output] [-i input] [-h]" 18 | echo "Options:" 19 | echo " -p, --publisher Specify the publisher application" 20 | echo " -s, --subscriber Specify the subscriber application" 21 | echo " -o, --output Specify the output XML file" 22 | echo " -i, --input Specify the directory where publisher/subscriber applications are located (only if -p and -s are not provided)" 23 | echo " -h, --help Print this help message" 24 | echo "Examples:" 25 | echo "Run Connext as publisher and all executables under './executables' as subscribers" 26 | echo " ./run_tests.sh -p connext_dds-6.1.2_shape_main_linux -i ./executables" 27 | exit 1 28 | } 29 | 30 | # Parse command-line arguments 31 | while [[ $# -gt 0 ]]; do 32 | case "$1" in 33 | -p|--publisher) 34 | publisher="$2" 35 | shift 2 36 | ;; 37 | -s|--subscriber) 38 | subscriber="$2" 39 | shift 2 40 | ;; 41 | -o|--output) 42 | output="$2" 43 | shift 2 44 | ;; 45 | -i|--input) 46 | input="$2" 47 | shift 2 48 | ;; 49 | -h|--help) 50 | usage 51 | ;; 52 | *) 53 | echo "Error: Unknown option $1" 54 | usage 55 | ;; 56 | esac 57 | done 58 | 59 | # If publisher is not provided, find publisher applications 60 | if [[ -z $publisher ]]; then 61 | echo "Searching for publisher applications in directory: $input" 62 | publisher=$(find "$input" -type f -name '*shape_main_linux') 63 | fi 64 | 65 | # If subscriber is not provided, find subscriber applications 66 | if [[ -z $subscriber ]]; then 67 | echo "Searching for subscriber applications in directory: $input" 68 | subscriber=$(find "$input" -type f -name '*shape_main_linux') 69 | fi 70 | 71 | # Check if required options are provided 72 | if [[ -z $publisher || -z $subscriber ]]; then 73 | echo "Error: Unable to find publisher or subscriber applications." 74 | usage 75 | fi 76 | 77 | # Run the application logic 78 | for i in $publisher; do 79 | for j in $subscriber; do 80 | publisher_name=$(basename "$i" _shape_main_linux) 81 | subscriber_name=$(basename "$j" _shape_main_linux) 82 | echo "Testing Publisher $publisher_name --- Subscriber $subscriber_name" 83 | extra_args="" 84 | if [[ "${subscriber,,}" == *opendds* && "${publisher,,}" == *connext* ]]; then 85 | extra_args="--periodic-announcement 5000" 86 | fi; 87 | if [[ -n $output ]]; then 88 | python3 ./interoperability_report.py -P "$i" -S "$j" -o "$output" $extra_args 89 | else 90 | python3 ./interoperability_report.py -P "$i" -S "$j" $extra_args 91 | fi 92 | if [ -d "./OpenDDS-durable-data-dir" ]; then 93 | echo Deleting OpenDDS-durable-data-dir; 94 | rm -rf ./OpenDDS-durable-data-dir; 95 | fi; 96 | done 97 | done 98 | -------------------------------------------------------------------------------- /srcCxx/shape_configurator_eprosima_fast_dds.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "GeneratedCode/shape.hpp" 15 | #include "GeneratedCode/shapePubSubTypes.hpp" 16 | 17 | #define LISTENER_STATUS_MASK_ALL StatusMask::all() 18 | #define LISTENER_STATUS_MASK_NONE StatusMask::none() 19 | #define REGISTER_TYPE TypeSupport ts(new ShapeTypePubSubType()); ts.register_type 20 | #define STRING_ASSIGN(field, value) field() = value 21 | #define STRING_IN .c_str() 22 | #define NAME_ACCESSOR .c_str() 23 | #define FIELD_ACCESSOR () 24 | #define GET_TOPIC_DESCRIPTION(dr) const_cast(dr->get_topicdescription()) 25 | #define ADD_PARTITION(field, value) field().push_back(value) 26 | #define SECONDS_FIELD_NAME seconds 27 | 28 | #define ShapeTypeDataReader DataReader 29 | #define ShapeTypeDataWriter DataWriter 30 | #define StringSeq std::vector 31 | 32 | namespace DDS = eprosima::fastdds::dds; 33 | #define RETCODE_OK DDS::RETCODE_OK 34 | 35 | const char* get_qos_policy_name(DDS::QosPolicyId_t policy_id) 36 | { 37 | switch (policy_id) { 38 | case DDS::USERDATA_QOS_POLICY_ID: return "USERDATA"; 39 | case DDS::DURABILITY_QOS_POLICY_ID: return "DURABILITY"; 40 | case DDS::PRESENTATION_QOS_POLICY_ID: return "PRESENTATION"; 41 | case DDS::DEADLINE_QOS_POLICY_ID: return "DEADLINE"; 42 | case DDS::LATENCYBUDGET_QOS_POLICY_ID: return "LATENCYBUDGET"; 43 | case DDS::OWNERSHIP_QOS_POLICY_ID: return "OWNERSHIP"; 44 | case DDS::OWNERSHIPSTRENGTH_QOS_POLICY_ID: return "OWNERSHIPSTRENGTH"; 45 | case DDS::LIVELINESS_QOS_POLICY_ID: return "LIVELINESS"; 46 | case DDS::TIMEBASEDFILTER_QOS_POLICY_ID: return "TIMEBASEDFILTER"; 47 | case DDS::PARTITION_QOS_POLICY_ID: return "PARTITION"; 48 | case DDS::RELIABILITY_QOS_POLICY_ID: return "RELIABILITY"; 49 | case DDS::DESTINATIONORDER_QOS_POLICY_ID: return "DESTINATIONORDER"; 50 | case DDS::HISTORY_QOS_POLICY_ID: return "HISTORY"; 51 | case DDS::RESOURCELIMITS_QOS_POLICY_ID: return "RESOURCELIMITS"; 52 | case DDS::ENTITYFACTORY_QOS_POLICY_ID: return "ENTITYFACTORY"; 53 | case DDS::WRITERDATALIFECYCLE_QOS_POLICY_ID: return "WRITERDATALIFECYCLE"; 54 | case DDS::READERDATALIFECYCLE_QOS_POLICY_ID: return "READERDATALIFECYCLE"; 55 | case DDS::TOPICDATA_QOS_POLICY_ID: return "TOPICDATA"; 56 | case DDS::GROUPDATA_QOS_POLICY_ID: return "GROUPDATA"; 57 | case DDS::TRANSPORTPRIORITY_QOS_POLICY_ID: return "TRANSPORTPRIORITY"; 58 | case DDS::LIFESPAN_QOS_POLICY_ID: return "LIFESPAN"; 59 | case DDS::DURABILITYSERVICE_QOS_POLICY_ID: return "DURABILITYSERVICE"; 60 | default: return "Unknown"; 61 | } 62 | } 63 | 64 | uint64_t DDS_UInt8Seq_get_length(const std::vector* seq) 65 | { 66 | return seq->size(); 67 | } 68 | 69 | void DDS_UInt8Seq_ensure_length(std::vector* seq, uint64_t length, uint64_t = 0) 70 | { 71 | seq->resize(length); 72 | } 73 | 74 | unsigned char* DDS_UInt8Seq_get_reference(std::vector* seq, uint64_t index) 75 | { 76 | return &((*seq)[index]); 77 | } 78 | 79 | const unsigned char* DDS_UInt8Seq_get_reference(const std::vector* seq, uint64_t index) 80 | { 81 | return &((*seq)[index]); 82 | } 83 | -------------------------------------------------------------------------------- /srcCxx/shape_configurator_opendds.h: -------------------------------------------------------------------------------- 1 | #include "shapeTypeSupportImpl.h" 2 | 3 | #include "dds/DCPS/Marked_Default_Qos.h" 4 | #include "dds/DCPS/Service_Participant.h" 5 | 6 | #include "dds/DCPS/RTPS/RtpsDiscovery.h" 7 | 8 | #include "dds/DCPS/transport/framework/TransportConfig_rch.h" 9 | #include "dds/DCPS/transport/framework/TransportRegistry.h" 10 | #include "dds/DCPS/transport/rtps_udp/RtpsUdp.h" 11 | 12 | #define OBTAIN_DOMAIN_PARTICIPANT_FACTORY TheParticipantFactory 13 | #define LISTENER_STATUS_MASK_ALL OpenDDS::DCPS::ALL_STATUS_MASK 14 | #define REGISTER_TYPE ShapeTypeTypeSupport_var ts = \ 15 | new ShapeTypeTypeSupportImpl; ts->register_type 16 | #define CONFIGURE_PARTICIPANT_FACTORY configure_rtps(); 17 | #define STRING_IN .in() 18 | #define STRING_INOUT .inout() 19 | #define STRING_ALLOC(LHS, RHS) LHS = CORBA::string_alloc(RHS) 20 | 21 | const char* get_qos_policy_name(DDS::QosPolicyId_t policy_id) 22 | { 23 | switch (policy_id) { 24 | case DDS::USERDATA_QOS_POLICY_ID: return "USERDATA"; 25 | case DDS::DURABILITY_QOS_POLICY_ID: return "DURABILITY"; 26 | case DDS::PRESENTATION_QOS_POLICY_ID: return "PRESENTATION"; 27 | case DDS::DEADLINE_QOS_POLICY_ID: return "DEADLINE"; 28 | case DDS::LATENCYBUDGET_QOS_POLICY_ID: return "LATENCYBUDGET"; 29 | case DDS::OWNERSHIP_QOS_POLICY_ID: return "OWNERSHIP"; 30 | case DDS::OWNERSHIPSTRENGTH_QOS_POLICY_ID: return "OWNERSHIPSTRENGTH"; 31 | case DDS::LIVELINESS_QOS_POLICY_ID: return "LIVELINESS"; 32 | case DDS::TIMEBASEDFILTER_QOS_POLICY_ID: return "TIMEBASEDFILTER"; 33 | case DDS::PARTITION_QOS_POLICY_ID: return "PARTITION"; 34 | case DDS::RELIABILITY_QOS_POLICY_ID: return "RELIABILITY"; 35 | case DDS::DESTINATIONORDER_QOS_POLICY_ID: return "DESTINATIONORDER"; 36 | case DDS::HISTORY_QOS_POLICY_ID: return "HISTORY"; 37 | case DDS::RESOURCELIMITS_QOS_POLICY_ID: return "RESOURCELIMITS"; 38 | case DDS::ENTITYFACTORY_QOS_POLICY_ID: return "ENTITYFACTORY"; 39 | case DDS::WRITERDATALIFECYCLE_QOS_POLICY_ID: return "WRITERDATALIFECYCLE"; 40 | case DDS::READERDATALIFECYCLE_QOS_POLICY_ID: return "READERDATALIFECYCLE"; 41 | case DDS::TOPICDATA_QOS_POLICY_ID: return "TOPICDATA"; 42 | case DDS::GROUPDATA_QOS_POLICY_ID: return "GROUPDATA"; 43 | case DDS::TRANSPORTPRIORITY_QOS_POLICY_ID: return "TRANSPORTPRIORITY"; 44 | case DDS::LIFESPAN_QOS_POLICY_ID: return "LIFESPAN"; 45 | case DDS::DURABILITYSERVICE_QOS_POLICY_ID: return "DURABILITYSERVICE"; 46 | default: return "Unknown"; 47 | } 48 | } 49 | 50 | void StringSeq_push(DDS::StringSeq& string_seq, const char* elem) 51 | { 52 | const unsigned int i = string_seq.length(); 53 | string_seq.length(i + 1); 54 | string_seq[i] = elem; 55 | } 56 | 57 | template 58 | DDS::UInt32 DDS_UInt8Seq_get_length(const Seq* seq) 59 | { 60 | return seq->length(); 61 | } 62 | 63 | template 64 | void DDS_UInt8Seq_ensure_length(Seq* seq, DDS::UInt32 len, DDS::UInt32 = 0) 65 | { 66 | seq->length(len); 67 | } 68 | 69 | template 70 | DDS::UInt8* DDS_UInt8Seq_get_reference(Seq* seq, DDS::UInt32 idx) 71 | { 72 | return &(*seq)[idx]; 73 | } 74 | 75 | template 76 | const DDS::UInt8* DDS_UInt8Seq_get_reference(const Seq* seq, DDS::UInt32 idx) 77 | { 78 | return &(*seq)[idx]; 79 | } 80 | 81 | void configure_rtps() 82 | { 83 | using namespace OpenDDS::DCPS; 84 | using namespace OpenDDS::RTPS; 85 | TransportConfig_rch config = 86 | TransportRegistry::instance()->create_config("rtps_interop_demo"); 87 | TransportInst_rch inst = 88 | TransportRegistry::instance()->create_inst("rtps_transport","rtps_udp"); 89 | config->instances_.push_back(inst); 90 | TransportRegistry::instance()->global_config(config); 91 | 92 | RtpsDiscovery_rch disc = make_rch("RtpsDiscovery"); 93 | disc->use_xtypes(RtpsDiscoveryConfig::XTYPES_NONE); 94 | TheServiceParticipant->add_discovery(static_rchandle_cast(disc)); 95 | TheServiceParticipant->set_default_discovery(disc->key()); 96 | } 97 | -------------------------------------------------------------------------------- /doc/test_description.template.rst: -------------------------------------------------------------------------------- 1 | .. include:: vars.rst 2 | 3 | .. _section-test-descriptions: 4 | 5 | Test Descriptions 6 | ================= 7 | 8 | Default Values 9 | -------------- 10 | 11 | This section describes the different test performed. When the test description 12 | mentions 'default settings' or if the test does not mention any QoS modification, 13 | then, it refers to the default values for different QoS settings and other 14 | parameters the ShapeDemo Application configures: 15 | 16 | * **Domain ID**: 0 17 | * **RELIABILITY QoS**: reliable 18 | * **DURABILITY QoS**: volatile 19 | * **HISTORY QoS**: default middleware HISTORY kind (should be KEEP_LAST with depth 1) 20 | * **DATA_REPRESENTATION QoS**: XCDR1 21 | * **OWNERSHIP QoS**: shared 22 | * **PARTITION QoS**: default middleware partition 23 | * **DEADLINE QoS**: disabled 24 | * **TIME_BASED_FILTER QoS**: disabled 25 | * **Instance (color value)**: BLUE 26 | * **Topic name**: if not mentioned, the topic used is "Square" 27 | * **Writing period**: 33ms 28 | * **Reading period**: 100ms 29 | * **Delay when creating entities**: at least 1s 30 | 31 | The type used in these tests is the following: 32 | 33 | .. code-block:: 34 | 35 | @appendable 36 | struct ShapeType { 37 | @key 38 | string<128> color; 39 | int32 x; 40 | int32 y; 41 | int32 shapesize; 42 | }; 43 | 44 | Additionally, the test description may mention 'Publisher' and 'Subscriber', 45 | this refers to the publisher/subscriber applications. Qos policies are set 46 | to the corresponding entity: DomainParticipant, Publisher, Subscriber, Topic, 47 | DataWriter or DataReader. 48 | 49 | Considerations per Product 50 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | 52 | This section outlines important considerations for different products, including 53 | default values, features enabled or disabled, and unsupported features. 54 | 55 | Note that there is no version number because these changes apply to all 56 | product versions. 57 | 58 | 59 | * **Connext DDS**: 60 | 61 | * Content Filtered Topic expression created with single quotes around strings 62 | values 63 | * Content Filtered Topic uses MATCH operator for string comparisons. 64 | * Increased the periodic discovery announcements to 5s in the tests where 65 | the subscriber is OpenDDS and the publisher is Connext DDS. 66 | 67 | * **FastDDS**: 68 | 69 | * Content Filtered Topic expression created with single quotes around strings 70 | values 71 | 72 | * **InterCOM DDS**: 73 | 74 | * Content Filtered Topic expression created with single quotes around strings 75 | values 76 | 77 | * **OpenDDS**: 78 | 79 | * The commands used to build OpenDDS and the test can be found [here](https://github.com/OpenDDS/OpenDDS/blob/master/.github/workflows/dds-rtps.yml). None of the options used affect interoperability. See the [OpenDDS Developer's Guide](https://opendds.readthedocs.io/en/latest-release/devguide/introduction.html#building-and-configuring-for-interoperability) for additional information about interoperability. 80 | * OpenDDS specific configuration for the test can be found in [shape_configurator_opendds.h](https://github.com/omg-dds/dds-rtps/blob/master/srcCxx/shape_configurator_opendds.h). A brief description is: 81 | * Use RTPS as the default transport 82 | * Use RTPS as the default discovery mechanism 83 | * Disable XTypes Support 84 | * Content Filtered Topic expression created without single quotes around 85 | strings values 86 | 87 | * **CoreDX DDS**: 88 | 89 | * Content Filtered Topic expression created without single quotes around 90 | strings values 91 | * Disabled writer-side content filtering 92 | * DataReader `send_initial_nack` enabled that sends an initial NACK to every 93 | discovered DataWriter (only when using reliable RELIABILITY) 94 | * DataReader `precache_max_samples` set to 0 that sets to 0 the number of 95 | samples pre-cached (only when using reliable RELIABILITY) 96 | * Set environment variable `COREDX_UDP_RX_BUFFER_SIZE` to `65536` that 97 | increases the buffer sizes to that value 98 | 99 | * **Dust DDS**: 100 | 101 | * Content Filtered Topic disabled 102 | 103 | |TEST_DESCRIPTION| 104 | -------------------------------------------------------------------------------- /CLA/CLA_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: _YourCompanyName_ 49 | 50 | Address: _YourCompanyAddress_ 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: _YourName_ 57 | 58 | Title: _YourTitle_ 59 | 60 | Date: _Fill in the date_ 61 | 62 | -------------------------------------------------------------------------------- /CLA/CLA_Atostek.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: Atostek Oy 49 | 50 | Address: Hermiankatu 3 A, 33720 Tampere, Finland 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: Juhana Helovuo 57 | 58 | Title: Business Director 59 | 60 | Date: December 21, 2020 61 | 62 | -------------------------------------------------------------------------------- /CLA/CLA_ObjectComputing.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: Object Computing, Inc. 49 | 50 | Address: 12140 Woodcrest Exec. Dr., Ste 250, St. Louis, MO 63141 USA 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: Adam Mitz 57 | 58 | Title: Principal Software Engineer 59 | 60 | Date: February 20, 2017 61 | -------------------------------------------------------------------------------- /CLA/CLA_OpenDDSFoundation.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: OpenDDS Foundation 49 | 50 | Address: 12140 Woodcrest Exec. Dr., Ste 250, St. Louis, MO 63141 USA 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: Justin Wilson 57 | 58 | Title: Principal Software Engineer 59 | 60 | Date: February 27, 2024 61 | -------------------------------------------------------------------------------- /CLA/CLA_Real-Time_Innovations.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: _Real-Time Innovations, Inc._ 49 | 50 | Address: _232 E. Java Dr. Sunnyvale, CA 94089, USA_ 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: _Gerardo Pardo-Castellote_ 57 | 58 | Title: _CTO_ 59 | 60 | Date: _February 16th, 2017_ 61 | -------------------------------------------------------------------------------- /CLA/CLA_S2E_Software_Systems.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: S2E Software Systems B.V. 49 | 50 | Address: St. Jacobstraat 125, 3511 BP Utrecht, The Netherlands 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: Stefan Kimmer 57 | 58 | Title: Director 59 | 60 | Date: August 26, 2024 61 | 62 | -------------------------------------------------------------------------------- /CLA/CLA_TwinOaksComputing.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: _Twin Oaks Computing, Inc_ 49 | 50 | Address: _755 Maleta Ln Ste 203 / Castle Rock CO 80108_ 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: _Clark Tucker_ 57 | 58 | Title: _CEO, Twin Oaks Computing, Inc_ 59 | 60 | Date: _Feb 16, 2017_ 61 | 62 | -------------------------------------------------------------------------------- /CLA/CLA_eProsima.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: _Proyectos y Sistemas de Mantenimiento SL (eProsima)_ 49 | 50 | Address: _Plaza de la Encina 10 2A, 28760 Tres Cantos (Madrid), Spain_ 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: _Jaime Martin Losa_ 57 | 58 | Title: _CEO_ 59 | 60 | Date: _Jun 21st, 2023_ 61 | -------------------------------------------------------------------------------- /CLA/CLA_Kongsberg.md: -------------------------------------------------------------------------------- 1 | # OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT 2 | 3 | **This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** 4 | 5 | 1. Definitions 6 | 7 | 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). 8 | 9 | 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. 10 | 11 | 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. 12 | 13 | 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. 14 | 15 | 5. A "User" is anyone who accesses the Repository. 16 | 17 | 2. Allowable Contribution Representations 18 | 19 | 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. 20 | 21 | 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. 22 | 23 | 3. License 24 | 25 | You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. 26 | 27 | 4. No Warranty, Consequential Damages. Limited Liability 28 | 29 | Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. 30 | 31 | 5. General 32 | 33 | 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. 34 | 35 | 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. 36 | 37 | 6. Electronic Signatures 38 | 39 | "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. 40 | 41 | Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. 42 | 43 | 44 | IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. 45 | 46 | **For:** 47 | 48 | Entity Name: _Kongsberg Defence & Aerospace_ 49 | 50 | Address: _Kirkegårdsveien 45, P.O. Box 1003, NO-3601 Kongsberg, Norway_ 51 | 52 | ("**You**") 53 | 54 | **By:** 55 | 56 | Name: _Ørnulf Staff_ 57 | 58 | Title: _Senior Engineer_ 59 | 60 | Date: _March 20, 2024_ 61 | 62 | -------------------------------------------------------------------------------- /.github/workflows/ci_opendds.yml: -------------------------------------------------------------------------------- 1 | name: CI OpenDDS 2 | on: 3 | pull_request: 4 | push: 5 | schedule: 6 | - cron: '10 0 * * 0' 7 | workflow_dispatch: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | build: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | dds: 19 | - opendds 20 | runner: 21 | - ubuntu-24.04 22 | 23 | runs-on: ${{ matrix.runner }} 24 | 25 | steps: 26 | - name: 'Checkout dds-rtps' 27 | uses: actions/checkout@v4 28 | - name: 'Checkout MPC' 29 | uses: actions/checkout@v4 30 | with: 31 | repository: DOCGroup/MPC 32 | path: MPC 33 | fetch-depth: 1 34 | - name: 'Checkout ACE_TAO' 35 | uses: actions/checkout@v4 36 | with: 37 | repository: DOCGroup/ACE_TAO 38 | ref: ace6tao2 39 | path: ACE_TAO 40 | fetch-depth: 1 41 | - name: 'Checkout OpenDDS' 42 | uses: actions/checkout@v4 43 | with: 44 | repository: OpenDDS/OpenDDS 45 | ref: latest-release 46 | path: OpenDDS 47 | fetch-depth: 1 48 | submodules: true 49 | - name: 'Set environment variables' 50 | shell: bash 51 | run: |- 52 | echo "ACE_ROOT=$GITHUB_WORKSPACE/ACE_TAO/ACE" >> $GITHUB_ENV 53 | echo "TAO_ROOT=$GITHUB_WORKSPACE/ACE_TAO/TAO" >> $GITHUB_ENV 54 | echo "DDS_ROOT=$GITHUB_WORKSPACE/OpenDDS" >> $GITHUB_ENV 55 | echo "MPC_ROOT=$GITHUB_WORKSPACE/MPC" >> $GITHUB_ENV 56 | export COMPILER_VERSION=$(c++ --version 2>&1 | head -n 1) 57 | echo "COMPILER_VERSION=$COMPILER_VERSION" >> $GITHUB_ENV 58 | echo "OBJ_EXT=\\.o" >> $GITHUB_ENV 59 | cd ACE_TAO 60 | export ACE_COMMIT=$(git rev-parse HEAD) 61 | echo "ACE_COMMIT=$ACE_COMMIT" >> $GITHUB_ENV 62 | cd ../OpenDDS 63 | export DDS_COMMIT=$(git rev-parse HEAD) 64 | echo "DDS_COMMIT=$DDS_COMMIT" >> $GITHUB_ENV 65 | export MATRIX_MD5=$(echo "${{ matrix }}" | md5sum | cut -d ' ' -f 1) 66 | echo "MATRIX_MD5=$MATRIX_MD5" >> $GITHUB_ENV 67 | export COMPILER_MD5=$(echo "$COMPILER_VERSION" | md5sum | cut -d ' ' -f 1) 68 | echo "COMPILER_MD5=$COMPILER_MD5" >> $GITHUB_ENV 69 | export CONFIG_OPTIONS="--optimize --no-debug --static --no-inline" 70 | echo "CONFIG_OPTIONS=$CONFIG_OPTIONS" >> $GITHUB_ENV 71 | export CONFIG_MD5=$(echo "$CONFIG_OPTIONS" | md5sum | cut -d ' ' -f 1) 72 | echo "CONFIG_MD5=$CONFIG_MD5" >> $GITHUB_ENV 73 | - name: 'Check Build Cache' 74 | id: cache-build 75 | uses: actions/cache@v4 76 | with: 77 | path: ${{ env.MATRIX_MD5 }}.tar.xz 78 | key: c01_${{ env.MATRIX_MD5 }}_${{ env.COMPILER_MD5 }}_${{ env.ACE_COMMIT }}_${{ env.DDS_COMMIT }}_${{ env.CONFIG_MD5 }} 79 | - name: 'Extract Build Cache' 80 | if: steps.cache-build.outputs.cache-hit == 'true' 81 | shell: bash 82 | run: | 83 | tar xvfJ ${{ env.MATRIX_MD5 }}.tar.xz 84 | - name: 'Configure OpenDDS' 85 | if: steps.cache-build.outputs.cache-hit != 'true' 86 | shell: bash 87 | run: |- 88 | cd OpenDDS 89 | ./configure ${{ env.CONFIG_OPTIONS }} 90 | tools/scripts/show_build_config.pl 91 | - name: 'Build OpenDDS' 92 | if: steps.cache-build.outputs.cache-hit != 'true' 93 | shell: bash 94 | run: |- 95 | cd OpenDDS 96 | . setenv.sh 97 | make -j3 OpenDDS_Rtps_Udp 98 | - name: 'Create Build Cache' 99 | if: steps.cache-build.outputs.cache-hit != 'true' 100 | shell: bash 101 | run: | 102 | cd ACE_TAO 103 | find . -iname "*$OBJ_EXT" | xargs rm 104 | git clean -xdn | cut -d ' ' -f 3- | sed 's/^/ACE_TAO\//g' | tee ../ACE_TAO_files.txt 105 | cd .. 106 | tar cvf ${{ env.MATRIX_MD5 }}.tar ACE_TAO/ACE/ace/config.h 107 | cat ACE_TAO_files.txt | xargs tar uvf ${{ env.MATRIX_MD5 }}.tar 108 | cd OpenDDS 109 | find . -iname "*$OBJ_EXT" | xargs rm 110 | git clean -xdn | cut -d ' ' -f 3- | sed 's/^/OpenDDS\//g' | tee ../OpenDDS_files.txt 111 | cd .. 112 | cat OpenDDS_files.txt | xargs tar uvf ${{ env.MATRIX_MD5 }}.tar 113 | xz -3 ${{ env.MATRIX_MD5 }}.tar 114 | - name: 'Set Up Problem Matcher' 115 | uses: ammaraskar/gcc-problem-matcher@0.3.0 116 | - name: 'Build Application' 117 | shell: bash 118 | run: |- 119 | cmake -G Ninja -S srcCxx/opendds-cmake -B build -D OpenDDS_ROOT=OpenDDS 120 | cmake --build build 121 | -------------------------------------------------------------------------------- /get_latest_file_urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ################################################################# 3 | # Use and redistribution is source and binary forms is permitted 4 | # subject to the OMG-DDS INTEROPERABILITY TESTING LICENSE found 5 | # at the following URL: 6 | # 7 | # https://github.com/omg-dds/dds-rtps/blob/master/LICENSE.md 8 | # 9 | ################################################################# 10 | 11 | import os 12 | import sys 13 | import json 14 | from google.oauth2 import service_account 15 | from googleapiclient.discovery import build 16 | 17 | 18 | class GoogleDriveClient: 19 | def __init__(self): 20 | # Load Google Drive credentials from environment variable 21 | self.credentials_str = os.getenv('GCP_CREDENTIAL_STR') 22 | 23 | # Load folder ID from environment variable 24 | self.folder_id = os.getenv('DRIVE_FOLDER_ID') 25 | 26 | # Create credentials object 27 | self.credentials = service_account.Credentials.from_service_account_info( 28 | json.loads(self.credentials_str), 29 | scopes=['https://www.googleapis.com/auth/drive'] 30 | ) 31 | 32 | # Create Google Drive service 33 | self.drive_service = build('drive', 'v3', credentials=self.credentials) 34 | 35 | 36 | def get_latest_files_url(self): 37 | # List to store XLSX files 38 | xlsx_files, zip_files = self.get_subfolder_files(self.folder_id) 39 | 40 | # Find the latest XLSX and ZIP files URL 41 | xlsx_url = None 42 | zip_url = None 43 | if xlsx_files: 44 | # Find the latest XLSX file based on modification time 45 | latest_file = max(xlsx_files, key=lambda x: x['modifiedTime']) 46 | xlsx_url = latest_file.get('webViewLink') 47 | if zip_files: 48 | # Find the latest zip file based on modification time 49 | latest_file = max(zip_files, key=lambda x: x['modifiedTime']) 50 | zip_url = latest_file.get('webViewLink') 51 | 52 | return xlsx_url, zip_url 53 | 54 | def get_subfolder_files(self, folder_id): 55 | page_token = None 56 | 57 | # Retrieve all files and folders within the subfolder 58 | while True: 59 | response = self.drive_service.files().list( 60 | q=f"'{folder_id}' in parents", 61 | includeItemsFromAllDrives=True, 62 | supportsAllDrives=True, 63 | fields='nextPageToken, files(id, name, webViewLink, mimeType, modifiedTime)', 64 | pageToken=page_token 65 | ).execute() 66 | 67 | # Extract files and folders from response 68 | items = response.get('files', []) 69 | 70 | # Check if there are more pages of results 71 | page_token = response.get('nextPageToken') 72 | if not page_token: 73 | break 74 | 75 | # List to store XLSX or ZIP files within subfolder 76 | xlsx_files = [] 77 | zip_files = [] 78 | 79 | # Iterate through files and folders 80 | for item in items: 81 | # Check if current item is a folder 82 | if item['mimeType'] == 'application/vnd.google-apps.folder': 83 | # Recursively search for XLSX files within sub-subfolder 84 | subfolder_xlsx_files, subfolder_zip_files = self.get_subfolder_files(item['id']) 85 | if subfolder_xlsx_files: 86 | xlsx_files.extend(subfolder_xlsx_files) 87 | if subfolder_zip_files: 88 | zip_files.extend(subfolder_zip_files) 89 | # Check if current item is an XLSX file 90 | elif item['mimeType'] == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 91 | # Add XLSX file to list 92 | xlsx_files.append(item) 93 | elif item['mimeType'] == 'application/zip': 94 | # Add ZIP file to list 95 | zip_files.append(item) 96 | 97 | # Return list of XLSX files within subfolder 98 | return xlsx_files, zip_files 99 | 100 | def main(): 101 | """This requires a filename to save the URL of the XLSX and ZIP files""" 102 | # Check if the file name is provided as a command-line argument 103 | if len(sys.argv) < 2: 104 | print("Usage: python get_latest_files.py ") 105 | sys.exit(1) 106 | 107 | # Get the file name from the command-line arguments 108 | file_name = sys.argv[1] 109 | 110 | if not file_name.endswith('.py'): 111 | print("Error: File must have .py extension") 112 | sys.exit(1) 113 | 114 | client = GoogleDriveClient() 115 | 116 | xlsx_file_url, zip_file_url = client.get_latest_files_url() 117 | 118 | with open(file_name, 'w') as file: 119 | if xlsx_file_url is not None: 120 | file.write(f'xlsx_url = \'{xlsx_file_url}\'\n') 121 | if zip_file_url is not None: 122 | file.write(f'zip_url = \'{zip_file_url}\'\n') 123 | 124 | if __name__ == '__main__': 125 | main() 126 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # DDS Interoperability Tests documentation build configuration file, created by 4 | # sphinx-quickstart 5 | # This file is execfile()d with the current directory set to its 6 | # containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | # If extensions (or modules to document with autodoc) are in another directory, 15 | # add these directories to sys.path here. If the directory is relative to the 16 | # documentation root, use os.path.abspath to make it absolute, like shown here. 17 | # 18 | import os 19 | import sys 20 | import glob 21 | import re 22 | # sys.path.insert(0, os.path.abspath('.')) 23 | import sphinx_rtd_theme 24 | 25 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) 26 | 27 | from gdrive_url import xlsx_url, zip_url 28 | import test_suite 29 | 30 | 31 | def find_index_html(): 32 | # Get the directory of the script 33 | script_directory = os.path.dirname(os.path.abspath(__file__)) 34 | 35 | # Define the pattern to search for 36 | pattern = os.path.join(script_directory, 37 | '_static/html/interoperability_report_*.html') 38 | 39 | # Use glob to find files matching the pattern 40 | matching_files = glob.glob(pattern) 41 | 42 | # Return the first matching file, if any 43 | if matching_files: 44 | return os.path.relpath(matching_files[0], script_directory) 45 | return None 46 | 47 | def generate_test_description_rst(): 48 | last_test_group = '' 49 | test_description_rst = '' 50 | 51 | for test_name, test_value in test_suite.rtps_test_suite_1.items(): 52 | current_test_group = re.search(r'Test_(.*?)_\d+', test_name).group(1) 53 | 54 | # write new group heading 55 | if last_test_group != current_test_group: 56 | test_description_rst += f'{current_test_group}\n' 57 | test_description_rst += '-' * len(current_test_group) + '\n\n' 58 | last_test_group = current_test_group 59 | 60 | # write test name heading 61 | test_description_rst += f'{test_name}\n' 62 | test_description_rst += '~' * len(test_name) + '\n\n' 63 | 64 | # write test name and description 65 | test_description_rst += f"{test_value['title']}\n\n" 66 | test_description_rst += f"{test_value['description']}\n" 67 | 68 | return test_description_rst 69 | 70 | # replacement is defined as 71 | # replacements = { 72 | # '|VARIABLE_NAME|': 'replacement_value', 73 | # # Add more replacements as needed 74 | # } 75 | 76 | def replace_in_rst_files(replacements): 77 | # Get the directory of the script 78 | directory = os.path.dirname(os.path.abspath(__file__)) 79 | 80 | # Get a list of all .template.rst files in the directory 81 | template_files = [f for f in os.listdir(directory) if f.endswith('.template.rst')] 82 | 83 | for template_file in template_files: 84 | # Construct paths for template and output files 85 | template_file_path = os.path.join(directory, template_file) 86 | output_file_path = os.path.join(directory, template_file.replace('.template.rst', '.rst')) 87 | 88 | # Read the content of the template file 89 | with open(template_file_path, 'r') as file: 90 | content = file.read() 91 | 92 | # Perform replacements in the content 93 | for target, replacement in replacements.items(): 94 | content = content.replace(target, replacement) 95 | 96 | # Write the modified content to the output file 97 | with open(output_file_path, 'w') as file: 98 | file.write(content) 99 | 100 | # -- General configuration ------------------------------------------------ 101 | 102 | # If your documentation needs a minimal Sphinx version, state it here. 103 | # 104 | # needs_sphinx = '1.0' 105 | 106 | # Add any Sphinx extension module names here, as strings. They can be 107 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 108 | # ones. 109 | extensions = ['sphinx.ext.imgmath', 110 | 'sphinx.ext.extlinks', 111 | 'sphinx.ext.imgconverter',] 112 | 113 | # Add any paths that contain templates here, relative to this directory. 114 | # templates_path = ['_templates'] 115 | 116 | # The suffix(es) of source filenames. 117 | # You can specify multiple suffix as a list of string: 118 | # 119 | # source_suffix = ['.rst', '.md'] 120 | source_suffix = '.rst' 121 | 122 | # The master toctree document. 123 | master_doc = 'index' 124 | 125 | # General information about the project. 126 | project = 'DDS Interoperability Tests' 127 | html_show_sphinx = False 128 | html_show_copyright = False 129 | 130 | # The version info for the project you're documenting, acts as replacement for 131 | # |version| and |release|, also used in various other places throughout the 132 | # built documents. 133 | # 134 | # The full version, including alpha/beta/rc tags. 135 | release = 'version 1.1 (2024)' 136 | version = release 137 | 138 | # The language for content autogenerated by Sphinx. Refer to documentation 139 | # for a list of supported languages. 140 | # 141 | # This is also used if you do content translation via gettext catalogs. 142 | # Usually you set "language" from the command line for these cases. 143 | language = "en" 144 | 145 | # List of patterns, relative to source directory, that match files and 146 | # directories to ignore when looking for source files. 147 | # This patterns also effect to html_static_path and html_extra_path 148 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '*.template.rst'] 149 | 150 | # The name of the Pygments (syntax highlighting) style to use. 151 | pygments_style = 'sphinx' 152 | 153 | # If true, `todo` and `todoList` produce output, else they produce nothing. 154 | todo_include_todos = False 155 | 156 | numfig = True 157 | numfig_format = {'figure': 'Figure %s', 158 | 'table': 'Table %s', 159 | 'code-block': 'Listing %s', 160 | 'section': 'Section %s'} 161 | 162 | # -- Options for HTML output ---------------------------------------------- 163 | 164 | # The theme to use for HTML and HTML Help pages. See the documentation for 165 | # a list of builtin themes. 166 | # 167 | html_theme = "sphinx_rtd_theme" 168 | # Override default css to get a larger width for local build 169 | 170 | def setup(app): 171 | app.add_css_file('css/custom.css') 172 | #app.add_javascript('js/custom.js') 173 | # Theme options are theme-specific and customize the look and feel of a theme 174 | # further. For a list of options available for each theme, see the 175 | # documentation. 176 | # 177 | # html_theme_options = {} 178 | html_logo = "_static/img/DDS-logo-nobg.png" 179 | html_favicon = "_static/img/favicon.ico" 180 | html_css_files = ['css/custom.css'] 181 | html_js_files = ['js/custom.js'] 182 | 183 | # Add any paths that contain custom static files (such as style sheets) here, 184 | # relative to this directory. They are copied after the builtin static files, 185 | # so a file named "default.css" will overwrite the builtin "default.css". 186 | html_static_path = ['_static'] 187 | 188 | # Custom sidebar templates, must be a dictionary that maps document names 189 | # to template names. 190 | # 191 | # This is required for the alabaster theme 192 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 193 | html_sidebars = { 194 | '**': [ 195 | 'relations.html', # needs 'show_related': True theme option to display 196 | 'searchbox.html', 197 | ] 198 | } 199 | 200 | 201 | # Add test description 202 | TEST_DESCRIPTION = generate_test_description_rst() 203 | 204 | # -- links 205 | LINK_XLSX_URL = xlsx_url 206 | LINK_ZIP_URL = zip_url 207 | INDEX_HTML_PATH = find_index_html() 208 | if INDEX_HTML_PATH is None: 209 | print ('Error getting INDEX_HTML_PATH') 210 | exit(1) 211 | 212 | replacements = { 213 | '|LINK_XLSX_URL|': LINK_XLSX_URL, 214 | '|INDEX_HTML_PATH|': INDEX_HTML_PATH, 215 | '|TEST_DESCRIPTION|': TEST_DESCRIPTION, 216 | # Add more replacements as needed 217 | } 218 | replace_in_rst_files(replacements) 219 | 220 | rst_epilog = """ 221 | .. |LINK_ZIP_URL| replace:: {zip_url} 222 | """.format( 223 | zip_url = LINK_ZIP_URL, 224 | ) 225 | 226 | # -- Options for HTMLHelp output ------------------------------------------ 227 | 228 | # Output file base name for HTML help builder. 229 | htmlhelp_basename = 'DDS_Interoperability_Tests' 230 | 231 | -------------------------------------------------------------------------------- /RustDDS/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Interoperability test program for `RustDDS` library 2 | 3 | #![deny(clippy::all)] 4 | #![warn(clippy::pedantic)] 5 | 6 | use log::{debug,trace,error,LevelFilter}; 7 | use log4rs::{Config, config::Appender, config::Root, append::console::ConsoleAppender}; 8 | 9 | use rustdds::dds::DomainParticipant; 10 | use rustdds::dds::qos::QosPolicyBuilder; 11 | use rustdds::dds::qos::policy::{ Reliability, Durability, History, Deadline }; 12 | use rustdds::dds::data_types::DDSDuration; 13 | use rustdds::dds::data_types::TopicKind; 14 | use rustdds::dds::traits::TopicDescription; 15 | use rustdds::dds::traits::Keyed; 16 | use rustdds::dds::statusevents::StatusEvented; 17 | use serde::{Serialize, Deserialize}; 18 | 19 | use clap::{App, Arg, ArgMatches}; // command line argument processing 20 | 21 | use mio::{Events, Poll, PollOpt, Ready, Token}; // polling 22 | use mio_extras::channel; // pollable channel 23 | 24 | 25 | use std::io; 26 | 27 | use rand::prelude::*; 28 | 29 | use std::time::{Duration,Instant}; 30 | 31 | #[derive(Serialize,Deserialize,Clone)] 32 | struct Shape { 33 | color: String, 34 | x: i32, 35 | y: i32, 36 | shapesize: i32, 37 | } 38 | 39 | impl Keyed for Shape { 40 | type K = String; 41 | fn key(&self) -> String { 42 | self.color.clone() 43 | } 44 | } 45 | 46 | const DA_WIDTH: i32 = 240; 47 | const DA_HEIGHT: i32 = 270; 48 | 49 | const STOP_PROGRAM: Token = Token(0); 50 | const READER_READY: Token = Token(1); 51 | const READER_STATUS_READY: Token = Token(2); 52 | const WRITER_STATUS_READY: Token = Token(3); 53 | 54 | #[allow(clippy::too_many_lines)] 55 | fn main() { 56 | configure_logging(); 57 | let matches = get_matches(); 58 | 59 | // Process command line arguments 60 | let topic_name = matches.value_of("topic").unwrap_or("Square"); 61 | let domain_id = matches.value_of("domain_id") 62 | .unwrap_or("0") 63 | .parse::() 64 | .unwrap_or(0); 65 | let color = matches.value_of("color").unwrap_or("BLUE"); 66 | 67 | let domain_participant = DomainParticipant::new(domain_id) 68 | .unwrap_or_else(|e| panic!("DomainParticipant construction failed: {:?}",e)); 69 | 70 | let mut qos_b = QosPolicyBuilder::new() 71 | .reliability( 72 | if matches.is_present("reliable") { 73 | Reliability::Reliable { max_blocking_time: DDSDuration::DURATION_ZERO } 74 | } else { 75 | Reliability::BestEffort 76 | } 77 | ) 78 | .durability( 79 | match matches.value_of("durability") { 80 | Some("l") => Durability::TransientLocal, 81 | Some("t") => Durability::Transient, 82 | Some("p") => Durability::Persistent, 83 | _ => Durability::Volatile, 84 | } 85 | ) 86 | .history( 87 | match matches.value_of("history_depth").map( str::parse ) { 88 | None | 89 | Some(Err(_)) => History::KeepAll, 90 | Some(Ok(d)) => 91 | if d < 0 { History::KeepAll } else { History::KeepLast{ depth: d } }, 92 | 93 | } 94 | ); 95 | let deadline_policy = 96 | match matches.value_of("deadline") { 97 | None => None, 98 | Some(dl) => 99 | match dl.parse::() { 100 | Ok(d) => Some(Deadline(DDSDuration::from_frac_seconds(d))), 101 | Err(e) => panic!("Expected numeric value for deadline. {:?}",e), 102 | }, 103 | }; 104 | 105 | if let Some(dl) = deadline_policy { 106 | qos_b = qos_b.deadline(dl); 107 | } 108 | 109 | assert!(!matches.is_present("partition"), "QoS policy Partition is not yet implemented."); 110 | 111 | assert!(!matches.is_present("interval"), "QoS policy Time Based Filter is not yet implemented."); 112 | 113 | assert!(!matches.is_present("ownership_strength"), "QoS policy Ownership Strength is not yet implemented."); 114 | 115 | let qos = qos_b.build(); 116 | 117 | let loop_delay : Duration = 118 | match deadline_policy { 119 | None => Duration::from_millis(200), // This is the default rate 120 | Some(Deadline(dd)) => 121 | Duration::from(dd) 122 | .mul_f32(0.8), // slightly faster than dealine 123 | }; 124 | 125 | let topic = domain_participant 126 | .create_topic(topic_name.to_string(), "ShapeType".to_string(), &qos, TopicKind::WithKey) 127 | .unwrap_or_else(|e| panic!("create_topic failed: {:?}",e)); 128 | println!("Topic name is {}. Type is {}.", topic.name(), topic.get_type().name()); 129 | 130 | // Set Ctrl-C handler 131 | let (stop_sender,stop_receiver) = channel::channel(); 132 | ctrlc::set_handler(move || { 133 | stop_sender.send( () ).unwrap_or( () ); 134 | // ignore errors, as we are quitting anyway 135 | }).expect("Error setting Ctrl-C handler"); 136 | println!("Press Ctrl-C to quit."); 137 | 138 | let poll = Poll::new().unwrap(); 139 | let mut events = Events::with_capacity(4); 140 | 141 | poll.register(&stop_receiver, STOP_PROGRAM, Ready::readable(),PollOpt::edge()) 142 | .unwrap(); 143 | 144 | let is_publisher = matches.is_present("publisher"); 145 | let is_subscriber = matches.is_present("subscriber"); 146 | 147 | let mut writer_opt = 148 | if is_publisher { 149 | debug!("Publisher"); 150 | let publisher = domain_participant.create_publisher(&qos).unwrap(); 151 | let mut writer = publisher 152 | .create_datawriter_cdr::( topic.clone(), None) // None = get qos policy from publisher 153 | .unwrap(); 154 | poll.register(writer.as_status_evented(), WRITER_STATUS_READY, Ready::readable(), PollOpt::edge()) 155 | .unwrap(); 156 | Some(writer) 157 | } else { None }; 158 | 159 | let mut reader_opt = 160 | if is_subscriber { 161 | debug!("Subscriber"); 162 | let subscriber = domain_participant.create_subscriber(&qos).unwrap(); 163 | let mut reader = subscriber 164 | .create_datareader_cdr::( topic.clone(), Some(qos) ) 165 | .unwrap(); 166 | poll.register(&reader, READER_READY, Ready::readable(),PollOpt::edge()) 167 | .unwrap(); 168 | poll.register(reader.as_status_evented(), READER_STATUS_READY, Ready::readable(), PollOpt::edge()) 169 | .unwrap(); 170 | debug!("Created DataReader"); 171 | Some(reader) 172 | } else { None }; 173 | 174 | let mut shape_sample = Shape { color: color.to_string(), x: 0, y: 0, shapesize: 21 }; 175 | let mut random_gen = thread_rng(); 176 | // a bit complicated lottery to ensure we do not end up with zero velocity. 177 | let mut x_vel = if random() { random_gen.gen_range(1..5) } else { random_gen.gen_range(-5..-1) }; 178 | let mut y_vel = if random() { random_gen.gen_range(1..5) } else { random_gen.gen_range(-5..-1) }; 179 | 180 | let mut last_write = Instant::now(); 181 | 182 | loop { 183 | poll 184 | .poll(&mut events, Some(loop_delay)) 185 | .unwrap(); 186 | for event in &events { 187 | match event.token() { 188 | STOP_PROGRAM => { 189 | if stop_receiver.try_recv().is_ok() { 190 | println!("Done."); 191 | return 192 | } 193 | } 194 | READER_READY => { 195 | match reader_opt { 196 | Some(ref mut reader) => { 197 | loop { 198 | trace!("DataReader triggered"); 199 | match reader.take_next_sample() { 200 | Ok(Some(sample)) => 201 | match sample.into_value() { 202 | Ok(sample) => 203 | println!("{:10.10} {:10.10} {:3.3} {:3.3} [{}]", 204 | topic.name(), 205 | sample.color, 206 | sample.x, 207 | sample.y, 208 | sample.shapesize, 209 | ), 210 | Err(key) => 211 | println!("Disposed key {:?}", key), 212 | }, 213 | Ok(None) => break, // no more data 214 | Err(e) => println!("DataReader error {:?}", e), 215 | } // match 216 | } 217 | } 218 | None => { error!("Where is my reader?"); } 219 | } 220 | } 221 | READER_STATUS_READY => { 222 | match reader_opt { 223 | Some(ref mut reader) => { 224 | while let Some(status) = reader.try_recv_status() { 225 | println!("DataReader status: {:?}", status); 226 | } 227 | } 228 | None => { error!("Where is my reader?"); } 229 | } 230 | } 231 | 232 | WRITER_STATUS_READY => { 233 | match writer_opt { 234 | Some(ref mut writer) => { 235 | while let Some(status) = writer.try_recv_status() { 236 | println!("DataWriter status: {:?}", status); 237 | } 238 | } 239 | None => { error!("Where is my writer?"); } 240 | } 241 | } 242 | other_token => { 243 | println!("Polled event is {:?}. WTF?", other_token); 244 | } 245 | } 246 | } 247 | 248 | let r = move_shape(shape_sample,x_vel,y_vel); 249 | shape_sample = r.0; 250 | x_vel = r.1; 251 | y_vel = r.2; 252 | 253 | // write to DDS 254 | trace!("Writing shape color {}", &color); 255 | match writer_opt { 256 | Some(ref mut writer) => { 257 | let now = Instant::now(); 258 | if last_write + loop_delay < now { 259 | writer.write( shape_sample.clone() , None) 260 | .unwrap_or_else(|e| error!("DataWriter write failed: {:?}",e)); 261 | last_write = now; 262 | } 263 | } 264 | None => { 265 | if is_publisher { 266 | error!("Where is my writer?"); 267 | } else { /* never mind */ } 268 | } 269 | } 270 | 271 | } // loop 272 | } 273 | 274 | fn configure_logging() { 275 | // initialize logging, preferably from config file 276 | log4rs::init_file("logging-config.yaml", log4rs::config::Deserializers::default()) 277 | .unwrap_or_else( |e| { 278 | match e.downcast_ref::() { 279 | // Config file did not work. If it is a simple "No such file or directory", then 280 | // substitute some default config. 281 | Some(os_err) if os_err.kind() == io::ErrorKind::NotFound => { 282 | println!("No config file."); 283 | let stdout = ConsoleAppender::builder().build(); 284 | let conf = Config::builder() 285 | .appender(Appender::builder().build("stdout", Box::new(stdout))) 286 | .build(Root::builder().appender("stdout").build(LevelFilter::Error)) 287 | .unwrap(); 288 | log4rs::init_config(conf).unwrap(); 289 | } 290 | // Give up. 291 | other_error => panic!("Config problem: {:?}",other_error), 292 | } 293 | }); 294 | } 295 | 296 | fn get_matches() -> ArgMatches<'static> { 297 | App::new("RustDDS-interop") 298 | .version("0.2.2") 299 | .author("Juhana Helovuo ") 300 | .about("Command-line \"shapes\" interoperability test.") 301 | .arg(Arg::with_name("domain_id") 302 | .short("d") 303 | .value_name("id") 304 | .help("Sets the DDS domain id number") 305 | .takes_value(true)) 306 | .arg(Arg::with_name("topic") 307 | .short("t") 308 | .value_name("name") 309 | .help("Sets the topic name") 310 | .takes_value(true) 311 | .required(true)) 312 | .arg(Arg::with_name("color") 313 | .short("c") 314 | .value_name("color") 315 | .help("Color to publish (or filter)") 316 | .takes_value(true)) 317 | .arg(Arg::with_name("durability") 318 | .short("D") 319 | .value_name("durability") 320 | .help("Set durability") 321 | .takes_value(true) 322 | .possible_values(&["v","l", "t","p"])) 323 | .arg(Arg::with_name("publisher") 324 | .help("Act as publisher") 325 | .short("P") 326 | .required_unless("subscriber")) 327 | .arg(Arg::with_name("subscriber") 328 | .help("Act as subscriber") 329 | .short("S") 330 | .required_unless("publisher")) 331 | .arg(Arg::with_name("best_effort") 332 | .help("BEST_EFFORT reliability") 333 | .short("b") 334 | .conflicts_with("reliable")) 335 | .arg(Arg::with_name("reliable") 336 | .help("RELIABLE reliability") 337 | .short("r") 338 | .conflicts_with("best_effort")) 339 | .arg(Arg::with_name("history_depth") 340 | .help("Keep history depth") 341 | .short("k") 342 | .takes_value(true) 343 | .value_name("depth")) 344 | .arg(Arg::with_name("deadline") 345 | .help("Set a 'deadline' with interval (seconds)") 346 | .short("f") 347 | .takes_value(true) 348 | .value_name("interval")) 349 | .arg(Arg::with_name("partition") 350 | .help("Set a 'partition' string") 351 | .short("p") 352 | .takes_value(true) 353 | .value_name("partition")) 354 | .arg(Arg::with_name("interval") 355 | .help("Apply 'time based filter' with interval (seconds)") 356 | .short("i") 357 | .takes_value(true) 358 | .value_name("interval")) 359 | .arg(Arg::with_name("ownership_strength") 360 | .help("Set ownership strength [-1: SHARED]") 361 | .short("s") 362 | .takes_value(true) 363 | .value_name("strength")) 364 | .get_matches() 365 | } 366 | 367 | #[allow(clippy::similar_names)] 368 | fn move_shape(shape:Shape, xv:i32, yv:i32) -> (Shape,i32,i32) { 369 | let half_size = shape.shapesize/2 + 1; 370 | let mut x = shape.x + xv; 371 | let mut y = shape.y + yv; 372 | 373 | let mut xv_new = xv; 374 | let mut yv_new = yv; 375 | 376 | if x < half_size { 377 | x = half_size; 378 | xv_new = -xv; 379 | } 380 | if x > DA_WIDTH - half_size { 381 | x = DA_WIDTH - half_size; 382 | xv_new = -xv; 383 | } 384 | if y < half_size { 385 | y = half_size; 386 | yv_new = -yv; 387 | } 388 | if y > DA_HEIGHT - half_size { 389 | y = DA_HEIGHT - half_size; 390 | yv_new = -yv; 391 | } 392 | ( Shape { color: shape.color, x, y, shapesize: shape.shapesize } , xv_new , yv_new) 393 | } -------------------------------------------------------------------------------- /.github/workflows/1_run_interoperability_tests.yml: -------------------------------------------------------------------------------- 1 | name: 1 - Run Interoperability Tests 2 | run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 3 | env: 4 | # comma separated list of tests to skip 5 | SKIP_EXEC: "connext_dds-6.1.2_shape_main_linux" 6 | on: workflow_dispatch 7 | jobs: 8 | generate_timestamp: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Generate timestamp file 12 | run: date '+%Y-%m-%d-%H_%M_%S' > timestamp 13 | - name: Attach the report 14 | if: always() 15 | uses: actions/upload-artifact@v4 16 | with: 17 | name: timestamp 18 | path: | 19 | ./timestamp 20 | connext_dds: 21 | runs-on: ubuntu-latest 22 | needs: generate_timestamp 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | - uses: actions/setup-python@v5 27 | with: 28 | python-version: '3.11.4' 29 | - name: Download artifact 30 | uses: actions/download-artifact@v4 31 | with: 32 | name: timestamp 33 | - name: Downloads assets 34 | uses: robinraju/release-downloader@v1.10 35 | with: 36 | latest: true 37 | fileName: "*" 38 | - name: Skip tests 39 | run: | 40 | echo "Skipping the following tests: $SKIP_EXEC" 41 | clean_list="${SKIP_EXEC//[[:space:]]/}" 42 | for name in ${clean_list//,/ }; do 43 | rm -f "$name.zip" 44 | done 45 | - name: Unzip 46 | run: unzip '*.zip' -d executables 47 | - name: Setting up environment 48 | run: | 49 | python3 -m venv .venv 50 | source .venv/bin/activate 51 | pip install -r requirements.txt 52 | - name: Run Interoperability script 53 | # The test descriptions used are the generated for the last execution. 54 | # This shouldn't be an issue because all test are run always 55 | run: | 56 | source .venv/bin/activate 57 | cd executables 58 | for publisher in connext_dds-* ; do \ 59 | if [ -e "$publisher" ]; then \ 60 | for subscriber in * ; do \ 61 | extra_args=""; \ 62 | if [[ "${subscriber,,}" == *opendds* ]]; then \ 63 | extra_args="--periodic-announcement 5000"; \ 64 | fi; \ 65 | echo "Testing Publisher $publisher --- Subscriber $subscriber"; \ 66 | python3 ./../interoperability_report.py -P ./$publisher -S ./$subscriber -o=./../junit_interoperability_report.xml $extra_args; \ 67 | if [ -d "./OpenDDS-durable-data-dir" ]; then \ 68 | echo Deleting OpenDDS-durable-data-dir; \ 69 | rm -rf ./OpenDDS-durable-data-dir; \ 70 | fi; \ 71 | done \ 72 | fi; \ 73 | done 74 | - name: Attach the report 75 | if: always() 76 | uses: actions/upload-artifact@v4 77 | with: 78 | name: interoperability_report_connext_dds 79 | path: | 80 | ./junit_interoperability_report.xml 81 | ./timestamp 82 | dust_dds: 83 | runs-on: ubuntu-latest 84 | needs: connext_dds 85 | steps: 86 | - name: Checkout 87 | uses: actions/checkout@v4 88 | - name: Download artifact 89 | uses: actions/download-artifact@v4 90 | with: 91 | name: interoperability_report_connext_dds 92 | - uses: actions/setup-python@v5 93 | with: 94 | python-version: '3.11.4' 95 | - name: Downloads assets 96 | uses: robinraju/release-downloader@v1.10 97 | with: 98 | latest: true 99 | fileName: "*" 100 | - name: Skip tests 101 | run: | 102 | echo "Skipping the following tests: $SKIP_EXEC" 103 | clean_list="${SKIP_EXEC//[[:space:]]/}" 104 | for name in ${clean_list//,/ }; do 105 | rm -f "$name.zip" 106 | done 107 | - name: Unzip 108 | run: unzip '*.zip' -d executables 109 | - name: Setting up environment 110 | run: | 111 | python3 -m venv .venv 112 | source .venv/bin/activate 113 | pip install -r requirements.txt 114 | - name: Run Interoperability script 115 | # The test descriptions used are the generated for the last execution. 116 | # This shouldn't be an issue because all test are run always 117 | run: | 118 | source .venv/bin/activate 119 | cd executables 120 | for publisher in dust_dds-* ; do \ 121 | if [ -e "$publisher" ]; then \ 122 | for subscriber in * ; do \ 123 | echo "Testing Publisher $publisher --- Subscriber $subscriber"; \ 124 | python3 ./../interoperability_report.py -P ./$publisher -S ./$subscriber -o=./../junit_interoperability_report.xml; \ 125 | if [ -d "./OpenDDS-durable-data-dir" ]; then \ 126 | echo Deleting OpenDDS-durable-data-dir; \ 127 | rm -rf ./OpenDDS-durable-data-dir; \ 128 | fi; \ 129 | done \ 130 | fi; \ 131 | done 132 | - name: Attach the report 133 | if: always() 134 | uses: actions/upload-artifact@v4 135 | with: 136 | name: interoperability_report_dust_dds 137 | path: | 138 | ./junit_interoperability_report.xml 139 | ./timestamp 140 | eprosima_fastdds: 141 | runs-on: ubuntu-latest 142 | needs: dust_dds 143 | steps: 144 | - name: Checkout 145 | uses: actions/checkout@v4 146 | - name: Download artifact 147 | uses: actions/download-artifact@v4 148 | with: 149 | name: interoperability_report_dust_dds 150 | - uses: actions/setup-python@v5 151 | with: 152 | python-version: '3.11.4' 153 | - name: Downloads assets 154 | uses: robinraju/release-downloader@v1.10 155 | with: 156 | latest: true 157 | fileName: "*" 158 | - name: Skip tests 159 | run: | 160 | echo "Skipping the following tests: $SKIP_EXEC" 161 | clean_list="${SKIP_EXEC//[[:space:]]/}" 162 | for name in ${clean_list//,/ }; do 163 | rm -f "$name.zip" 164 | done 165 | - name: Unzip 166 | run: unzip '*.zip' -d executables 167 | - name: Setting up environment 168 | run: | 169 | python3 -m venv .venv 170 | source .venv/bin/activate 171 | pip install -r requirements.txt 172 | - name: Run Interoperability script 173 | # The test descriptions used are the generated for the last execution. 174 | # This shouldn't be an issue because all test are run always 175 | run: | 176 | source .venv/bin/activate 177 | cd executables 178 | for publisher in eprosima_fastdds-* ; do \ 179 | if [ -e "$publisher" ]; then \ 180 | for subscriber in * ; do \ 181 | echo "Testing Publisher $publisher --- Subscriber $subscriber"; \ 182 | python3 ./../interoperability_report.py -P ./$publisher -S ./$subscriber -o=./../junit_interoperability_report.xml; \ 183 | if [ -d "./OpenDDS-durable-data-dir" ]; then \ 184 | echo Deleting OpenDDS-durable-data-dir; \ 185 | rm -rf ./OpenDDS-durable-data-dir; \ 186 | fi; \ 187 | done \ 188 | fi; \ 189 | done 190 | - name: Attach the report 191 | if: always() 192 | uses: actions/upload-artifact@v4 193 | with: 194 | name: interoperability_report_eprosima_fastdds 195 | path: | 196 | ./junit_interoperability_report.xml 197 | ./timestamp 198 | intercom_dds: 199 | runs-on: ubuntu-latest 200 | needs: eprosima_fastdds 201 | steps: 202 | - name: Checkout 203 | uses: actions/checkout@v4 204 | - name: Download artifact 205 | uses: actions/download-artifact@v4 206 | with: 207 | name: interoperability_report_eprosima_fastdds 208 | - uses: actions/setup-python@v5 209 | with: 210 | python-version: '3.11.4' 211 | - name: Downloads assets 212 | uses: robinraju/release-downloader@v1.10 213 | with: 214 | latest: true 215 | fileName: "*" 216 | - name: Skip tests 217 | run: | 218 | echo "Skipping the following tests: $SKIP_EXEC" 219 | clean_list="${SKIP_EXEC//[[:space:]]/}" 220 | for name in ${clean_list//,/ }; do 221 | rm -f "$name.zip" 222 | done 223 | - name: Unzip 224 | run: unzip '*.zip' -d executables 225 | - name: Setting up environment 226 | run: | 227 | python3 -m venv .venv 228 | source .venv/bin/activate 229 | pip install -r requirements.txt 230 | - name: Run Interoperability script 231 | # The test descriptions used are the generated for the last execution. 232 | # This shouldn't be an issue because all test are run always 233 | run: | 234 | source .venv/bin/activate 235 | cd executables 236 | for publisher in intercom_dds-* ; do \ 237 | if [ -e "$publisher" ]; then \ 238 | for subscriber in * ; do \ 239 | echo "Testing Publisher $publisher --- Subscriber $subscriber"; \ 240 | python3 ./../interoperability_report.py -P ./$publisher -S ./$subscriber -o=./../junit_interoperability_report.xml; \ 241 | if [ -d "./OpenDDS-durable-data-dir" ]; then \ 242 | echo Deleting OpenDDS-durable-data-dir; \ 243 | rm -rf ./OpenDDS-durable-data-dir; \ 244 | fi; \ 245 | done \ 246 | fi; \ 247 | done 248 | - name: Attach the report 249 | if: always() 250 | uses: actions/upload-artifact@v4 251 | with: 252 | name: interoperability_report_intercom_dds 253 | path: | 254 | ./junit_interoperability_report.xml 255 | ./timestamp 256 | opendds: 257 | runs-on: ubuntu-latest 258 | needs: intercom_dds 259 | steps: 260 | - name: Checkout 261 | uses: actions/checkout@v4 262 | - name: Download artifact 263 | uses: actions/download-artifact@v4 264 | with: 265 | name: interoperability_report_intercom_dds 266 | - uses: actions/setup-python@v5 267 | with: 268 | python-version: '3.11.4' 269 | - name: Downloads assets 270 | uses: robinraju/release-downloader@v1.10 271 | with: 272 | latest: true 273 | fileName: "*" 274 | - name: Skip tests 275 | run: | 276 | echo "Skipping the following tests: $SKIP_EXEC" 277 | clean_list="${SKIP_EXEC//[[:space:]]/}" 278 | for name in ${clean_list//,/ }; do 279 | rm -f "$name.zip" 280 | done 281 | - name: Unzip 282 | run: unzip '*.zip' -d executables 283 | - name: Setting up environment 284 | run: | 285 | python3 -m venv .venv 286 | source .venv/bin/activate 287 | pip install -r requirements.txt 288 | - name: Run Interoperability script 289 | # The test descriptions used are the generated for the last execution. 290 | # This shouldn't be an issue because all test are run always 291 | run: | 292 | source .venv/bin/activate 293 | cd executables 294 | for publisher in opendds-* ; do \ 295 | if [ -e "$publisher" ]; then \ 296 | for subscriber in * ; do \ 297 | echo "Testing Publisher $publisher --- Subscriber $subscriber"; \ 298 | python3 ./../interoperability_report.py -P ./$publisher -S ./$subscriber -o=./../junit_interoperability_report.xml; \ 299 | if [ -d "./OpenDDS-durable-data-dir" ]; then \ 300 | echo Deleting OpenDDS-durable-data-dir; \ 301 | rm -rf ./OpenDDS-durable-data-dir; \ 302 | fi; \ 303 | done \ 304 | fi; \ 305 | done 306 | - name: Attach the report 307 | if: always() 308 | uses: actions/upload-artifact@v4 309 | with: 310 | name: interoperability_report_opendds 311 | path: | 312 | ./junit_interoperability_report.xml 313 | ./timestamp 314 | toc_coredx_dds: 315 | runs-on: ubuntu-latest 316 | needs: opendds 317 | steps: 318 | - name: Checkout 319 | uses: actions/checkout@v4 320 | - name: Download artifact 321 | uses: actions/download-artifact@v4 322 | with: 323 | name: interoperability_report_opendds 324 | - uses: actions/setup-python@v5 325 | with: 326 | python-version: '3.11.4' 327 | - name: Downloads assets 328 | uses: robinraju/release-downloader@v1.10 329 | with: 330 | latest: true 331 | fileName: "*" 332 | - name: Skip tests 333 | run: | 334 | echo "Skipping the following tests: $SKIP_EXEC" 335 | clean_list="${SKIP_EXEC//[[:space:]]/}" 336 | for name in ${clean_list//,/ }; do 337 | rm -f "$name.zip" 338 | done 339 | - name: Unzip 340 | run: unzip '*.zip' -d executables 341 | - name: Setting up environment 342 | run: | 343 | python3 -m venv .venv 344 | source .venv/bin/activate 345 | pip install -r requirements.txt 346 | - name: Run Interoperability script 347 | # The test descriptions used are the generated for the last execution. 348 | # This shouldn't be an issue because all test are run always 349 | run: | 350 | source .venv/bin/activate 351 | cd executables 352 | for publisher in toc_coredx_dds-* ; do \ 353 | if [ -e "$publisher" ]; then \ 354 | for subscriber in * ; do \ 355 | echo "Testing Publisher $publisher --- Subscriber $subscriber"; \ 356 | python3 ./../interoperability_report.py -P ./$publisher -S ./$subscriber -o=./../junit_interoperability_report.xml; \ 357 | if [ -d "./OpenDDS-durable-data-dir" ]; then \ 358 | echo Deleting OpenDDS-durable-data-dir; \ 359 | rm -rf ./OpenDDS-durable-data-dir; \ 360 | fi; \ 361 | done \ 362 | fi; \ 363 | done 364 | - name: Attach the report 365 | if: always() 366 | uses: actions/upload-artifact@v4 367 | with: 368 | name: interoperability_report_toc_coredx_dds 369 | path: | 370 | ./junit_interoperability_report.xml 371 | ./timestamp 372 | generate_report: 373 | runs-on: ubuntu-latest 374 | needs: toc_coredx_dds 375 | steps: 376 | - name: Checkout 377 | uses: actions/checkout@v4 378 | - name: Download artifact 379 | uses: actions/download-artifact@v4 380 | with: 381 | name: interoperability_report_toc_coredx_dds 382 | - uses: actions/setup-python@v5 383 | with: 384 | python-version: '3.11.4' 385 | - name: Setting up environment 386 | run: | 387 | python3 -m venv .venv 388 | source .venv/bin/activate 389 | pip install -r requirements.txt 390 | - name: Generate xlsx report 391 | run: | 392 | source .venv/bin/activate 393 | python3 generate_xlsx_report.py --input junit_interoperability_report.xml --output interoperability_report.xlsx 394 | - name: XUnit Viewer 395 | id: xunit-viewer 396 | uses: AutoModality/action-xunit-viewer@v1 397 | with: 398 | results: ./junit_interoperability_report.xml 399 | - name: Attach the report 400 | if: always() 401 | uses: actions/upload-artifact@v4 402 | with: 403 | name: interoperability_report_complete 404 | path: | 405 | ./index.html 406 | ./junit_interoperability_report.xml 407 | ./interoperability_report.xlsx 408 | ./timestamp 409 | -------------------------------------------------------------------------------- /test_suite_functions.py: -------------------------------------------------------------------------------- 1 | ################################################################# 2 | # Use and redistribution is source and binary forms is permitted 3 | # subject to the OMG-DDS INTEROPERABILITY TESTING LICENSE found 4 | # at the following URL: 5 | # 6 | # https://github.com/omg-dds/dds-rtps/blob/master/LICENSE.md 7 | # 8 | ################################################################# 9 | 10 | from rtps_test_utilities import ReturnCode 11 | import re 12 | import pexpect 13 | import queue 14 | import time 15 | 16 | # This constant is used to limit the maximum number of samples that tests that 17 | # check the behavior needs to read. For example, checking that the data 18 | # is received in order, or that OWNERSHIP works properly, etc... 19 | MAX_SAMPLES_READ = 500 20 | 21 | def test_ownership_receivers(child_sub, samples_sent, last_sample_saved, timeout): 22 | 23 | """ 24 | This function is used by test cases that have several publishers and one 25 | subscriber. 26 | This tests that the Ownership QoS works correctly. In order to do that the 27 | function checks if the subscriber has received samples from one publisher or 28 | from both. Each publisher should publish data with a different size. 29 | A subscriber has received from both publishers if there is a sample 30 | from each publisher interleaved. This is done to make sure the subscriber 31 | did not started receiving samples from the publisher that was run before, 32 | and then change to the publisher with the greatest ownership. 33 | 34 | child_sub: child program generated with pexpect 35 | samples_sent: not used 36 | last_sample_saved: not used 37 | timeout: time pexpect waits until it matches a pattern. 38 | 39 | This functions assumes that the subscriber has already received samples 40 | from, at least, one publisher. 41 | """ 42 | ignore_first_samples = True 43 | max_samples_received = MAX_SAMPLES_READ 44 | samples_read = 0 45 | sizes_received = [] 46 | last_size_received = 0 47 | 48 | while(samples_read < max_samples_received): 49 | # take the topic, color, position and size of the ShapeType. 50 | # child_sub.before contains x and y, and child_sub.after contains 51 | # [shapesize] 52 | # Example: child_sub.before contains 'Square BLUE 191 152' 53 | # child_sub.after contains '[30]' 54 | sub_string = re.search('[0-9]+ [0-9]+ \[([0-9]+)\]', 55 | child_sub.before + child_sub.after) 56 | # sub_string contains 'x y [shapesize]', example: '191 152 [30]' 57 | 58 | # Determine from which publisher the current sample belongs to 59 | # size determines the publisher 60 | if sub_string is not None: 61 | if int(sub_string.group(1)) not in sizes_received: 62 | last_size_received = int(sub_string.group(1)) 63 | sizes_received.append(last_size_received) 64 | else: 65 | return ReturnCode.DATA_NOT_RECEIVED 66 | 67 | # A potential case is that the reader gets data from one writer and 68 | # then start receiving from a different writer with a higher 69 | # ownership. This avoids returning RECEIVING_FROM_BOTH if this is 70 | # the case. 71 | # This if is only run once we process the first sample received by the 72 | # subscriber application 73 | if ignore_first_samples == True and len(sizes_received) == 2: 74 | # if we have received samples from both publishers, then we stop 75 | # ignoring samples 76 | ignore_first_samples = False 77 | # only leave the last received sample in the sizes_received list 78 | sizes_received.clear() 79 | sizes_received.append(last_size_received) 80 | 81 | # Get the next samples the subscriber is receiving 82 | index = child_sub.expect( 83 | [ 84 | '\[[0-9]+\]', # index = 0 85 | pexpect.TIMEOUT, # index = 1 86 | ], 87 | timeout 88 | ) 89 | if index == 1: 90 | break 91 | 92 | samples_read += 1 93 | 94 | print(f'Samples read: {samples_read}') 95 | if len(sizes_received) == 2: 96 | return ReturnCode.RECEIVING_FROM_BOTH 97 | elif len(sizes_received) == 1: 98 | return ReturnCode.RECEIVING_FROM_ONE 99 | return ReturnCode.DATA_NOT_RECEIVED 100 | 101 | def test_ownership_receivers_by_samples_sent(child_sub, samples_sent, last_sample_saved, timeout): 102 | 103 | """ 104 | This function is used by test cases that have two publishers and one subscriber. 105 | This tests that the Ownership QoS works correctly. In order to do that the 106 | function checks if the subscriber has received samples from one publisher or 107 | from both. A subscriber has received from both publishers if there is a sample 108 | from each publisher interleaved. This is done to make sure the subscriber did 109 | not started receiving samples from the publisher that was run before, and then 110 | change to the publisher with the greatest ownership. 111 | 112 | child_sub: child program generated with pexpect 113 | samples_sent: list of multiprocessing Queues with the samples 114 | the publishers send. Element 1 of the list is for 115 | publisher 1, etc. 116 | last_sample_saved: list of multiprocessing Queues with the last 117 | sample saved on samples_sent for each Publisher. Element 1 of 118 | the list is for Publisher 1, etc. 119 | timeout: time pexpect waits until it matches a pattern. 120 | 121 | This functions assumes that the subscriber has already received samples 122 | from, at least, one publisher. 123 | """ 124 | first_sample_received_publisher = 0 125 | ignore_first_samples = True 126 | first_received = False 127 | second_received = False 128 | list_data_received_second = [] 129 | list_data_received_first = [] 130 | max_samples_received = MAX_SAMPLES_READ 131 | max_retries = 500 132 | current_retries = 0 133 | samples_read = 0 134 | list_samples_processed = [] 135 | last_first_sample = '' 136 | last_second_sample = '' 137 | 138 | while(samples_read < max_samples_received): 139 | # take the topic, color, position and size of the ShapeType. 140 | # child_sub.before contains x and y, and child_sub.after contains 141 | # [shapesize] 142 | # Example: child_sub.before contains 'Square BLUE 191 152' 143 | # child_sub.after contains '[30]' 144 | sub_string = re.search('[0-9]+ [0-9]+ \[[0-9]+\]', 145 | child_sub.before + child_sub.after) 146 | # sub_string contains 'x y [shapesize]', example: '191 152 [30]' 147 | 148 | # takes samples written from both publishers stored in their queues 149 | # ('samples_sent[i]') and save them in different lists. 150 | # Try to get all available samples to avoid a race condition that 151 | # happens when the samples are not in the list but the reader has 152 | # already read them. 153 | # waits until to stop the execution of the loop and 154 | # returns the code "RECEIVING_FROM_ONE". 155 | # list_data_received_[first|second] is a list with the samples sent from 156 | # its corresponding publisher 157 | try: 158 | while True: 159 | list_data_received_first.append(samples_sent[0].get( 160 | block=False)) 161 | except queue.Empty: 162 | pass 163 | 164 | try: 165 | while True: 166 | list_data_received_second.append(samples_sent[1].get( 167 | block=False)) 168 | except queue.Empty: 169 | pass 170 | 171 | # Take the last sample published by each publisher from their queues 172 | # ('last_sample_saved[i]') and save them local variables. 173 | try: 174 | last_first_sample = last_sample_saved[0].get(block=False) 175 | except queue.Empty: 176 | pass 177 | 178 | try: 179 | last_second_sample = last_sample_saved[1].get(block=False) 180 | except queue.Empty: 181 | pass 182 | 183 | # Determine to which publisher the current sample belong to 184 | if sub_string.group(0) in list_data_received_second: 185 | current_sample_from_publisher = 2 186 | elif sub_string.group(0) in list_data_received_first: 187 | current_sample_from_publisher = 1 188 | else: 189 | # If the sample is not in any queue, break the loop if the 190 | # the last sample for any publisher has already been processed. 191 | if last_first_sample in list_samples_processed: 192 | break 193 | if last_second_sample in list_samples_processed: 194 | break 195 | print(f'Last samples: {last_first_sample}, {last_second_sample}') 196 | # Otherwise, wait a bit and continue 197 | time.sleep(0.1) 198 | current_retries += 1 199 | if current_retries > max_retries: 200 | print('Max retries exceeded') 201 | return ReturnCode.DATA_NOT_CORRECT 202 | continue 203 | 204 | current_retries = 0 205 | 206 | # Keep all samples processed in a single list, so we can check whether 207 | # the last sample published by any publisher has already been processed 208 | list_samples_processed.append(sub_string.group(0)) 209 | 210 | # If the app hit this point, it is because the previous subscriber 211 | # sample has been already read. Then, we can process the next sample 212 | # read by the subscriber. 213 | # Get the next samples the subscriber is receiving 214 | index = child_sub.expect( 215 | [ 216 | '\[[0-9]+\]', # index = 0 217 | pexpect.TIMEOUT, # index = 1 218 | ], 219 | timeout 220 | ) 221 | if index == 1: 222 | break 223 | 224 | samples_read += 1 225 | 226 | # A potential case is that the reader gets data from one writer and 227 | # then start receiving from a different writer with a higher 228 | # ownership. This avoids returning RECEIVING_FROM_BOTH if this is 229 | # the case. 230 | # This if is only run once we process the first sample received by the 231 | # subscriber application 232 | if first_sample_received_publisher == 0: 233 | if current_sample_from_publisher == 1: 234 | first_sample_received_publisher = 1 235 | elif current_sample_from_publisher == 2: 236 | first_sample_received_publisher = 2 237 | 238 | # Check if the app still needs to ignore samples 239 | if ignore_first_samples == True: 240 | if (first_sample_received_publisher == 1 \ 241 | and current_sample_from_publisher == 2) \ 242 | or (first_sample_received_publisher == 2 \ 243 | and current_sample_from_publisher == 1): 244 | # if receiving samples from a different publisher, then stop 245 | # ignoring samples 246 | ignore_first_samples = False 247 | else: 248 | # in case that the app only receives samples from one publisher 249 | # this loop always continues and will return RECEIVING_FROM_ONE 250 | continue 251 | 252 | if current_sample_from_publisher == 1: 253 | first_received = True 254 | else: 255 | second_received = True 256 | if second_received == True and first_received == True: 257 | return ReturnCode.RECEIVING_FROM_BOTH 258 | 259 | print(f'Samples read: {samples_read}') 260 | return ReturnCode.RECEIVING_FROM_ONE 261 | 262 | def test_color_receivers(child_sub, samples_sent, last_sample_saved, timeout): 263 | 264 | """ 265 | This function is used by test cases that have two publishers and one 266 | subscriber. This tests that only one of the color is received by the 267 | subscriber application because it contains a filter that only allows to 268 | receive data from one color. 269 | 270 | child_sub: child program generated with pexpect 271 | samples_sent: not used 272 | last_sample_saved: not used 273 | timeout: time pexpect waits until it matches a pattern. 274 | """ 275 | sub_string = re.search('\w\s+(\w+)\s+[0-9]+ [0-9]+ \[[0-9]+\]', 276 | child_sub.before + child_sub.after) 277 | first_sample_color = sub_string.group(1) 278 | 279 | max_samples_received = MAX_SAMPLES_READ 280 | samples_read = 0 281 | 282 | while sub_string is not None and samples_read < max_samples_received: 283 | current_sample_color = sub_string.group(1) 284 | 285 | # Check that all received samples have the same color 286 | if current_sample_color != first_sample_color: 287 | return ReturnCode.RECEIVING_FROM_BOTH 288 | 289 | index = child_sub.expect( 290 | [ 291 | '\[[0-9]+\]', # index = 0 292 | pexpect.TIMEOUT # index = 1 293 | ], 294 | timeout 295 | ) 296 | 297 | if index == 1: 298 | break 299 | 300 | samples_read += 1 301 | 302 | sub_string = re.search('\w\s+(\w+)\s+[0-9]+ [0-9]+ \[[0-9]+\]', 303 | child_sub.before + child_sub.after) 304 | 305 | print(f'Samples read: {samples_read}') 306 | return ReturnCode.RECEIVING_FROM_ONE 307 | 308 | def test_reliability_order(child_sub, samples_sent, last_sample_saved, timeout): 309 | """ 310 | This function tests reliability, it checks whether the subscriber receives 311 | the samples in order. 312 | 313 | child_sub: child program generated with pexpect 314 | samples_sent: not used 315 | last_sample_saved: not used 316 | timeout: not used 317 | """ 318 | 319 | produced_code = ReturnCode.OK 320 | 321 | # Read the first sample printed by the subscriber 322 | sub_string = re.search('[0-9]+ [0-9]+ \[([0-9]+)\]', 323 | child_sub.before + child_sub.after) 324 | last_size = 0 325 | 326 | max_samples_received = MAX_SAMPLES_READ 327 | samples_read = 0 328 | 329 | while sub_string is not None and samples_read < max_samples_received: 330 | current_size = int(sub_string.group(1)) 331 | if (current_size > last_size): 332 | last_size = current_size 333 | else: 334 | produced_code = ReturnCode.DATA_NOT_CORRECT 335 | break 336 | 337 | # Get the next sample the subscriber is receiving 338 | index = child_sub.expect( 339 | [ 340 | '\[[0-9]+\]', # index = 0 341 | pexpect.TIMEOUT # index = 1 342 | ], 343 | timeout 344 | ) 345 | if index == 1: 346 | # no more data to process 347 | break 348 | 349 | samples_read += 1 350 | 351 | # search the next received sample by the subscriber app 352 | sub_string = re.search('[0-9]+ [0-9]+ \[([0-9]+)\]', 353 | child_sub.before + child_sub.after) 354 | 355 | print(f'Samples read: {samples_read}') 356 | return produced_code 357 | 358 | 359 | def test_reliability_no_losses(child_sub, samples_sent, last_sample_saved, timeout): 360 | """ 361 | This function tests RELIABLE reliability, it checks whether the subscriber 362 | receives the samples in order and with no losses. 363 | 364 | child_sub: child program generated with pexpect 365 | samples_sent: list of multiprocessing Queues with the samples 366 | the publishers send. Element 1 of the list is for 367 | publisher 1, etc. 368 | last_sample_saved: not used 369 | timeout: time pexpect waits until it matches a pattern. 370 | """ 371 | 372 | produced_code = ReturnCode.OK 373 | processed_samples = 0 374 | 375 | # take the first sample received by the subscriber 376 | sub_string = re.search('[0-9]+ [0-9]+ \[[0-9]+\]', 377 | child_sub.before + child_sub.after) 378 | 379 | # This makes sure that at least one sample has been received 380 | if sub_string.group(0) is None: 381 | produced_code = ReturnCode.DATA_NOT_RECEIVED 382 | 383 | # Get the sample sent by the DataWriter that matches the first sample 384 | # received 385 | pub_sample = "" 386 | try: 387 | while pub_sample != sub_string.group(0): 388 | pub_sample = samples_sent[0].get(block=True, timeout=timeout) 389 | except: 390 | # If we don't find a sample in the publisher app that matches the 391 | # first sample received by the DataReader 392 | produced_code = ReturnCode.DATA_NOT_CORRECT 393 | 394 | # The first execution we don't need to call samples_sent[0].get() because 395 | # that takes the first element and remove it from the queue. As we have 396 | # checked before that the samples are the same, we need to skip that part 397 | # and get the next received sample 398 | first_execution = True 399 | 400 | max_samples_received = MAX_SAMPLES_READ 401 | samples_read = 0 402 | 403 | while sub_string is not None and samples_read < max_samples_received: 404 | # check that all the samples received by the DataReader are in order 405 | # and matches the samples sent by the DataWriter 406 | try: 407 | if first_execution: 408 | # do nothing because the first execution should already have 409 | # a pub_sample so we don't need to get it from the queue 410 | first_execution = False 411 | else: 412 | pub_sample = samples_sent[0].get(block=False) 413 | 414 | if pub_sample != sub_string.group(0): 415 | produced_code = ReturnCode.DATA_NOT_CORRECT 416 | break 417 | processed_samples += 1 418 | 419 | except: 420 | # at least 2 samples should be received 421 | if processed_samples <= 1: 422 | produced_code = ReturnCode.DATA_NOT_CORRECT 423 | break 424 | 425 | # Get the next sample the subscriber is receiving 426 | index = child_sub.expect( 427 | [ 428 | '\[[0-9]+\]', # index = 0 429 | pexpect.TIMEOUT # index = 1 430 | ], 431 | timeout 432 | ) 433 | if index == 1: 434 | # no more data to process 435 | break 436 | samples_read += 1 437 | # search the next received sample by the subscriber app 438 | sub_string = re.search('[0-9]+ [0-9]+ \[[0-9]+\]', 439 | child_sub.before + child_sub.after) 440 | 441 | print(f'Samples read: {samples_read}') 442 | return produced_code 443 | 444 | def test_durability_volatile(child_sub, samples_sent, last_sample_saved, timeout): 445 | """ 446 | This function tests the volatile durability, it checks that the sample the 447 | subscriber receives is not the first one. The publisher application sends 448 | samples increasing the value of the size, so if the first sample that the 449 | subscriber app doesn't have the size > 5, the test is correct. 450 | 451 | Note: size > 5 to avoid checking only the first sample, that may be an edge 452 | case where the DataReader hasn't matched with the DataWriter yet and 453 | the first samples are not received. 454 | 455 | child_sub: child program generated with pexpect 456 | samples_sent: not used 457 | last_sample_saved: not used 458 | timeout: not used 459 | """ 460 | 461 | # Read the first sample, if it has the size > 5, it is using volatile 462 | # durability correctly 463 | sub_string = re.search('[0-9]+ [0-9]+ \[([0-9]+)\]', 464 | child_sub.before + child_sub.after) 465 | 466 | # Check if the element received is not the first 5 samples (aka size >= 5) 467 | # which should not be the case because the subscriber application waits some 468 | # seconds after the publisher. Checking 5 samples instead of just one to 469 | # make sure that there is not the case in which the DataReader hasn't 470 | # matched with the DataWriter yet and the first samples may not be received. 471 | # The group(1) contains the matching element for the parameter between 472 | # brackets in the regular expression. In this case is the size as a string. 473 | if int(sub_string.group(1)) >= 5: 474 | produced_code = ReturnCode.OK 475 | else: 476 | produced_code = ReturnCode.DATA_NOT_CORRECT 477 | 478 | return produced_code 479 | 480 | def test_durability_transient_local(child_sub, samples_sent, last_sample_saved, timeout): 481 | """ 482 | This function tests the TRANSIENT_LOCAL durability, it checks that the 483 | sample the subscriber receives is the first one. The publisher application 484 | sends samples increasing the value of the size, so if the first sample that 485 | the subscriber app does have the size == 1, the test is correct. 486 | 487 | child_sub: child program generated with pexpect 488 | samples_sent: not used 489 | last_sample_saved: not used 490 | timeout: not used 491 | """ 492 | 493 | # Read the first sample, if it has the size == 1, it is using transient 494 | # local durability correctly 495 | sub_string = re.search('[0-9]+ [0-9]+ \[([0-9]+)\]', 496 | child_sub.before + child_sub.after) 497 | 498 | # Check if the element is the first one sent (aka size == 1), which should 499 | # be the case for TRANSIENT_LOCAL durability. 500 | # The group(1) contains the matching element for the parameter between 501 | # brackets in the regular expression. In this case is the size as a string. 502 | if int(sub_string.group(1)) == 1: 503 | produced_code = ReturnCode.OK 504 | else: 505 | produced_code = ReturnCode.DATA_NOT_CORRECT 506 | 507 | return produced_code 508 | 509 | 510 | def test_deadline_missed(child_sub, samples_sent, last_sample_saved, timeout): 511 | """ 512 | This function tests whether the subscriber application misses the requested 513 | deadline or not. This is needed in case the subscriber application receives 514 | some samples and then missed the requested deadline. 515 | 516 | child_sub: child program generated with pexpect 517 | samples_sent: not used 518 | last_sample_saved: not used 519 | timeout: time pexpect waits until it matches a pattern 520 | """ 521 | 522 | # At this point, the subscriber app has already received one sample 523 | # Check deadline requested missed 524 | index = child_sub.expect([ 525 | 'on_requested_deadline_missed()', # index = 0 526 | pexpect.TIMEOUT # index = 1 527 | ], 528 | timeout) 529 | if index == 0: 530 | return ReturnCode.DEADLINE_MISSED 531 | else: 532 | index = child_sub.expect([ 533 | '\[[0-9]+\]', # index = 0 534 | pexpect.TIMEOUT # index = 1 535 | ], 536 | timeout) 537 | if index == 0: 538 | return ReturnCode.OK 539 | else: 540 | return ReturnCode.DATA_NOT_RECEIVED 541 | -------------------------------------------------------------------------------- /srcRs/DustDDS/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "anstream" 7 | version = "0.6.21" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" 10 | dependencies = [ 11 | "anstyle", 12 | "anstyle-parse", 13 | "anstyle-query", 14 | "anstyle-wincon", 15 | "colorchoice", 16 | "is_terminal_polyfill", 17 | "utf8parse", 18 | ] 19 | 20 | [[package]] 21 | name = "anstyle" 22 | version = "1.0.13" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" 25 | 26 | [[package]] 27 | name = "anstyle-parse" 28 | version = "0.2.7" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 31 | dependencies = [ 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle-query" 37 | version = "1.1.5" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" 40 | dependencies = [ 41 | "windows-sys 0.61.2", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-wincon" 46 | version = "3.0.11" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" 49 | dependencies = [ 50 | "anstyle", 51 | "once_cell_polyfill", 52 | "windows-sys 0.61.2", 53 | ] 54 | 55 | [[package]] 56 | name = "async-lock" 57 | version = "3.4.1" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" 60 | dependencies = [ 61 | "event-listener", 62 | "event-listener-strategy", 63 | "pin-project-lite", 64 | ] 65 | 66 | [[package]] 67 | name = "bitflags" 68 | version = "2.10.0" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" 71 | 72 | [[package]] 73 | name = "block-buffer" 74 | version = "0.10.4" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 77 | dependencies = [ 78 | "generic-array", 79 | ] 80 | 81 | [[package]] 82 | name = "block2" 83 | version = "0.6.2" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" 86 | dependencies = [ 87 | "objc2", 88 | ] 89 | 90 | [[package]] 91 | name = "cc" 92 | version = "1.2.47" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" 95 | dependencies = [ 96 | "find-msvc-tools", 97 | "shlex", 98 | ] 99 | 100 | [[package]] 101 | name = "cfg-if" 102 | version = "1.0.4" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 105 | 106 | [[package]] 107 | name = "cfg_aliases" 108 | version = "0.2.1" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 111 | 112 | [[package]] 113 | name = "clap" 114 | version = "4.5.53" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" 117 | dependencies = [ 118 | "clap_builder", 119 | "clap_derive", 120 | ] 121 | 122 | [[package]] 123 | name = "clap_builder" 124 | version = "4.5.53" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" 127 | dependencies = [ 128 | "anstream", 129 | "anstyle", 130 | "clap_lex", 131 | "strsim", 132 | ] 133 | 134 | [[package]] 135 | name = "clap_derive" 136 | version = "4.5.49" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" 139 | dependencies = [ 140 | "heck", 141 | "proc-macro2", 142 | "quote", 143 | "syn", 144 | ] 145 | 146 | [[package]] 147 | name = "clap_lex" 148 | version = "0.7.6" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" 151 | 152 | [[package]] 153 | name = "colorchoice" 154 | version = "1.0.4" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 157 | 158 | [[package]] 159 | name = "concurrent-queue" 160 | version = "2.5.0" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 163 | dependencies = [ 164 | "crossbeam-utils", 165 | ] 166 | 167 | [[package]] 168 | name = "cpufeatures" 169 | version = "0.2.17" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 172 | dependencies = [ 173 | "libc", 174 | ] 175 | 176 | [[package]] 177 | name = "crossbeam-utils" 178 | version = "0.8.21" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 181 | 182 | [[package]] 183 | name = "crypto-common" 184 | version = "0.1.7" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" 187 | dependencies = [ 188 | "generic-array", 189 | "typenum", 190 | ] 191 | 192 | [[package]] 193 | name = "ctrlc" 194 | version = "3.5.1" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "73736a89c4aff73035ba2ed2e565061954da00d4970fc9ac25dcc85a2a20d790" 197 | dependencies = [ 198 | "dispatch2", 199 | "nix", 200 | "windows-sys 0.61.2", 201 | ] 202 | 203 | [[package]] 204 | name = "digest" 205 | version = "0.10.7" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 208 | dependencies = [ 209 | "block-buffer", 210 | "crypto-common", 211 | ] 212 | 213 | [[package]] 214 | name = "dispatch2" 215 | version = "0.3.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" 218 | dependencies = [ 219 | "bitflags", 220 | "block2", 221 | "libc", 222 | "objc2", 223 | ] 224 | 225 | [[package]] 226 | name = "dust_dds" 227 | version = "0.14.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "e0c41e5b28f155aec2860a5485db193485e57649bfce59258aa02e8b4e93f778" 230 | dependencies = [ 231 | "async-lock", 232 | "dust_dds_derive", 233 | "md5", 234 | "network-interface", 235 | "regex", 236 | "socket2", 237 | "tracing", 238 | ] 239 | 240 | [[package]] 241 | name = "dust_dds_derive" 242 | version = "0.14.0" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "ad07e59a9f8ff513bba952dfa82c4667e6162ba5b1e159e020845eded535b489" 245 | dependencies = [ 246 | "proc-macro2", 247 | "quote", 248 | "syn", 249 | "xml-rs", 250 | ] 251 | 252 | [[package]] 253 | name = "dust_dds_gen" 254 | version = "0.14.0" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "916c6f88f9d4989e4d62d0dd51717f28376c44f4402dee54a122efcb4f65cc98" 257 | dependencies = [ 258 | "pest", 259 | "pest_derive", 260 | ] 261 | 262 | [[package]] 263 | name = "dust_dds_shape_main_linux" 264 | version = "0.1.0" 265 | dependencies = [ 266 | "clap", 267 | "ctrlc", 268 | "dust_dds", 269 | "dust_dds_gen", 270 | "rand", 271 | ] 272 | 273 | [[package]] 274 | name = "event-listener" 275 | version = "5.4.1" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" 278 | dependencies = [ 279 | "concurrent-queue", 280 | "parking", 281 | "pin-project-lite", 282 | ] 283 | 284 | [[package]] 285 | name = "event-listener-strategy" 286 | version = "0.5.4" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" 289 | dependencies = [ 290 | "event-listener", 291 | "pin-project-lite", 292 | ] 293 | 294 | [[package]] 295 | name = "find-msvc-tools" 296 | version = "0.1.5" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" 299 | 300 | [[package]] 301 | name = "generic-array" 302 | version = "0.14.7" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 305 | dependencies = [ 306 | "typenum", 307 | "version_check", 308 | ] 309 | 310 | [[package]] 311 | name = "getrandom" 312 | version = "0.2.16" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 315 | dependencies = [ 316 | "cfg-if", 317 | "libc", 318 | "wasi", 319 | ] 320 | 321 | [[package]] 322 | name = "heck" 323 | version = "0.5.0" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 326 | 327 | [[package]] 328 | name = "is_terminal_polyfill" 329 | version = "1.70.2" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" 332 | 333 | [[package]] 334 | name = "libc" 335 | version = "0.2.177" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 338 | 339 | [[package]] 340 | name = "md5" 341 | version = "0.7.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 344 | 345 | [[package]] 346 | name = "memchr" 347 | version = "2.7.6" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 350 | 351 | [[package]] 352 | name = "network-interface" 353 | version = "1.1.4" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "a4a43439bf756eed340bdf8feba761e2d50c7d47175d87545cd5cbe4a137c4d1" 356 | dependencies = [ 357 | "cc", 358 | "libc", 359 | "thiserror", 360 | "winapi", 361 | ] 362 | 363 | [[package]] 364 | name = "nix" 365 | version = "0.30.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" 368 | dependencies = [ 369 | "bitflags", 370 | "cfg-if", 371 | "cfg_aliases", 372 | "libc", 373 | ] 374 | 375 | [[package]] 376 | name = "objc2" 377 | version = "0.6.3" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" 380 | dependencies = [ 381 | "objc2-encode", 382 | ] 383 | 384 | [[package]] 385 | name = "objc2-encode" 386 | version = "4.1.0" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" 389 | 390 | [[package]] 391 | name = "once_cell_polyfill" 392 | version = "1.70.2" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" 395 | 396 | [[package]] 397 | name = "parking" 398 | version = "2.2.1" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 401 | 402 | [[package]] 403 | name = "pest" 404 | version = "2.8.3" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" 407 | dependencies = [ 408 | "memchr", 409 | "ucd-trie", 410 | ] 411 | 412 | [[package]] 413 | name = "pest_derive" 414 | version = "2.8.3" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" 417 | dependencies = [ 418 | "pest", 419 | "pest_generator", 420 | ] 421 | 422 | [[package]] 423 | name = "pest_generator" 424 | version = "2.8.3" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" 427 | dependencies = [ 428 | "pest", 429 | "pest_meta", 430 | "proc-macro2", 431 | "quote", 432 | "syn", 433 | ] 434 | 435 | [[package]] 436 | name = "pest_meta" 437 | version = "2.8.3" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" 440 | dependencies = [ 441 | "pest", 442 | "sha2", 443 | ] 444 | 445 | [[package]] 446 | name = "pin-project-lite" 447 | version = "0.2.16" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 450 | 451 | [[package]] 452 | name = "ppv-lite86" 453 | version = "0.2.21" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 456 | dependencies = [ 457 | "zerocopy", 458 | ] 459 | 460 | [[package]] 461 | name = "proc-macro2" 462 | version = "1.0.103" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 465 | dependencies = [ 466 | "unicode-ident", 467 | ] 468 | 469 | [[package]] 470 | name = "quote" 471 | version = "1.0.42" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" 474 | dependencies = [ 475 | "proc-macro2", 476 | ] 477 | 478 | [[package]] 479 | name = "rand" 480 | version = "0.8.5" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 483 | dependencies = [ 484 | "libc", 485 | "rand_chacha", 486 | "rand_core", 487 | ] 488 | 489 | [[package]] 490 | name = "rand_chacha" 491 | version = "0.3.1" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 494 | dependencies = [ 495 | "ppv-lite86", 496 | "rand_core", 497 | ] 498 | 499 | [[package]] 500 | name = "rand_core" 501 | version = "0.6.4" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 504 | dependencies = [ 505 | "getrandom", 506 | ] 507 | 508 | [[package]] 509 | name = "regex" 510 | version = "1.12.2" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" 513 | dependencies = [ 514 | "regex-automata", 515 | "regex-syntax", 516 | ] 517 | 518 | [[package]] 519 | name = "regex-automata" 520 | version = "0.4.13" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" 523 | dependencies = [ 524 | "regex-syntax", 525 | ] 526 | 527 | [[package]] 528 | name = "regex-syntax" 529 | version = "0.8.8" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" 532 | 533 | [[package]] 534 | name = "sha2" 535 | version = "0.10.9" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 538 | dependencies = [ 539 | "cfg-if", 540 | "cpufeatures", 541 | "digest", 542 | ] 543 | 544 | [[package]] 545 | name = "shlex" 546 | version = "1.3.0" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 549 | 550 | [[package]] 551 | name = "socket2" 552 | version = "0.5.10" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" 555 | dependencies = [ 556 | "libc", 557 | "windows-sys 0.52.0", 558 | ] 559 | 560 | [[package]] 561 | name = "strsim" 562 | version = "0.11.1" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 565 | 566 | [[package]] 567 | name = "syn" 568 | version = "2.0.110" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" 571 | dependencies = [ 572 | "proc-macro2", 573 | "quote", 574 | "unicode-ident", 575 | ] 576 | 577 | [[package]] 578 | name = "thiserror" 579 | version = "1.0.69" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 582 | dependencies = [ 583 | "thiserror-impl", 584 | ] 585 | 586 | [[package]] 587 | name = "thiserror-impl" 588 | version = "1.0.69" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 591 | dependencies = [ 592 | "proc-macro2", 593 | "quote", 594 | "syn", 595 | ] 596 | 597 | [[package]] 598 | name = "tracing" 599 | version = "0.1.41" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 602 | dependencies = [ 603 | "pin-project-lite", 604 | "tracing-attributes", 605 | "tracing-core", 606 | ] 607 | 608 | [[package]] 609 | name = "tracing-attributes" 610 | version = "0.1.30" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 613 | dependencies = [ 614 | "proc-macro2", 615 | "quote", 616 | "syn", 617 | ] 618 | 619 | [[package]] 620 | name = "tracing-core" 621 | version = "0.1.34" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 624 | 625 | [[package]] 626 | name = "typenum" 627 | version = "1.19.0" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" 630 | 631 | [[package]] 632 | name = "ucd-trie" 633 | version = "0.1.7" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" 636 | 637 | [[package]] 638 | name = "unicode-ident" 639 | version = "1.0.22" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 642 | 643 | [[package]] 644 | name = "utf8parse" 645 | version = "0.2.2" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 648 | 649 | [[package]] 650 | name = "version_check" 651 | version = "0.9.5" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 654 | 655 | [[package]] 656 | name = "wasi" 657 | version = "0.11.1+wasi-snapshot-preview1" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 660 | 661 | [[package]] 662 | name = "winapi" 663 | version = "0.3.9" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 666 | dependencies = [ 667 | "winapi-i686-pc-windows-gnu", 668 | "winapi-x86_64-pc-windows-gnu", 669 | ] 670 | 671 | [[package]] 672 | name = "winapi-i686-pc-windows-gnu" 673 | version = "0.4.0" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 676 | 677 | [[package]] 678 | name = "winapi-x86_64-pc-windows-gnu" 679 | version = "0.4.0" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 682 | 683 | [[package]] 684 | name = "windows-link" 685 | version = "0.2.1" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 688 | 689 | [[package]] 690 | name = "windows-sys" 691 | version = "0.52.0" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 694 | dependencies = [ 695 | "windows-targets", 696 | ] 697 | 698 | [[package]] 699 | name = "windows-sys" 700 | version = "0.61.2" 701 | source = "registry+https://github.com/rust-lang/crates.io-index" 702 | checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 703 | dependencies = [ 704 | "windows-link", 705 | ] 706 | 707 | [[package]] 708 | name = "windows-targets" 709 | version = "0.52.6" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 712 | dependencies = [ 713 | "windows_aarch64_gnullvm", 714 | "windows_aarch64_msvc", 715 | "windows_i686_gnu", 716 | "windows_i686_gnullvm", 717 | "windows_i686_msvc", 718 | "windows_x86_64_gnu", 719 | "windows_x86_64_gnullvm", 720 | "windows_x86_64_msvc", 721 | ] 722 | 723 | [[package]] 724 | name = "windows_aarch64_gnullvm" 725 | version = "0.52.6" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 728 | 729 | [[package]] 730 | name = "windows_aarch64_msvc" 731 | version = "0.52.6" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 734 | 735 | [[package]] 736 | name = "windows_i686_gnu" 737 | version = "0.52.6" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 740 | 741 | [[package]] 742 | name = "windows_i686_gnullvm" 743 | version = "0.52.6" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 746 | 747 | [[package]] 748 | name = "windows_i686_msvc" 749 | version = "0.52.6" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 752 | 753 | [[package]] 754 | name = "windows_x86_64_gnu" 755 | version = "0.52.6" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 758 | 759 | [[package]] 760 | name = "windows_x86_64_gnullvm" 761 | version = "0.52.6" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 764 | 765 | [[package]] 766 | name = "windows_x86_64_msvc" 767 | version = "0.52.6" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 770 | 771 | [[package]] 772 | name = "xml-rs" 773 | version = "0.8.28" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" 776 | 777 | [[package]] 778 | name = "zerocopy" 779 | version = "0.8.28" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90" 782 | dependencies = [ 783 | "zerocopy-derive", 784 | ] 785 | 786 | [[package]] 787 | name = "zerocopy-derive" 788 | version = "0.8.28" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26" 791 | dependencies = [ 792 | "proc-macro2", 793 | "quote", 794 | "syn", 795 | ] 796 | --------------------------------------------------------------------------------