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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions score/mw/com/test/common_test_resources/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ cc_library(
],
)

cc_library(
name = "send_incrementing_sequence_of_samples",
srcs = [
"send_incrementing_sequence_of_samples.cpp",
],
hdrs = ["send_incrementing_sequence_of_samples.h"],
features = COMPILER_WARNING_FEATURES,
visibility = ["//score/mw/com/test:__subpackages__"],
deps = [
":fail_test",
],
)

cc_library(
name = "fail_test",
srcs = [
Expand Down
10 changes: 10 additions & 0 deletions score/mw/com/test/common_test_resources/proxy_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <utility>

namespace score::mw::com::test
{
Expand All @@ -39,6 +40,15 @@ class ProxyContainer
return *proxy_;
}

Proxy Extract()
{
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(proxy_ != nullptr,
"Proxy was not successfully created! Cannot extract it!");
auto proxy = std::move(*proxy_);
proxy_.reset();
return proxy;
}

private:
std::unique_ptr<typename Proxy::HandleType> handle_{nullptr};
std::mutex proxy_creation_mutex_{};
Expand Down
55 changes: 49 additions & 6 deletions score/mw/com/test/common_test_resources/proxy_event_receiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,73 @@

#include <functional>
#include <iostream>
#include <type_traits>
#include <utility>
#include <variant>

namespace score::mw::com::test
{

/// \brief Helper class which registers a receiveHandler on construction and allows waiting for a
/// certain number of samples to be received. It also checks that the received samples are in the expected order.
template <typename ProxyOrFieldType>
template <typename ProxyOrFieldType, typename StoredCallback = std::monostate>
class ProxyEventReceiver
{
public:
explicit ProxyEventReceiver(ProxyOrFieldType& proxy_event_or_field)
: received_sample_notification_{}, proxy_event_or_field_{proxy_event_or_field}
: received_sample_notification_{}, proxy_event_or_field_{proxy_event_or_field}, stored_callback_{}
{
auto receive_handler = [&received_sample_notification = received_sample_notification_]() {
std::cout << "ProxyEventReceiver: Received event notification" << std::endl;
received_sample_notification.notify();
};
proxy_event_or_field_.SetReceiveHandler(receive_handler);
proxy_event_or_field_.get().SetReceiveHandler(receive_handler);
}

explicit ProxyEventReceiver(ProxyOrFieldType& proxy_event_or_field, StoredCallback callback)
: received_sample_notification_{},
proxy_event_or_field_{proxy_event_or_field},
stored_callback_{std::move(callback)}
{
auto receive_handler = [&received_sample_notification = received_sample_notification_]() {
std::cout << "ProxyEventReceiver: Received event notification" << std::endl;
received_sample_notification.notify();
};
proxy_event_or_field_.get().SetReceiveHandler(receive_handler);
}

~ProxyEventReceiver()
{
proxy_event_or_field_.UnsetReceiveHandler();
proxy_event_or_field_.get().UnsetReceiveHandler();
}

ProxyEventReceiver(const ProxyEventReceiver&) = delete;
ProxyEventReceiver& operator=(const ProxyEventReceiver&) = delete;
ProxyEventReceiver(ProxyEventReceiver&&) = delete;
ProxyEventReceiver& operator=(ProxyEventReceiver&&) = delete;

/// \brief Reattach the receiver to a new event object (e.g. after a proxy move).
/// Updates the internal reference so that GetNewSamples and UnsetReceiveHandler
/// are called on the new event without re-registering the receive handler.
void Reattach(ProxyOrFieldType& new_event)
{
proxy_event_or_field_ = std::ref(new_event);
}

/// \brief Wait for a certain number of samples to be received using the stored callback.
///
/// Only available when constructed with a callback argument.
///
/// \return true if the expected number of samples was received, false if the wait was interrupted by the
/// stop_token.
[[nodiscard]] bool WaitForSamples(const score::cpp::stop_token& stop_token,
const std::size_t num_samples_to_receive)
{
static_assert(!std::is_same<StoredCallback, std::monostate>::value,
"WaitForSamples(stop_token, num_samples) requires a callback to be passed at construction");
return WaitForSamples(stop_token, num_samples_to_receive, stored_callback_);
}

/// \brief Wait for a certain number of samples to be received.
///
/// \return true if the expected number of samples was received, false if the wait was interrupted by the
Expand All @@ -64,7 +100,7 @@ class ProxyEventReceiver
std::size_t received_count{0U};
while (!stop_token.stop_requested())
{
auto get_samples_result = proxy_event_or_field_.GetNewSamples(
auto get_samples_result = proxy_event_or_field_.get().GetNewSamples(
[&get_new_samples_callback](auto sample) {
std::invoke(get_new_samples_callback, std::move(sample));
},
Expand Down Expand Up @@ -132,9 +168,16 @@ class ProxyEventReceiver

private:
score::concurrency::Notification received_sample_notification_;
ProxyOrFieldType& proxy_event_or_field_;
std::reference_wrapper<ProxyOrFieldType> proxy_event_or_field_;
StoredCallback stored_callback_;
};

template <typename ProxyOrFieldType>
ProxyEventReceiver(ProxyOrFieldType&) -> ProxyEventReceiver<ProxyOrFieldType>;

template <typename ProxyOrFieldType, typename CallbackType>
ProxyEventReceiver(ProxyOrFieldType&, CallbackType) -> ProxyEventReceiver<ProxyOrFieldType, CallbackType>;

} // namespace score::mw::com::test

#endif // SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_PROXY_EVENT_RECEIVER_H
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <score/stop_token.hpp>

#include <cstdint>
#include <functional>
#include <iostream>
#include <mutex>
#include <optional>
Expand All @@ -43,7 +44,7 @@ class ProxyEventStateChangeNotifier
condition_variable_.notify_all();
return true;
};
const auto registration_result = proxy_event_.SetSubscriptionStateChangeHandler(state_change_handler);
const auto registration_result = proxy_event_.get().SetSubscriptionStateChangeHandler(state_change_handler);
if (!registration_result.has_value())
{
FailTest("ProxyEventStateChangeNotifier: Failed to register state change handler: ",
Expand All @@ -53,7 +54,17 @@ class ProxyEventStateChangeNotifier

~ProxyEventStateChangeNotifier()
{
proxy_event_.UnsetSubscriptionStateChangeHandler();
proxy_event_.get().UnsetSubscriptionStateChangeHandler();
}

/// \brief Rebind this notifier to a different event after a proxy move.
///
/// Does NOT re-register the subscription state change handler — the handler was already transferred to the
/// new event by the proxy move. Only updates the internal reference so that subsequent GetSubscriptionState
/// calls target the correct event.
void Reattach(ProxyEventType& new_event) noexcept
{
proxy_event_ = std::ref(new_event);
}

ProxyEventStateChangeNotifier(const ProxyEventStateChangeNotifier&) = delete;
Expand All @@ -69,7 +80,7 @@ class ProxyEventStateChangeNotifier
[[nodiscard]] bool WaitForStateChange(const score::cpp::stop_token& stop_token, SubscriptionState desired_state)
{
std::unique_lock lock(mutex_);
const auto current_state = proxy_event_.GetSubscriptionState();
const auto current_state = proxy_event_.get().GetSubscriptionState();
if (current_state == desired_state)
{
return true;
Expand All @@ -90,7 +101,7 @@ class ProxyEventStateChangeNotifier
std::mutex mutex_{};
concurrency::InterruptibleConditionalVariable condition_variable_{};
std::optional<SubscriptionState> last_seen_state_{};
ProxyEventType& proxy_event_;
std::reference_wrapper<ProxyEventType> proxy_event_;
};

} // namespace score::mw::com::test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*******************************************************************************
* 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/common_test_resources/send_incrementing_sequence_of_samples.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/********************************************************************************
* 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_COMMON_TEST_RESOURCES_SEND_INCREMENTING_SEQUENCE_OF_SAMPLES_H
#define SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_SEND_INCREMENTING_SEQUENCE_OF_SAMPLES_H

#include "score/mw/com/test/common_test_resources/fail_test.h"

#include <chrono>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <thread>

namespace score::mw::com::test
{

/// Sends an incrementing sequence of \p number_of_samples_to_send_per_offer samples via
/// \p skeleton.moved_event_, starting at \p initial_value.
template <typename SkeletonT>
void SendIncrementingSequenceOfSamples(SkeletonT& skeleton,
const std::size_t number_of_samples_to_send_per_offer,
const std::uint32_t initial_value)
{
std::cout << "\nProvider: Sending " << number_of_samples_to_send_per_offer << " samples" << std::endl;
for (std::uint32_t i = 0; i < number_of_samples_to_send_per_offer; ++i)
{
auto send_result = skeleton.moved_event_.Send(i + initial_value);
if (!send_result.has_value())
{
FailTest("Provider: Send failed: ", send_result.error());
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}

} // namespace score::mw::com::test

#endif // SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_SEND_INCREMENTING_SEQUENCE_OF_SAMPLES_H
Loading
Loading