Skip to content

Commit

Permalink
Wrap getAndVerifyCommand in try catch block
Browse files Browse the repository at this point in the history
Includes a basic unit test
  • Loading branch information
ll-nick authored and orzechow committed Nov 19, 2024
1 parent d940f67 commit 2624083
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
10 changes: 9 additions & 1 deletion include/arbitration_graphs/internal/arbitrator_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,15 @@ SubCommandT Arbitrator<CommandT, SubCommandT, VerifierT, VerificationResultT>::g
// otherwise we have bestOption == activeBehavior_ which already gained control

// an arbitrator as option might not return a command, if its applicable options fail verification:
const std::optional<SubCommandT> command = getAndVerifyCommand(bestOption, time);
std::optional<SubCommandT> command;
try {
command = getAndVerifyCommand(bestOption, time);
} catch (const std::exception& e) {
VLOG(1) << bestOption->behavior_->name_ << " threw an exception during getAndVerifyCommand(): " << e.what();
bestOption->verificationResult_.reset();
bestOption->behavior_->loseControl(time);
continue;
}

if (command) {
if (activeBehavior_ && bestOption != activeBehavior_) {
Expand Down
10 changes: 10 additions & 0 deletions test/dummy_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ class DummyBehavior : public Behavior<DummyCommand> {
int loseControlCounter_{0};
};

class BrokenDummyBehavior : public DummyBehavior {
public:
BrokenDummyBehavior(const bool invocation, const bool commitment, const std::string& name = "BrokenDummyBehavior")
: DummyBehavior(invocation, commitment, name) {};

DummyCommand getCommand(const Time& time) override {
throw std::runtime_error("BrokenDummyBehavior::getCommand() is broken");
}
};

struct DummyResult {
bool isOk() const {
return isOk_;
Expand Down
51 changes: 51 additions & 0 deletions test/handle_exceptions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <optional>
#include <string>
#include "gtest/gtest.h"

#include "behavior.hpp"
#include "priority_arbitrator.hpp"

#include "dummy_types.hpp"

using namespace arbitration_graphs;
using namespace arbitration_graphs_tests;

class ExceptionHandlingTest : public ::testing::Test {
protected:
BrokenDummyBehavior::Ptr testBehaviorHighPriority =
std::make_shared<BrokenDummyBehavior>(true, true, "HighPriority");
DummyBehavior::Ptr testBehaviorLowPriority = std::make_shared<DummyBehavior>(true, true, "LowPriority");

Time time{Clock::now()};
};

TEST_F(ExceptionHandlingTest, HandleException) {
using OptionFlags = PriorityArbitrator<DummyCommand>::Option::Flags;

PriorityArbitrator<DummyCommand> testPriorityArbitrator;

testPriorityArbitrator.addOption(testBehaviorHighPriority, OptionFlags::NO_FLAGS);
testPriorityArbitrator.addOption(testBehaviorLowPriority, OptionFlags::NO_FLAGS);

ASSERT_TRUE(testPriorityArbitrator.checkInvocationCondition(time));

testPriorityArbitrator.gainControl(time);

// Since the high priority behavior is broken, we should get the low priority behavior as fallback
EXPECT_EQ("LowPriority", testPriorityArbitrator.getCommand(time));
EXPECT_FALSE(testPriorityArbitrator.options().at(0)->verificationResult_.cached(time));
ASSERT_TRUE(testPriorityArbitrator.options().at(1)->verificationResult_.cached(time));

EXPECT_TRUE(testPriorityArbitrator.options().at(1)->verificationResult_.cached(time)->isOk());

testPriorityArbitrator.loseControl(time);

testBehaviorLowPriority->invocationCondition_ = false;
ASSERT_TRUE(testPriorityArbitrator.checkInvocationCondition(time));

testPriorityArbitrator.gainControl(time);

// With no fallback, there is no option to call even if the invocation condition is true
EXPECT_THROW(testPriorityArbitrator.getCommand(time), NoApplicableOptionPassedVerificationError);
}

0 comments on commit 2624083

Please sign in to comment.