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 committed Oct 7, 2024
1 parent 39d60b6 commit b27341b
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 3 deletions.
12 changes: 10 additions & 2 deletions 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 All @@ -127,4 +135,4 @@ SubCommandT Arbitrator<CommandT, SubCommandT, VerifierT, VerificationResultT>::g
" applicable options passed the verification step!");
}

} // namespace arbitration_graphs
} // namespace arbitration_graphs
12 changes: 11 additions & 1 deletion test/dummy_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ class DummyBehavior : public Behavior<DummyCommand> {
int loseControlCounter_;
};

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 All @@ -76,4 +86,4 @@ struct DummyResult {
inline std::ostream& operator<<(std::ostream& out, const arbitration_graphs_tests::DummyResult& result) {
out << (result.isOk() ? "is okay" : "is not okay");
return out;
}
}
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 b27341b

Please sign in to comment.