diff --git a/.env.oft-latest b/.env.oft-latest new file mode 100644 index 0000000..7071071 --- /dev/null +++ b/.env.oft-latest @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 + +# shellcheck disable=SC2148,SC2034 + +# The file patterns that specify the relevant parts of the latest uProtocol Specification +# that this component is supposed to implement +UP_SPEC_FILE_PATTERNS="up-spec/basics/uattributes.adoc up-spec/up-l1/README.adoc up-spec/up-l1/iceoryx2.adoc" + +# The file patterns that specify this component's resources which contain specification items +# that cover the requirements +COMPONENT_FILE_PATTERNS="*.adoc *.md *.rs .github examples src tests" + +OFT_FILE_PATTERNS="$UP_SPEC_FILE_PATTERNS $COMPONENT_FILE_PATTERNS" +OFT_TAGS="_,TransportLayerImpl,TransportLayerImplPush" diff --git a/.github/workflows/spec_compatibility.yml b/.github/workflows/spec_compatibility.yml new file mode 100644 index 0000000..dc48828 --- /dev/null +++ b/.github/workflows/spec_compatibility.yml @@ -0,0 +1,88 @@ +# ******************************************************************************** +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************** + +# Verifies that this crate can be built using the uProtocol Core API from up-spec's main branch. +# Also performs requirements tracing using OpenFastTrace. The job fails if any of the two +# activities fail. + +name: Latest uP Spec Compatibility + +on: + schedule: + - cron: '0 4 * * *' + workflow_dispatch: + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +env: + RUST_TOOLCHAIN: ${{ vars.RUST_TOOLCHAIN || 'stable' }} + RUSTFLAGS: -Dwarnings + CARGO_TERM_COLOR: always + +jobs: + requirements-tracing: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + - name: Fast-Forward to HEAD revision of uProtocol Spec main branch + run: | + cd "${{ github.workspace }}/up-spec" + echo "Switching to up-spec/main branch ..." + git checkout main + echo "fast-forwarding to HEAD revision ..." + git pull + git status + cd "${{ github.workspace }}" + + - name: "Determine OpenFastTrace file patterns from .env file" + uses: xom9ikk/dotenv@v2.3.0 + with: + mode: "oft-latest" + load-mode: strict + + # run OpenFastTrace first because the action will always succeed and produce + # a tracing report + - name: Run OpenFastTrace + id: run-oft + uses: eclipse-uprotocol/ci-cd/.github/actions/run-oft@main + with: + file-patterns: "${{ env.OFT_FILE_PATTERNS }}" + tags: "${{ env.OFT_TAGS_}}" + + # now try to build and run the tests which may fail if incompatible changes + # have been introduced into the uProtocol Core API + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + - uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@nextest + - name: Run tests + run: | + # Using nextest because it's faster than built-in test + cargo nextest run --all-features + # but it cannot execute doc tests + cargo test --doc --all-features + + # This step will only be run if the tests in the previous step have succeeded. + # In that case, we use the exit code produced by the OFT run as the job's + # overall outcome. This means that the job fails if the tests run successfully + # but some of the requirements from up-spec are not covered. + - name: Determine exit status + env: + OFT_EXIT_CODE: ${{ steps.run-oft.outputs.oft-exit-code }} + run: | + exit $OFT_EXIT_CODE diff --git a/.gitignore b/.gitignore index 2a5f86e..f4422cd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ # # This program and the accompanying materials are made available under the # terms of the Apache License Version 2.0 which is available at -# https: //www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # SPDX-License-Identifier: Apache-2.0 # ################################################################################ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8af405b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "up-spec"] + path = up-spec + url = https://github.com/eclipse-uprotocol/up-spec diff --git a/src/lib.rs b/src/lib.rs index c9c2ee6..78bc4e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,6 +72,7 @@ impl Iceoryx2Transport { /// send() makes use of UAttributesValidator /// register_listener() and unregister_listener() use verify_filter_criteria() /// Criteria for identification of message types can be found here: https://github.com/eclipse-uprotocol/up-spec/blob/main/basics/uattributes.adoc + fn determine_message_type(source: &UUri, sink: Option<&UUri>) -> Result { let src_id = source.resource_id; let sink_id = sink.map(|s| s.resource_id); @@ -95,6 +96,7 @@ impl Iceoryx2Transport { } /// Called in send(), register_listener() and unregister_listener() + fn compute_service_name(source: &UUri, sink: Option<&UUri>) -> Result { let join_segments = |segments: Vec| segments.join("/"); @@ -141,52 +143,49 @@ mod tests { UUri::try_from_parts(authority, entity_id, version, resource).unwrap() } - // performing successful tests for service name computation - #[test] - // [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"] + // [utest->dsn~up-transport-iceoryx2-service-name~1] fn test_publish_service_name() { let source = test_uri("device1", 0x0000, 0x10AB, 0x03, 0x7FFF); - let name = Iceoryx2Transport::compute_service_name(&source, None).unwrap(); + let name = Iceoryx2Transport::compute_service_name(&source,None).unwrap(); assert_eq!(name, "up/device1/10AB/0/3/7FFF"); } #[test] - // [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"] + + // [utest->dsn~up-transport-iceoryx2-service-name~1] fn test_notification_service_name() { let source = test_uri("device1", 0x0000, 0x10AB, 0x03, 0x80CD); let sink = test_uri("device1", 0x0000, 0x30EF, 0x04, 0x0000); - let name = Iceoryx2Transport::compute_service_name(&source, Some(&sink)).unwrap(); + let name = Iceoryx2Transport::compute_service_name(&source,Some(&sink)).unwrap(); + assert_eq!(name, "up/device1/10AB/0/3/80CD/device1/30EF/0/4/0"); } #[test] - // [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"] + + // [utest->dsn~up-transport-iceoryx2-service-name~1] fn test_rpc_request_service_name() { let sink = test_uri("device1", 0x0004, 0x03AB, 0x03, 0x0000); let reply_to = test_uri("device1", 0x0000, 0x00CD, 0x04, 0xB); - let name = Iceoryx2Transport::compute_service_name(&sink, Some(&reply_to)).unwrap(); + assert_eq!(name, "up/device1/CD/0/4/B"); } #[test] - // [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"] + // [utest->dsn~up-transport-iceoryx2-service-name~1] fn test_rpc_response_service_name() { let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0xB); let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x0000); - - let name = Iceoryx2Transport::compute_service_name(&source, Some(&sink)).unwrap(); + let name = Iceoryx2Transport::compute_service_name(&source,Some(&sink)).unwrap(); + assert_eq!(name, "up/device1/CD/0/4/B/device1/3AB/4/3/0"); } - // performing failing tests for service name computation - #[test] - // .specitem[dsn~up-attributes-request-source~1] - // .specitem[dsn~up-attributes-response-source~1] - // .specitem[dsn~up-attributes-notification-source~1] + // [utest->dsn~up-transport-iceoryx2-service-name~1] fn test_missing_uri_error() { let uuri = UUri::new(); let result = Iceoryx2Transport::compute_service_name(&uuri, None); @@ -196,11 +195,8 @@ mod tests { } #[test] - //both source and sink have resource ID equal to 0 - // .specitem[dsn~up-attributes-request-source~1] - // .specitem[dsn~up-attributes-request-sink~1] - // .specitem[dsn~up-attributes-response-source~1] - // .specitem[dsn~up-attributes-response-sink~1] + // [utest->dsn~up-transport-iceoryx2-service-name~1] + fn test_fail_resource_id_error() { let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0x000); let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x0000); @@ -209,20 +205,8 @@ mod tests { } #[test] - //source has resource id=0 but missing sink - // .specitem[dsn~up-attributes-request-sink~1] - // .specitem[dsn~up-attributes-request-source~1] - fn test_fail_missing_sink_error() { - let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0x000); - let result = Iceoryx2Transport::compute_service_name(&source, None); - assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT)); - } + // [utest->dsn~up-transport-iceoryx2-service-name~1] - #[test] - //missing source URI - // .specitem[dsn~up-attributes-request-source~1] - // .specitem[dsn~up-attributes-response-source~1] - // .specitem[dsn~up-attributes-notification-source~1] fn test_fail_missing_source_error() { let uuri = UUri::new(); let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x000); @@ -230,3 +214,4 @@ mod tests { assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT)); } } + diff --git a/up-spec b/up-spec new file mode 160000 index 0000000..ba0f3ca --- /dev/null +++ b/up-spec @@ -0,0 +1 @@ +Subproject commit ba0f3caef4fc4a73b3561e26e0a9abf71883efcd