Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -170,30 +170,62 @@ class BasicLmControlImpl final : public ILmControl
}
}

score::Result<void> activate_run_target(RunTargetName runTargetName, bool force) override
/*
Not implemented on the daemon side yet.

score::Result<void> queue_run_target(RunTargetName runTargetName) override
{
auto* const proxy = connectedProxy();
if (proxy == nullptr)
{
return score::MakeUnexpected(ExecErrc::kCommunicationError);
}

LM_LOG_DEBUG() << "LmControl: queue_run_target:" << runTargetName;

const ActivateRunTargetRequest request{runTargetName, ActivationMode::kQueued};

const score::Result<MethodResultPtr<ActivateRunTargetResponse>> result = proxy->activate_run_target(request);
if (!result.has_value())
{
LM_LOG_ERROR() << "LmControl: queue_run_target: proxy method call failed with error:" << result.error();
return score::MakeUnexpected(ExecErrc::kCommunicationError);
}

const auto& response = *result.value();
if (response.status == RequestStatus::kRejected)
{
LM_LOG_DEBUG() << "LmControl: queue_run_target: rejected by LM with code" << response.rejection_reason;
return score::MakeUnexpected(response.rejection_reason);
}

return {};
}
*/

score::Result<void> force_run_target(RunTargetName runTargetName) override
{
auto* const proxy = connectedProxy();
if (proxy == nullptr)
{
return score::MakeUnexpected(ExecErrc::kCommunicationError);
}

LM_LOG_DEBUG() << "LmControl: activate_run_target:" << runTargetName << " force=" << force;
LM_LOG_DEBUG() << "LmControl: force_run_target:" << runTargetName;

const ActivateRunTargetRequest request{
runTargetName, force ? ActivationMode::kForced : ActivationMode::kQueued};
const ActivateRunTargetRequest request{runTargetName, ActivationMode::kForced};

const score::Result<MethodResultPtr<ActivateRunTargetResponse>> result = proxy->activate_run_target(request);
if (!result.has_value())
{
LM_LOG_ERROR() << "LmControl: activate_run_target: proxy method call failed with error:" << result.error();
LM_LOG_ERROR() << "LmControl: force_run_target: proxy method call failed with error:" << result.error();
return score::MakeUnexpected(ExecErrc::kCommunicationError);
}

const auto& response = *result.value();
if (response.status == RequestStatus::kRejected)
{
LM_LOG_DEBUG() << "LmControl: activate_run_target: rejected by LM with code" << response.rejection_reason;
LM_LOG_DEBUG() << "LmControl: force_run_target: rejected by LM with code" << response.rejection_reason;
return score::MakeUnexpected(response.rejection_reason);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,17 +359,23 @@ TEST_F(LmControlUT, MethodsFailWhileNotYetConnected)
{
RecordProperty(
"Description",
"Before the service is discovered, activate_run_target and get_active_run_target return "
"Before the service is discovered, queue_run_target, force_run_target and get_active_run_target return "
"kCommunicationError without issuing any proxy calls.");

EXPECT_CALL(mock_, ActivateRunTarget(_)).Times(0);
EXPECT_CALL(mock_, GetActiveRunTarget()).Times(0);

auto sut = MakeLmControl();

auto activate = sut->activate_run_target("Running", false);
ASSERT_FALSE(activate.has_value());
EXPECT_EQ(activate.error(), ExecErrc::kCommunicationError);
/*
auto queue = sut->queue_run_target("Running");
ASSERT_FALSE(queue.has_value());
EXPECT_EQ(queue.error(), ExecErrc::kCommunicationError);
*/

auto force = sut->force_run_target("Running");
ASSERT_FALSE(force.has_value());
EXPECT_EQ(force.error(), ExecErrc::kCommunicationError);

auto get = sut->get_active_run_target();
ASSERT_FALSE(get.has_value());
Expand Down Expand Up @@ -516,13 +522,13 @@ TEST_F(LmControlUT, StopFindServiceFailureOnDestructionIsTolerated)
}

// ---------------------------------------------------------------------------
// activate_run_target
// queue_run_target
// ---------------------------------------------------------------------------

TEST_F(LmControlUT, ActivateForwardsNameAndQueuedModeByDefault)
/*
TEST_F(LmControlUT, QueueForwardsNameAndUsesQueue)
{
RecordProperty(
"Description", "activate_run_target forwards the run target name and defaults to queued activation mode.");
RecordProperty("Description", "queue_run_target forwards the run target name and uses the queued activation mode.");

auto sut = MakeConnected();

Expand All @@ -533,46 +539,82 @@ TEST_F(LmControlUT, ActivateForwardsNameAndQueuedModeByDefault)
Field(&ActivateRunTargetRequest::mode, ActivationMode::kQueued))))
.WillOnce(Return(Accepted()));

// Through the interface: that is where the force=false default lives.
ILmControl& lm_control = *sut;
EXPECT_TRUE(lm_control.activate_run_target("Driving").has_value());
EXPECT_TRUE(lm_control.queue_run_target("Driving").has_value());
}

TEST_F(LmControlUT, QueueRejectionSurfacesRejectionReason)
{
RecordProperty("Description", "A rejected queue_run_target surfaces the rejection reason as the returned error.");

auto sut = MakeConnected();

EXPECT_CALL(mock_, ActivateRunTarget(_))
.WillOnce(Return(ActivateRunTargetResponse{RequestStatus::kRejected, ExecErrc::kRequestQueueIsFull}));

auto result = sut->queue_run_target("Driving");
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), ExecErrc::kRequestQueueIsFull);
}

TEST_F(LmControlUT, ActivateForcedMapsToForcedMode)
TEST_F(LmControlUT, QueueTransportFailureReturnsCommunicationError)
{
RecordProperty("Description", "activate_run_target with force=true maps to forced activation mode.");
RecordProperty("Description", "A transport failure during queue_run_target is reported as kCommunicationError.");

auto sut = MakeConnected();

EXPECT_CALL(mock_, ActivateRunTarget(Field(&ActivateRunTargetRequest::mode, ActivationMode::kForced)))
EXPECT_CALL(mock_, ActivateRunTarget(_)).WillOnce(Return(score::MakeUnexpected(ExecErrc::kFailed)));

auto result = sut->queue_run_target("Driving");
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), ExecErrc::kCommunicationError);
}
*/

// ---------------------------------------------------------------------------
// force_run_target
// ---------------------------------------------------------------------------

TEST_F(LmControlUT, ForceForwardsNameAndUsesForce)
{
RecordProperty("Description", "force_run_target forwards the run target name and uses the forced activation mode.");

auto sut = MakeConnected();

EXPECT_CALL(
mock_,
ActivateRunTarget(AllOf(
Field(&ActivateRunTargetRequest::run_target_name, RunTargetName{"Driving"}),
Field(&ActivateRunTargetRequest::mode, ActivationMode::kForced))))
.WillOnce(Return(Accepted()));

EXPECT_TRUE(sut->activate_run_target("Driving", /*force=*/true).has_value());
ILmControl& lm_control = *sut;
EXPECT_TRUE(lm_control.force_run_target("Driving").has_value());
}

TEST_F(LmControlUT, ActivateRejectionSurfacesRejectionReason)
TEST_F(LmControlUT, ForceRejectionSurfacesRejectionReason)
{
RecordProperty("Description", "A rejected activation surfaces the rejection reason as the returned error.");
RecordProperty("Description", "A rejected force_run_target surfaces the rejection reason as the returned error.");

auto sut = MakeConnected();

EXPECT_CALL(mock_, ActivateRunTarget(_))
.WillOnce(Return(ActivateRunTargetResponse{RequestStatus::kRejected, ExecErrc::kRequestQueueIsFull}));

auto result = sut->activate_run_target("Driving", false);
auto result = sut->force_run_target("Driving");
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), ExecErrc::kRequestQueueIsFull);
}

