From a14b7564137f784a5de89ac71418877e6b29627c Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Tue, 17 Mar 2026 15:47:22 +0530 Subject: [PATCH 1/3] Rust::com COM-API integration test using the integration_testing framework * Added Integration test case for sync and async both APIs --- score/mw/com/test/bigdata/BUILD | 5 + score/mw/com/test/com_api/BUILD | 44 +++++ .../com/test/com_api/bigdata_com_api_gen.cpp | 27 +++ .../mw/com/test/com_api/bigdata_com_api_gen.h | 21 ++ .../com/test/com_api/bigdata_com_api_gen.rs | 185 ++++++++++++++++++ .../test/com_api/consumer_async_apis/BUILD | 45 +++++ .../consumer_async_apis/consumer_app.rs | 131 +++++++++++++ .../integration_test/BUILD | 30 +++ .../com_api_async_api_test.py | 19 ++ .../com/test/com_api/consumer_sync_apis/BUILD | 44 +++++ .../consumer_sync_apis/consumer_app.rs | 137 +++++++++++++ .../consumer_sync_apis/integration_test/BUILD | 30 +++ .../integration_test/com_api_sync_api_test.py | 19 ++ score/mw/com/test/com_api/etc/BUILD | 18 ++ score/mw/com/test/com_api/etc/config.json | 83 ++++++++ score/mw/com/test/com_api/producer_app/BUILD | 27 +++ .../test/com_api/producer_app/producer_app.rs | 91 +++++++++ 17 files changed, 956 insertions(+) create mode 100644 score/mw/com/test/com_api/BUILD create mode 100644 score/mw/com/test/com_api/bigdata_com_api_gen.cpp create mode 100644 score/mw/com/test/com_api/bigdata_com_api_gen.h create mode 100644 score/mw/com/test/com_api/bigdata_com_api_gen.rs create mode 100644 score/mw/com/test/com_api/consumer_async_apis/BUILD create mode 100644 score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs create mode 100644 score/mw/com/test/com_api/consumer_async_apis/integration_test/BUILD create mode 100644 score/mw/com/test/com_api/consumer_async_apis/integration_test/com_api_async_api_test.py create mode 100644 score/mw/com/test/com_api/consumer_sync_apis/BUILD create mode 100644 score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs create mode 100644 score/mw/com/test/com_api/consumer_sync_apis/integration_test/BUILD create mode 100644 score/mw/com/test/com_api/consumer_sync_apis/integration_test/com_api_sync_api_test.py create mode 100644 score/mw/com/test/com_api/etc/BUILD create mode 100644 score/mw/com/test/com_api/etc/config.json create mode 100644 score/mw/com/test/com_api/producer_app/BUILD create mode 100644 score/mw/com/test/com_api/producer_app/producer_app.rs diff --git a/score/mw/com/test/bigdata/BUILD b/score/mw/com/test/bigdata/BUILD index 2948682bc..d22f50b74 100644 --- a/score/mw/com/test/bigdata/BUILD +++ b/score/mw/com/test/bigdata/BUILD @@ -16,6 +16,11 @@ load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") load("//score/mw/com/test:pkg_application.bzl", "pkg_application") +exports_files( + ["logging.json"], + visibility = ["//score/mw/com/test:__subpackages__"], +) + cc_binary( name = "bigdata", srcs = [ diff --git a/score/mw/com/test/com_api/BUILD b/score/mw/com/test/com_api/BUILD new file mode 100644 index 000000000..0e8696e4a --- /dev/null +++ b/score/mw/com/test/com_api/BUILD @@ -0,0 +1,44 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@rules_rust//rust:defs.bzl", "rust_library") +load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") + +cc_library( + name = "bigdata_com_api_gen_cpp", + srcs = ["bigdata_com_api_gen.cpp"], + hdrs = ["bigdata_com_api_gen.h"], + features = COMPILER_WARNING_FEATURES, + implementation_deps = [ + "//score/mw/com/impl/rust/com-api/com-api-ffi-lola:registry_bridge_macro_cpp", + ], + deps = [ + "//score/mw/com/test/common_test_resources:bigdata_type", + ], + alwayslink = True, +) + +rust_library( + name = "bigdata_com_api_gen_rs", + srcs = ["bigdata_com_api_gen.rs"], + crate_name = "bigdata_com_api_gen", + features = ["link_std_cpp_lib"], + visibility = [ + "//score/mw/com/test/com_api:__subpackages__", + ], + deps = [ + ":bigdata_com_api_gen_cpp", + "//score/mw/com/impl/rust/com-api/com-api", + ], +) diff --git a/score/mw/com/test/com_api/bigdata_com_api_gen.cpp b/score/mw/com/test/com_api/bigdata_com_api_gen.cpp new file mode 100644 index 000000000..90b4b1d40 --- /dev/null +++ b/score/mw/com/test/com_api/bigdata_com_api_gen.cpp @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2026 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 + *******************************************************************************/ + +#include "score/mw/com/test/com_api/bigdata_com_api_gen.h" +#include "score/mw/com/impl/rust/com-api/com-api-ffi-lola/registry_bridge_macro.h" + +// Register the BigData interface with the com-api FFI bridge. +BEGIN_EXPORT_MW_COM_INTERFACE(BigDataInterface, + ::score::mw::com::test::BigDataProxy, + ::score::mw::com::test::BigDataSkeleton) +EXPORT_MW_COM_EVENT(::score::mw::com::test::MapApiLanesStamped, map_api_lanes_stamped_) +EXPORT_MW_COM_EVENT(::score::mw::com::test::DummyDataStamped, dummy_data_stamped_) +END_EXPORT_MW_COM_INTERFACE() + +// Export data types so that the Rust-side CommData::ID can resolve them. +EXPORT_MW_COM_TYPE(MapApiLanesStamped, ::score::mw::com::test::MapApiLanesStamped) +EXPORT_MW_COM_TYPE(DummyDataStamped, ::score::mw::com::test::DummyDataStamped) diff --git a/score/mw/com/test/com_api/bigdata_com_api_gen.h b/score/mw/com/test/com_api/bigdata_com_api_gen.h new file mode 100644 index 000000000..bc7dbd9ff --- /dev/null +++ b/score/mw/com/test/com_api/bigdata_com_api_gen.h @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2026 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 + *******************************************************************************/ + +#ifndef SCORE_MW_COM_TEST_COM_API_BIGDATA_COM_API_GEN_H +#define SCORE_MW_COM_TEST_COM_API_BIGDATA_COM_API_GEN_H + +// Re-export the BigData interface types (BigDataProxy / BigDataSkeleton) that are +// already defined in big_datatype.h +#include "score/mw/com/test/common_test_resources/big_datatype.h" + +#endif // SCORE_MW_COM_TEST_COM_API_BIGDATA_COM_API_GEN_H diff --git a/score/mw/com/test/com_api/bigdata_com_api_gen.rs b/score/mw/com/test/com_api/bigdata_com_api_gen.rs new file mode 100644 index 000000000..5fe5a6631 --- /dev/null +++ b/score/mw/com/test/com_api/bigdata_com_api_gen.rs @@ -0,0 +1,185 @@ +/******************************************************************************** + * Copyright (c) 2026 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 + ********************************************************************************/ + +//! Generated bindings for the BigData interface using the com-api library. +//! +//! This file is the com-api counterpart of the old-API `bigdata_gen.rs`. It +//! defines the same large data types (`MapApiLanesStamped`, `DummyDataStamped`) +//! and wires them through the com-api `Interface` / `Consumer` / `Producer` +//! abstractions instead of the legacy `mw_com::import_interface!` macro. + +use com_api::{ + CommData, Consumer, Interface, OfferedProducer, Producer, ProviderInfo, Publisher, Reloc, + Runtime, Subscriber, +}; + +use core::fmt::Debug; + +#[repr(C)] +#[derive(Default, Reloc)] +pub struct StdTimestamp { + pub fractional_seconds: u32, + pub seconds: u32, + pub sync_status: u32, +} + +/// Opaque representation of `MapApiLaneBoundaryData` (empty struct in C++). +#[repr(C)] +#[derive(Default, Reloc)] +pub struct MapApiLaneBoundaryData { + _dummy: [u8; 1], +} + +/// Opaque representation of `MapApiLaneData`. +/// Using a single-byte placeholder; the C++ type is much larger. +/// This is sufficient because the test only verifies sample-count delivery. +#[repr(C)] +#[derive(Default, Reloc)] +pub struct MapApiLaneData { + _dummy: [u8; 1], +} + +/// Opaque representation of `LaneGroupData` (empty struct in C++). +#[repr(C)] +#[derive(Default, Reloc)] +pub struct LaneGroupData { + _dummy: [u8; 1], +} + +pub const MAX_LANES: usize = 16; + +/// Large data type sent over the `map_api_lanes_stamped` event. +#[repr(C)] +#[derive(Default, Reloc)] +pub struct MapApiLanesStamped { + pub time_stamp: StdTimestamp, + pub frame_id: [u8; 10], + pub projection_id: u32, + pub event_data_qualifier: u32, + pub lane_boundaries: [MapApiLaneBoundaryData; 10], + pub lanes: [MapApiLaneData; MAX_LANES], + pub lane_groups: [LaneGroupData; 10], + pub x: u32, + pub hash_value: usize, +} + +impl CommData for MapApiLanesStamped { + const ID: &'static str = "MapApiLanesStamped"; +} + +impl Debug for MapApiLanesStamped { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "MapApiLanesStamped {{ x: {} }}", self.x) + } +} + +/// Secondary event data type. +#[repr(C)] +#[derive(Default, Reloc)] +pub struct DummyDataStamped { + pub time_stamp: StdTimestamp, + pub x: u8, + pub hash_value: usize, +} + +impl CommData for DummyDataStamped { + const ID: &'static str = "DummyDataStamped"; +} + +impl Debug for DummyDataStamped { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "DummyDataStamped {{ x: {} }}", self.x) + } +} + +/// Generated com-api bindings for the BigData interface. +pub struct BigDataInterface {} + +impl Interface for BigDataInterface { + const INTERFACE_ID: &'static str = "BigDataInterface"; + type Consumer = BigDataConsumer; + type Producer = BigDataProducer; +} + +/// Consumer type for the BigData interface. +pub struct BigDataConsumer { + pub map_api_lanes_stamped: R::Subscriber, + pub dummy_data_stamped: R::Subscriber, +} + +impl Consumer for BigDataConsumer { + fn new(instance_info: R::ConsumerInfo) -> Self { + let map_api_lanes_stamped = + R::Subscriber::new("map_api_lanes_stamped_", instance_info.clone()) + .expect("Failed to create map_api_lanes_stamped subscriber"); + let dummy_data_stamped = R::Subscriber::new("dummy_data_stamped_", instance_info) + .expect("Failed to create dummy_data_stamped subscriber"); + BigDataConsumer { + map_api_lanes_stamped, + dummy_data_stamped, + } + } +} + +/// Producer type for the BigData interface. +pub struct BigDataProducer { + _runtime: core::marker::PhantomData, + instance_info: R::ProviderInfo, +} + +impl Producer for BigDataProducer { + type Interface = BigDataInterface; + type OfferedProducer = BigDataOfferedProducer; + + fn new(instance_info: R::ProviderInfo) -> com_api::Result { + Ok(BigDataProducer { + _runtime: core::marker::PhantomData, + instance_info, + }) + } + + fn offer(self) -> com_api::Result { + let map_api_lanes_stamped = + R::Publisher::new("map_api_lanes_stamped_", self.instance_info.clone()) + .expect("Failed to create map_api_lanes_stamped publisher"); + let dummy_data_stamped = + R::Publisher::new("dummy_data_stamped_", self.instance_info.clone()) + .expect("Failed to create dummy_data_stamped publisher"); + self.instance_info.offer_service()?; + Ok(BigDataOfferedProducer { + map_api_lanes_stamped, + dummy_data_stamped, + instance_info: self.instance_info, + }) + } +} + +/// Offered producer type for the BigData interface, returned by `BigDataProducer::offer()`. +pub struct BigDataOfferedProducer { + pub map_api_lanes_stamped: R::Publisher, + pub dummy_data_stamped: R::Publisher, + instance_info: R::ProviderInfo, +} + +impl OfferedProducer for BigDataOfferedProducer { + type Interface = BigDataInterface; + type Producer = BigDataProducer; + + fn unoffer(self) -> com_api::Result { + self.instance_info.stop_offer_service()?; + Ok(BigDataProducer { + _runtime: core::marker::PhantomData, + instance_info: self.instance_info, + }) + } +} diff --git a/score/mw/com/test/com_api/consumer_async_apis/BUILD b/score/mw/com/test/com_api/consumer_async_apis/BUILD new file mode 100644 index 000000000..be647feb5 --- /dev/null +++ b/score/mw/com/test/com_api/consumer_async_apis/BUILD @@ -0,0 +1,45 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* + +load("@rules_rust//rust:defs.bzl", "rust_binary") +load("//score/mw/com/test:pkg_application.bzl", "pkg_application") + +rust_binary( + name = "bigdata-consumer-async", + srcs = ["consumer_app.rs"], + features = ["link_std_cpp_lib"], + visibility = [ + "//score/mw/com/test/com_api:__subpackages__", + ], + deps = [ + "//score/mw/com/impl/rust/com-api/com-api", + "//score/mw/com/test/com_api:bigdata_com_api_gen_rs", + "@score_communication_crate_index//:tokio", + ], +) + +pkg_application( + name = "bigdata-com-api-async-pkg", + app_name = "bigdata-com-api-async", + bin = [ + ":bigdata-consumer-async", + "//score/mw/com/test/com_api/producer_app:bigdata-producer", + ], + etc = [ + "//score/mw/com/test/com_api/etc:config", + "//score/mw/com/test/bigdata:logging.json", + ], + visibility = [ + "//score/mw/com/test/com_api:__subpackages__", + ], +) diff --git a/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs b/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs new file mode 100644 index 000000000..9ea08f716 --- /dev/null +++ b/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs @@ -0,0 +1,131 @@ +/******************************************************************************** + * Copyright (c) 2026 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 + ********************************************************************************/ + +//! Consumer (proxy) binary for the BigData com-api SCT. +//! it use the async APIs for Service Discovery and Receive samples. +//! +//! # Usage +//! +//! ``` +//! bigdata-consumer -n +//! ``` +//! * `-n ` — number of samples to receive before exiting. +//! The consumer subscribes to the producer's `map_api_lanes_stamped` output and +//! prints the `x` field of each received sample until it has received the specified number of samples, at which point it exits. + +use bigdata_com_api_gen::BigDataInterface; +use com_api::{ + Builder, FindServiceSpecifier, InstanceSpecifier, LolaRuntimeBuilderImpl, Runtime, + RuntimeBuilder, SampleContainer, ServiceDiscovery, Subscriber, Subscription, +}; +use std::path::Path; + +const CONFIG_PATH: &str = "etc/config.json"; +const MAX_SAMPLES_PER_CALL: usize = 5; + +fn parse_args() -> usize { + let args: Vec = std::env::args().collect(); + let mut iter = args.iter().skip(1); + while let Some(arg) = iter.next() { + if arg == "-n" { + if let Some(val) = iter.next() { + if let Ok(n) = val.parse::() { + return n; + } + } + } + } + eprintln!("[bigdata-consumer] ERROR: -n is required"); + std::process::exit(1); +} + +#[tokio::main] +async fn main() { + let num_cycles = parse_args(); + + println!( + "[bigdata-consumer] Starting, will receive {} samples", + num_cycles + ); + + // Initialise the Lola runtime. + let mut runtime_builder = LolaRuntimeBuilderImpl::new(); + runtime_builder.load_config(Path::new(CONFIG_PATH)); + let runtime = runtime_builder + .build() + .expect("Failed to build Lola runtime"); + + let instance_specifier = InstanceSpecifier::new("/score/cp60/MapApiLanesStamped") + .expect("Invalid instance specifier"); + + let discovery = runtime.find_service::(FindServiceSpecifier::Specific( + instance_specifier.clone(), + )); + + // Await the producer to become available. + let instances = discovery + .get_available_instances_async() + .await + .expect("Failed to get available instances"); + + let builder = instances + .into_iter() + .next() + .expect("No service instances available"); + let consumer = builder.build().expect("Failed to build consumer"); + + // Subscribe with a slot buffer large enough for MAX_SAMPLES_PER_CALL. + let subscription = consumer + .map_api_lanes_stamped + .subscribe(MAX_SAMPLES_PER_CALL) + .expect("Failed to subscribe to map_api_lanes_stamped"); + + let mut received_total: usize = 0; + let mut sample_buf = SampleContainer::new(MAX_SAMPLES_PER_CALL); + // `receive` awaits until at least `min_samples` (1) are available. + while received_total < num_cycles { + sample_buf = match subscription + .receive(sample_buf, 1, MAX_SAMPLES_PER_CALL) + .await + { + Ok(returned_buf) => { + let count = returned_buf.sample_count(); + if count > 0 { + let mut buf = returned_buf; + for _ in 0..count { + if let Some(sample) = buf.pop_front() { + println!("[bigdata-consumer] Received sample x={}", sample.x); + } + } + received_total += count; + println!( + "[bigdata-consumer] Progress: {}/{}", + received_total, num_cycles + ); + buf + } else { + returned_buf + } + } + Err(e) => { + eprintln!("[bigdata-consumer] Receive error: {:?}", e); + std::process::exit(1); + } + }; + } + + println!( + "[bigdata-consumer] Received all {} samples, exiting", + num_cycles + ); +} diff --git a/score/mw/com/test/com_api/consumer_async_apis/integration_test/BUILD b/score/mw/com/test/com_api/consumer_async_apis/integration_test/BUILD new file mode 100644 index 000000000..1083b4eda --- /dev/null +++ b/score/mw/com/test/com_api/consumer_async_apis/integration_test/BUILD @@ -0,0 +1,30 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//quality/integration_testing:integration_testing.bzl", "integration_test") + +pkg_tar( + name = "filesystem", + deps = [ + "//score/mw/com/test/com_api/consumer_async_apis:bigdata-com-api-async-pkg", + ], +) + +integration_test( + name = "test_com_api_async", + timeout = "moderate", + srcs = [ + "com_api_async_api_test.py", + ], + filesystem = ":filesystem", +) diff --git a/score/mw/com/test/com_api/consumer_async_apis/integration_test/com_api_async_api_test.py b/score/mw/com/test/com_api/consumer_async_apis/integration_test/com_api_async_api_test.py new file mode 100644 index 000000000..17e8c07df --- /dev/null +++ b/score/mw/com/test/com_api/consumer_async_apis/integration_test/com_api_async_api_test.py @@ -0,0 +1,19 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* + + +def test_bigdata_async_exchange(sut): + # Sender runs for 40 cycles, Receiver receives 25 cycles asynchronously + with sut.start_process("./bin/bigdata-producer -n 40", cwd="/opt/bigdata-com-api-async/") as sender_process: + with sut.start_process("./bin/bigdata-consumer-async -n 25", cwd="/opt/bigdata-com-api-async/") as receiver_process: + assert receiver_process.wait_for_exit(timeout=120) == 0 diff --git a/score/mw/com/test/com_api/consumer_sync_apis/BUILD b/score/mw/com/test/com_api/consumer_sync_apis/BUILD new file mode 100644 index 000000000..d2021d517 --- /dev/null +++ b/score/mw/com/test/com_api/consumer_sync_apis/BUILD @@ -0,0 +1,44 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* + +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library") +load("//score/mw/com/test:pkg_application.bzl", "pkg_application") + +rust_binary( + name = "bigdata-consumer", + srcs = ["consumer_app.rs"], + features = ["link_std_cpp_lib"], + visibility = [ + "//score/mw/com/test/com_api:__subpackages__", + ], + deps = [ + "//score/mw/com/impl/rust/com-api/com-api", + "//score/mw/com/test/com_api:bigdata_com_api_gen_rs", + ], +) + +pkg_application( + name = "bigdata-com-api-sync-pkg", + app_name = "bigdata-com-api-sync", + bin = [ + ":bigdata-consumer", + "//score/mw/com/test/com_api/producer_app:bigdata-producer", + ], + etc = [ + "//score/mw/com/test/com_api/etc:config", + "//score/mw/com/test/bigdata:logging.json", + ], + visibility = [ + "//score/mw/com/test/com_api:__subpackages__", + ], +) diff --git a/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs b/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs new file mode 100644 index 000000000..205f74f83 --- /dev/null +++ b/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs @@ -0,0 +1,137 @@ +/******************************************************************************** + * Copyright (c) 2026 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 + ********************************************************************************/ + +//! Consumer (proxy) binary for the BigData com-api SCT. +//! +//! # Usage +//! +//! ``` +//! bigdata-consumer -n +//! ``` +//! +//! * `-n ` — number of `MapApiLanesStamped` samples to receive +//! before exiting (required). +//! +//! The consumer retries service discovery until the producer is available, +//! then subscribes to `map_api_lanes_stamped` and reads exactly `num_cycles` +//! samples before exiting with code 0. + +use bigdata_com_api_gen::BigDataInterface; +use com_api::{ + Builder, FindServiceSpecifier, InstanceSpecifier, LolaRuntimeBuilderImpl, Runtime, + RuntimeBuilder, SampleContainer, ServiceDiscovery, Subscriber, Subscription, +}; +use std::path::Path; +use std::thread; +use std::time::Duration; + +const CONFIG_PATH: &str = "etc/config.json"; +const SERVICE_DISCOVERY_RETRY_MS: u64 = 500; +const MAX_SAMPLES_PER_CALL: usize = 5; + +fn parse_args() -> Result { + let args: Vec = std::env::args().collect(); + let mut args_iter = args.iter().skip(1).peekable(); + while let Some(arg) = args_iter.next() { + if arg == "-n" { + return args_iter + .next() + .and_then(|v| v.parse::().ok()) + .ok_or_else(|| "expected integer after -n".to_owned()); + } + } + Err("-n is required".to_owned()) +} + +fn main() { + let num_cycles = parse_args().unwrap_or_else(|e| { + eprintln!("[bigdata-consumer] ERROR: {e}"); + std::process::exit(1); + }); + + println!( + "[bigdata-consumer] Starting, will receive {} samples", + num_cycles + ); + + // Initialise the Lola runtime. + let mut runtime_builder = LolaRuntimeBuilderImpl::new(); + runtime_builder.load_config(Path::new(CONFIG_PATH)); + let runtime = runtime_builder + .build() + .expect("Failed to build Lola runtime"); + + let instance_specifier = InstanceSpecifier::new("/score/cp60/MapApiLanesStamped") + .expect("Invalid instance specifier"); + + // Retry until the producer has offered the service. + let consumer_builder = loop { + let discovery = runtime.find_service::(FindServiceSpecifier::Specific( + instance_specifier.clone(), + )); + let instances = discovery + .get_available_instances() + .expect("Service discovery failed"); + if let Some(builder) = instances.into_iter().next() { + break builder; + } + println!("[bigdata-consumer] Service not yet available, retrying..."); + thread::sleep(Duration::from_millis(SERVICE_DISCOVERY_RETRY_MS)); + }; + + let consumer = consumer_builder.build().expect("Failed to build consumer"); + + let subscription = consumer + .map_api_lanes_stamped + .subscribe(MAX_SAMPLES_PER_CALL) + .expect("Failed to subscribe to map_api_lanes_stamped"); + + println!( + "[bigdata-consumer] Subscribed, waiting for {} samples", + num_cycles + ); + + let mut received_total: usize = 0; + let mut sample_buf = SampleContainer::new(MAX_SAMPLES_PER_CALL); + + while received_total < num_cycles { + let want = (num_cycles - received_total).min(MAX_SAMPLES_PER_CALL); + match subscription.try_receive(&mut sample_buf, want) { + Ok(0) => { + // No data yet — yield briefly and retry. + thread::sleep(Duration::from_millis(1)); + } + Ok(n) => { + for _ in 0..n { + if let Some(sample) = sample_buf.pop_front() { + println!("[bigdata-consumer] Received sample x={}", sample.x); + } + } + received_total += n; + println!( + "[bigdata-consumer] Progress: {}/{}", + received_total, num_cycles + ); + } + Err(e) => { + eprintln!("[bigdata-consumer] Receive error: {:?}", e); + std::process::exit(1); + } + } + } + + println!( + "[bigdata-consumer] Received all {} samples, exiting", + num_cycles + ); +} diff --git a/score/mw/com/test/com_api/consumer_sync_apis/integration_test/BUILD b/score/mw/com/test/com_api/consumer_sync_apis/integration_test/BUILD new file mode 100644 index 000000000..33b640823 --- /dev/null +++ b/score/mw/com/test/com_api/consumer_sync_apis/integration_test/BUILD @@ -0,0 +1,30 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//quality/integration_testing:integration_testing.bzl", "integration_test") + +pkg_tar( + name = "filesystem", + deps = [ + "//score/mw/com/test/com_api/consumer_sync_apis:bigdata-com-api-sync-pkg", + ], +) + +integration_test( + name = "test_com_api_sync", + timeout = "moderate", + srcs = [ + "com_api_sync_api_test.py", + ], + filesystem = ":filesystem", +) diff --git a/score/mw/com/test/com_api/consumer_sync_apis/integration_test/com_api_sync_api_test.py b/score/mw/com/test/com_api/consumer_sync_apis/integration_test/com_api_sync_api_test.py new file mode 100644 index 000000000..a554bfd4c --- /dev/null +++ b/score/mw/com/test/com_api/consumer_sync_apis/integration_test/com_api_sync_api_test.py @@ -0,0 +1,19 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* + + +def test_bigdata_exchange(sut): + # Sender runs for 30 cycles, Receiver receives 25 cycles + with sut.start_process("./bin/bigdata-producer -n 30", cwd="/opt/bigdata-com-api-sync/") as sender_process: + with sut.start_process("./bin/bigdata-consumer -n 25", cwd="/opt/bigdata-com-api-sync/") as receiver_process: + assert receiver_process.wait_for_exit(timeout=120) == 0 diff --git a/score/mw/com/test/com_api/etc/BUILD b/score/mw/com/test/com_api/etc/BUILD new file mode 100644 index 000000000..206454775 --- /dev/null +++ b/score/mw/com/test/com_api/etc/BUILD @@ -0,0 +1,18 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* + +filegroup( + name = "config", + srcs = ["config.json"], + visibility = ["//:__subpackages__"], +) diff --git a/score/mw/com/test/com_api/etc/config.json b/score/mw/com/test/com_api/etc/config.json new file mode 100644 index 000000000..78b87e091 --- /dev/null +++ b/score/mw/com/test/com_api/etc/config.json @@ -0,0 +1,83 @@ +{ + "serviceTypes": [ + { + "serviceTypeName": "/score/adp/MapApiLanesStamped", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 6432, + "events": [ + { + "eventName": "map_api_lanes_stamped", + "eventId": 1 + }, + { + "eventName": "dummy_data_stamped", + "eventId": 2 + } + ] + } + ] + }, + { + "serviceTypeName": "/score/adp/DummyServiceType", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 6433, + "events": [ + ] + } + ] + } + ], + "serviceInstances": [ + { + "instanceSpecifier": "/score/cp60/MapApiLanesStamped", + "serviceTypeName": "/score/adp/MapApiLanesStamped", + "version": { + "major": 1, + "minor": 0 + }, + "instances": [ + { + "instanceId": 1, + "allowedConsumer": { + "QM": [ + 4002, + 0 + ] + }, + "allowedProvider": { + "QM": [ + 4001, + 0 + ] + }, + "asil-level": "QM", + "binding": "SHM", + "events": [ + { + "eventName": "map_api_lanes_stamped", + "numberOfSampleSlots": 10, + "maxSubscribers": 3 + }, + { + "eventName": "dummy_data_stamped", + "numberOfSampleSlots": 10, + "maxSubscribers": 3 + } + ] + } + ] + } + ] +} diff --git a/score/mw/com/test/com_api/producer_app/BUILD b/score/mw/com/test/com_api/producer_app/BUILD new file mode 100644 index 000000000..dafe4a53d --- /dev/null +++ b/score/mw/com/test/com_api/producer_app/BUILD @@ -0,0 +1,27 @@ +# ******************************************************************************* +# Copyright (c) 2026 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 +# ******************************************************************************* + +load("@rules_rust//rust:defs.bzl", "rust_binary") + +rust_binary( + name = "bigdata-producer", + srcs = ["producer_app.rs"], + features = ["link_std_cpp_lib"], + visibility = [ + "//score/mw/com/test/com_api:__subpackages__", + ], + deps = [ + "//score/mw/com/impl/rust/com-api/com-api", + "//score/mw/com/test/com_api:bigdata_com_api_gen_rs", + ], +) diff --git a/score/mw/com/test/com_api/producer_app/producer_app.rs b/score/mw/com/test/com_api/producer_app/producer_app.rs new file mode 100644 index 000000000..f435a6c03 --- /dev/null +++ b/score/mw/com/test/com_api/producer_app/producer_app.rs @@ -0,0 +1,91 @@ +/******************************************************************************** + * Copyright (c) 2026 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 + ********************************************************************************/ + +//! Producer (skeleton) binary for the BigData com-api SCT. +//! +//! # Usage +//! +//! ``` +//! bigdata-producer [-n ] +//! ``` +//! * `-n ` — number of samples to send before exiting (default: 40). +//! +//! The producer sends incrementing `MapApiLanesStamped` samples until it has sent +//! `num_cycles` samples, then exits with code 0. +//! It sleeps for a short duration between sends. +use std::path::Path; +use std::thread; +use std::time::Duration; + +use bigdata_com_api_gen::{BigDataInterface, MapApiLanesStamped}; +use com_api::{ + Builder, InstanceSpecifier, LolaRuntimeBuilderImpl, Producer, Publisher, Runtime, + RuntimeBuilder, SampleMaybeUninit, SampleMut, +}; + +const CONFIG_PATH: &str = "etc/config.json"; +const DEFAULT_CYCLES: u32 = 40; +const SERVICE_OFFER_DELAY_MS: u64 = 2000; +const SEND_INTERVAL_MS: u64 = 100; + +fn parse_args() -> u32 { + let args: Vec = std::env::args().collect(); + let mut num_cycles = DEFAULT_CYCLES; + let mut iter = args.iter().skip(1); + while let Some(arg) = iter.next() { + if arg == "-n" { + if let Some(val) = iter.next() { + num_cycles = val.parse().unwrap_or(DEFAULT_CYCLES); + } + } + } + num_cycles +} + +fn main() { + let num_cycles = parse_args(); + + println!("[bigdata-producer] Starting with num_cycles={}", num_cycles); + + // Initialise the Lola runtime. + let mut runtime_builder = LolaRuntimeBuilderImpl::new(); + runtime_builder.load_config(Path::new(CONFIG_PATH)); + let runtime = runtime_builder + .build() + .expect("Failed to build Lola runtime"); + + // Create the producer and offer the service. + let instance_specifier = InstanceSpecifier::new("/score/cp60/MapApiLanesStamped") + .expect("Invalid instance specifier"); + // Sleep for a few seconds before offering the service to allow the consumer to start first and demonstrate service discovery retries. + thread::sleep(Duration::from_millis(SERVICE_OFFER_DELAY_MS)); + + let producer_builder = runtime.producer_builder::(instance_specifier); + let producer = producer_builder.build().expect("Failed to build producer"); + let offered = producer.offer().expect("Failed to offer service"); + + println!("[bigdata-producer] Service offered, starting send loop"); + for x in 0..num_cycles { + let uninit = offered + .map_api_lanes_stamped + .allocate() + .expect("Failed to allocate sample"); + let mut sample = MapApiLanesStamped::default(); + sample.x = x; + let ready = uninit.write(sample); + ready.send().expect("Failed to send sample"); + println!("[bigdata-producer] Sent sample x={}", x); + + thread::sleep(Duration::from_millis(SEND_INTERVAL_MS)); + } +} From 43c7515cb47b0c5eabc851feb604dccf71b94b64 Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Fri, 20 Mar 2026 08:36:10 +0530 Subject: [PATCH 2/3] Rust::com Added interface macro for rust gen file * Removed manual implementation of gen trait --- .../com/test/com_api/bigdata_com_api_gen.rs | 93 ++----------------- .../consumer_async_apis/consumer_app.rs | 11 +-- .../consumer_sync_apis/consumer_app.rs | 11 +-- .../test/com_api/producer_app/producer_app.rs | 2 +- 4 files changed, 19 insertions(+), 98 deletions(-) diff --git a/score/mw/com/test/com_api/bigdata_com_api_gen.rs b/score/mw/com/test/com_api/bigdata_com_api_gen.rs index 5fe5a6631..ab76d5e97 100644 --- a/score/mw/com/test/com_api/bigdata_com_api_gen.rs +++ b/score/mw/com/test/com_api/bigdata_com_api_gen.rs @@ -18,10 +18,7 @@ //! and wires them through the com-api `Interface` / `Consumer` / `Producer` //! abstractions instead of the legacy `mw_com::import_interface!` macro. -use com_api::{ - CommData, Consumer, Interface, OfferedProducer, Producer, ProviderInfo, Publisher, Reloc, - Runtime, Subscriber, -}; +use com_api::{interface, CommData, ProviderInfo, Publisher, Reloc, Subscriber}; use core::fmt::Debug; @@ -102,84 +99,10 @@ impl Debug for DummyDataStamped { } } -/// Generated com-api bindings for the BigData interface. -pub struct BigDataInterface {} - -impl Interface for BigDataInterface { - const INTERFACE_ID: &'static str = "BigDataInterface"; - type Consumer = BigDataConsumer; - type Producer = BigDataProducer; -} - -/// Consumer type for the BigData interface. -pub struct BigDataConsumer { - pub map_api_lanes_stamped: R::Subscriber, - pub dummy_data_stamped: R::Subscriber, -} - -impl Consumer for BigDataConsumer { - fn new(instance_info: R::ConsumerInfo) -> Self { - let map_api_lanes_stamped = - R::Subscriber::new("map_api_lanes_stamped_", instance_info.clone()) - .expect("Failed to create map_api_lanes_stamped subscriber"); - let dummy_data_stamped = R::Subscriber::new("dummy_data_stamped_", instance_info) - .expect("Failed to create dummy_data_stamped subscriber"); - BigDataConsumer { - map_api_lanes_stamped, - dummy_data_stamped, - } - } -} - -/// Producer type for the BigData interface. -pub struct BigDataProducer { - _runtime: core::marker::PhantomData, - instance_info: R::ProviderInfo, -} - -impl Producer for BigDataProducer { - type Interface = BigDataInterface; - type OfferedProducer = BigDataOfferedProducer; - - fn new(instance_info: R::ProviderInfo) -> com_api::Result { - Ok(BigDataProducer { - _runtime: core::marker::PhantomData, - instance_info, - }) - } - - fn offer(self) -> com_api::Result { - let map_api_lanes_stamped = - R::Publisher::new("map_api_lanes_stamped_", self.instance_info.clone()) - .expect("Failed to create map_api_lanes_stamped publisher"); - let dummy_data_stamped = - R::Publisher::new("dummy_data_stamped_", self.instance_info.clone()) - .expect("Failed to create dummy_data_stamped publisher"); - self.instance_info.offer_service()?; - Ok(BigDataOfferedProducer { - map_api_lanes_stamped, - dummy_data_stamped, - instance_info: self.instance_info, - }) - } -} - -/// Offered producer type for the BigData interface, returned by `BigDataProducer::offer()`. -pub struct BigDataOfferedProducer { - pub map_api_lanes_stamped: R::Publisher, - pub dummy_data_stamped: R::Publisher, - instance_info: R::ProviderInfo, -} - -impl OfferedProducer for BigDataOfferedProducer { - type Interface = BigDataInterface; - type Producer = BigDataProducer; - - fn unoffer(self) -> com_api::Result { - self.instance_info.stop_offer_service()?; - Ok(BigDataProducer { - _runtime: core::marker::PhantomData, - instance_info: self.instance_info, - }) - } -} +interface!( + interface BigData, { + Id = "BigDataInterface", + map_api_lanes_stamped_: Event, + dummy_data_stamped_: Event, + } +); diff --git a/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs b/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs index 9ea08f716..481a75935 100644 --- a/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs +++ b/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs @@ -20,7 +20,7 @@ //! bigdata-consumer -n //! ``` //! * `-n ` — number of samples to receive before exiting. -//! The consumer subscribes to the producer's `map_api_lanes_stamped` output and +//! The consumer subscribes to the producer's `map_api_lanes_stamped_` output and //! prints the `x` field of each received sample until it has received the specified number of samples, at which point it exits. use bigdata_com_api_gen::BigDataInterface; @@ -68,9 +68,8 @@ async fn main() { let instance_specifier = InstanceSpecifier::new("/score/cp60/MapApiLanesStamped") .expect("Invalid instance specifier"); - let discovery = runtime.find_service::(FindServiceSpecifier::Specific( - instance_specifier.clone(), - )); + let discovery = runtime + .find_service::(FindServiceSpecifier::Specific(instance_specifier)); // Await the producer to become available. let instances = discovery @@ -86,9 +85,9 @@ async fn main() { // Subscribe with a slot buffer large enough for MAX_SAMPLES_PER_CALL. let subscription = consumer - .map_api_lanes_stamped + .map_api_lanes_stamped_ .subscribe(MAX_SAMPLES_PER_CALL) - .expect("Failed to subscribe to map_api_lanes_stamped"); + .expect("Failed to subscribe to map_api_lanes_stamped_"); let mut received_total: usize = 0; let mut sample_buf = SampleContainer::new(MAX_SAMPLES_PER_CALL); diff --git a/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs b/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs index 205f74f83..ad15413d0 100644 --- a/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs +++ b/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs @@ -23,7 +23,7 @@ //! before exiting (required). //! //! The consumer retries service discovery until the producer is available, -//! then subscribes to `map_api_lanes_stamped` and reads exactly `num_cycles` +//! then subscribes to `map_api_lanes_stamped_` and reads exactly `num_cycles` //! samples before exiting with code 0. use bigdata_com_api_gen::BigDataInterface; @@ -76,9 +76,8 @@ fn main() { // Retry until the producer has offered the service. let consumer_builder = loop { - let discovery = runtime.find_service::(FindServiceSpecifier::Specific( - instance_specifier.clone(), - )); + let discovery = runtime + .find_service::(FindServiceSpecifier::Specific(instance_specifier)); let instances = discovery .get_available_instances() .expect("Service discovery failed"); @@ -92,9 +91,9 @@ fn main() { let consumer = consumer_builder.build().expect("Failed to build consumer"); let subscription = consumer - .map_api_lanes_stamped + .map_api_lanes_stamped_ .subscribe(MAX_SAMPLES_PER_CALL) - .expect("Failed to subscribe to map_api_lanes_stamped"); + .expect("Failed to subscribe to map_api_lanes_stamped_"); println!( "[bigdata-consumer] Subscribed, waiting for {} samples", diff --git a/score/mw/com/test/com_api/producer_app/producer_app.rs b/score/mw/com/test/com_api/producer_app/producer_app.rs index f435a6c03..f9834da2d 100644 --- a/score/mw/com/test/com_api/producer_app/producer_app.rs +++ b/score/mw/com/test/com_api/producer_app/producer_app.rs @@ -77,7 +77,7 @@ fn main() { println!("[bigdata-producer] Service offered, starting send loop"); for x in 0..num_cycles { let uninit = offered - .map_api_lanes_stamped + .map_api_lanes_stamped_ .allocate() .expect("Failed to allocate sample"); let mut sample = MapApiLanesStamped::default(); From f88232c62849c680816d109e2b85cbe915ab9670 Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Fri, 20 Mar 2026 09:11:32 +0530 Subject: [PATCH 3/3] Rust::com Added clap crate for parsing the argument * Added clap crate for parsing cmd argument in test app --- .../test/com_api/consumer_async_apis/BUILD | 1 + .../consumer_async_apis/consumer_app.rs | 23 ++++++--------- .../com/test/com_api/consumer_sync_apis/BUILD | 1 + .../consumer_sync_apis/consumer_app.rs | 28 +++++++------------ score/mw/com/test/com_api/producer_app/BUILD | 1 + .../test/com_api/producer_app/producer_app.rs | 21 ++++++-------- 6 files changed, 29 insertions(+), 46 deletions(-) diff --git a/score/mw/com/test/com_api/consumer_async_apis/BUILD b/score/mw/com/test/com_api/consumer_async_apis/BUILD index be647feb5..05b38032b 100644 --- a/score/mw/com/test/com_api/consumer_async_apis/BUILD +++ b/score/mw/com/test/com_api/consumer_async_apis/BUILD @@ -24,6 +24,7 @@ rust_binary( deps = [ "//score/mw/com/impl/rust/com-api/com-api", "//score/mw/com/test/com_api:bigdata_com_api_gen_rs", + "@score_communication_crate_index//:clap", "@score_communication_crate_index//:tokio", ], ) diff --git a/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs b/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs index 481a75935..0dbd3b92e 100644 --- a/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs +++ b/score/mw/com/test/com_api/consumer_async_apis/consumer_app.rs @@ -24,6 +24,7 @@ //! prints the `x` field of each received sample until it has received the specified number of samples, at which point it exits. use bigdata_com_api_gen::BigDataInterface; +use clap::Parser; use com_api::{ Builder, FindServiceSpecifier, InstanceSpecifier, LolaRuntimeBuilderImpl, Runtime, RuntimeBuilder, SampleContainer, ServiceDiscovery, Subscriber, Subscription, @@ -33,25 +34,17 @@ use std::path::Path; const CONFIG_PATH: &str = "etc/config.json"; const MAX_SAMPLES_PER_CALL: usize = 5; -fn parse_args() -> usize { - let args: Vec = std::env::args().collect(); - let mut iter = args.iter().skip(1); - while let Some(arg) = iter.next() { - if arg == "-n" { - if let Some(val) = iter.next() { - if let Ok(n) = val.parse::() { - return n; - } - } - } - } - eprintln!("[bigdata-consumer] ERROR: -n is required"); - std::process::exit(1); +#[derive(Parser)] +struct Args { + /// Number of samples to receive before exiting + #[arg(short = 'n', required = true)] + num_cycles: usize, } #[tokio::main] async fn main() { - let num_cycles = parse_args(); + let args = Args::parse(); + let num_cycles = args.num_cycles; println!( "[bigdata-consumer] Starting, will receive {} samples", diff --git a/score/mw/com/test/com_api/consumer_sync_apis/BUILD b/score/mw/com/test/com_api/consumer_sync_apis/BUILD index d2021d517..cc7133c40 100644 --- a/score/mw/com/test/com_api/consumer_sync_apis/BUILD +++ b/score/mw/com/test/com_api/consumer_sync_apis/BUILD @@ -24,6 +24,7 @@ rust_binary( deps = [ "//score/mw/com/impl/rust/com-api/com-api", "//score/mw/com/test/com_api:bigdata_com_api_gen_rs", + "@score_communication_crate_index//:clap", ], ) diff --git a/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs b/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs index ad15413d0..08267e4c4 100644 --- a/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs +++ b/score/mw/com/test/com_api/consumer_sync_apis/consumer_app.rs @@ -27,6 +27,7 @@ //! samples before exiting with code 0. use bigdata_com_api_gen::BigDataInterface; +use clap::Parser; use com_api::{ Builder, FindServiceSpecifier, InstanceSpecifier, LolaRuntimeBuilderImpl, Runtime, RuntimeBuilder, SampleContainer, ServiceDiscovery, Subscriber, Subscription, @@ -39,25 +40,16 @@ const CONFIG_PATH: &str = "etc/config.json"; const SERVICE_DISCOVERY_RETRY_MS: u64 = 500; const MAX_SAMPLES_PER_CALL: usize = 5; -fn parse_args() -> Result { - let args: Vec = std::env::args().collect(); - let mut args_iter = args.iter().skip(1).peekable(); - while let Some(arg) = args_iter.next() { - if arg == "-n" { - return args_iter - .next() - .and_then(|v| v.parse::().ok()) - .ok_or_else(|| "expected integer after -n".to_owned()); - } - } - Err("-n is required".to_owned()) +#[derive(Parser)] +struct Args { + /// Number of samples to receive before exiting + #[arg(short = 'n', required = true)] + num_cycles: usize, } fn main() { - let num_cycles = parse_args().unwrap_or_else(|e| { - eprintln!("[bigdata-consumer] ERROR: {e}"); - std::process::exit(1); - }); + let args = Args::parse(); + let num_cycles = args.num_cycles; println!( "[bigdata-consumer] Starting, will receive {} samples", @@ -73,11 +65,11 @@ fn main() { let instance_specifier = InstanceSpecifier::new("/score/cp60/MapApiLanesStamped") .expect("Invalid instance specifier"); + let discovery = runtime + .find_service::(FindServiceSpecifier::Specific(instance_specifier)); // Retry until the producer has offered the service. let consumer_builder = loop { - let discovery = runtime - .find_service::(FindServiceSpecifier::Specific(instance_specifier)); let instances = discovery .get_available_instances() .expect("Service discovery failed"); diff --git a/score/mw/com/test/com_api/producer_app/BUILD b/score/mw/com/test/com_api/producer_app/BUILD index dafe4a53d..6304a0e41 100644 --- a/score/mw/com/test/com_api/producer_app/BUILD +++ b/score/mw/com/test/com_api/producer_app/BUILD @@ -23,5 +23,6 @@ rust_binary( deps = [ "//score/mw/com/impl/rust/com-api/com-api", "//score/mw/com/test/com_api:bigdata_com_api_gen_rs", + "@score_communication_crate_index//:clap", ], ) diff --git a/score/mw/com/test/com_api/producer_app/producer_app.rs b/score/mw/com/test/com_api/producer_app/producer_app.rs index f9834da2d..7b4e2e1b7 100644 --- a/score/mw/com/test/com_api/producer_app/producer_app.rs +++ b/score/mw/com/test/com_api/producer_app/producer_app.rs @@ -28,6 +28,7 @@ use std::thread; use std::time::Duration; use bigdata_com_api_gen::{BigDataInterface, MapApiLanesStamped}; +use clap::Parser; use com_api::{ Builder, InstanceSpecifier, LolaRuntimeBuilderImpl, Producer, Publisher, Runtime, RuntimeBuilder, SampleMaybeUninit, SampleMut, @@ -38,22 +39,16 @@ const DEFAULT_CYCLES: u32 = 40; const SERVICE_OFFER_DELAY_MS: u64 = 2000; const SEND_INTERVAL_MS: u64 = 100; -fn parse_args() -> u32 { - let args: Vec = std::env::args().collect(); - let mut num_cycles = DEFAULT_CYCLES; - let mut iter = args.iter().skip(1); - while let Some(arg) = iter.next() { - if arg == "-n" { - if let Some(val) = iter.next() { - num_cycles = val.parse().unwrap_or(DEFAULT_CYCLES); - } - } - } - num_cycles +#[derive(Parser)] +struct Args { + /// Number of samples to send before exiting + #[arg(short = 'n', default_value_t = DEFAULT_CYCLES)] + num_cycles: u32, } fn main() { - let num_cycles = parse_args(); + let args = Args::parse(); + let num_cycles = args.num_cycles; println!("[bigdata-producer] Starting with num_cycles={}", num_cycles);