TEST_F(LmControlUT, ActivateTransportFailureReturnsCommunicationError)
TEST_F(LmControlUT, ForceTransportFailureReturnsCommunicationError)
{
RecordProperty("Description", "A transport failure during activate_run_target is reported as kCommunicationError.");
RecordProperty("Description", "A transport failure during force_run_target is reported as kCommunicationError.");

auto sut = MakeConnected();

EXPECT_CALL(mock_, ActivateRunTarget(_)).WillOnce(Return(score::MakeUnexpected(ExecErrc::kFailed)));

auto result = sut->activate_run_target("Driving", false);
auto result = sut->force_run_target("Driving");
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), ExecErrc::kCommunicationError);
}
Expand Down
35 changes: 27 additions & 8 deletions score/launch_manager/src/lm_control/src/ilm_control.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,15 @@ class ILmControl
///
/// Posts the request into the Launch Manager's fixed-capacity FIFO queue
/// and returns as soon as the request is accepted. The Launch Manager
/// executes activations one at a time in FIFO order. Completion is
/// notified asynchronously via the callback registered with
/// register_run_target_activation_callback().
/// executes activations one at a time in FIFO order.
///
/// If the queue is full, kRequestQueueIsFull is returned immediately
/// and the request is discarded.
///
/// Completion is notified asynchronously via the callback registered with
/// register_run_target_activation_callback().
///
/// @param[in] runTargetName Name of a Run Target configured in the Launch Manager.
/// @param[in] force If false (default), the request is queued behind any
/// in-progress activation and executed afterwards.
/// If true, any in-progress activation is cancelled, the
/// queue is cleared, and this activation starts immediately.
///
/// @returns void when the Launch Manager accepted the request.
///
Expand All @@ -128,7 +126,28 @@ class ILmControl
/// @error kRunTargetDoesntExist Name of the requested Run Target does not exist in current configuration.
/// @error kCommunicationError Connection with Launch Manager could not be established and request cannot be
/// sent.
virtual score::Result<void> activate_run_target(RunTargetName runTargetName, bool force = false) = 0;
/*
Not implemented on the daemon side yet.

virtual score::Result<void> queue_run_target(RunTargetName runTargetName) = 0;
*/

/// @brief Request Run Target activation.
///
/// Cancels any previously queued activations, and immediately begins
/// switching to the specified run target.
///
/// Completion is notified asynchronously via the callback registered with
/// register_run_target_activation_callback().
///
/// @param[in] runTargetName Name of a Run Target configured in the Launch Manager.
///
/// @returns void when the Launch Manager accepted the request.
///
/// @error kRunTargetDoesntExist Name of the requested Run Target does not exist in current configuration.
/// @error kCommunicationError Connection with Launch Manager could not be established and request cannot be
/// sent.
virtual score::Result<void> force_run_target(RunTargetName runTargetName) = 0;

/// @brief Register a callback invoked whenever Launch Manager finishes a Run Target activation.
///
Expand Down
Loading