Skip to content

Commit

Permalink
scripting: protect FSM execution and tracing against self-deactivation
Browse files Browse the repository at this point in the history
Signed-off-by: Ruben Smits <ruben.smits@intermodalics.eu>

Conflicts:

	tests/state_test.cpp
  • Loading branch information
snrkiwi committed Oct 8, 2014
1 parent 8d215d3 commit 6537ae7
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 10 deletions.
12 changes: 6 additions & 6 deletions rtt/scripting/StateMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,7 @@ namespace RTT {
if ( this->executeProgram(currentTrans, stepping) == false )
return false;
// done.
TRACE("Finished transition program from '"+ current->getName() + "' to '"+next->getName()+"'" );
TRACE("Finished transition program from '"+ (current ? current->getName() : "(null)") + "' to '"+ ( next ? next->getName() : "(null)")+"'" );
// in stepping mode, delay 'true' one executePending().
if ( stepping ) {
currentProg = currentExit ? currentExit : (currentEntry ? currentEntry : currentRun);
Expand All @@ -1040,7 +1040,7 @@ namespace RTT {
if ( this->executeProgram(currentExit, stepping) == false )
return false;
// done.
TRACE("Finished exit program from '"+ current->getName() + "' (going to '"+ (next ? next->getName() : "(null)") +"')" );
TRACE("Finished exit program from '"+ (current ? current->getName() : "(null)") + "' (going to '"+ (next ? next->getName() : "(null)") +"')" );
// in stepping mode, delay 'true' one executePending().
if ( stepping ) {
currentProg = (currentEntry ? currentEntry : currentRun);
Expand Down Expand Up @@ -1082,7 +1082,7 @@ namespace RTT {
if ( this->executeProgram(currentEntry, stepping) == false )
return false;
// done.
TRACE("Finished entry program of '"+ current->getName() +"'" );
TRACE("Finished entry program of '"+ (current ? current->getName() : "(null)") +"'" );
// in stepping mode, delay 'true' one executePending().
if ( stepping ) {
currentProg = currentRun;
Expand All @@ -1096,7 +1096,7 @@ namespace RTT {
if ( this->executeProgram(currentHandle, stepping) == false )
return false;
// done.
TRACE("Finished handle program of '"+ current->getName() +"'" );
TRACE("Finished handle program of '"+ (current ? current->getName() : "(null)") +"'" );
// in stepping mode, delay 'true' one executePending().
if ( stepping ) {
currentProg = currentRun;
Expand All @@ -1110,7 +1110,7 @@ namespace RTT {
if ( this->executeProgram(currentRun, stepping) == false )
return false;
// done.
TRACE("Finished run program of '"+ current->getName() +"'" );
TRACE("Finished run program of '"+ (current ? current->getName() : "(null)") +"'" );
// in stepping mode, delay 'true' one executePending().
if ( stepping )
return false;
Expand All @@ -1130,7 +1130,7 @@ namespace RTT {
currentProg->step();
else
currentProg->execute();
if ( currentProg->inError() ) {
if ( currentProg && currentProg->inError() ) {
smStatus = Status::error;
smpStatus = nill;
TRACE("Encountered run-time error at line " << this->getLineNumber() );
Expand Down
127 changes: 123 additions & 4 deletions tests/state_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class StateTest
}
void doState(const std::string& name, const std::string& prog, TaskContext*, bool test=true, int runs = 1000 );
void parseState( const std::string& prog, TaskContext*, bool test=true );
void runState(const std::string& name, TaskContext*, bool test=true, int runs = 1000 );
void runState(const std::string& name, TaskContext*, bool test=true, int runs = 1000, bool trace = true );
void checkState( const std::string& name, TaskContext*, bool test=true );
void finishState( std::string const& name, TaskContext*, bool test=true );

Expand Down Expand Up @@ -1539,7 +1539,6 @@ BOOST_AUTO_TEST_CASE( testStateEvents)
this->finishState( "x", tc);
}


BOOST_AUTO_TEST_CASE( testStateLevelEvents)
{
// test event reception in sub states.
Expand Down Expand Up @@ -1674,6 +1673,126 @@ BOOST_AUTO_TEST_CASE( testStateLevelEvents)
this->finishState( "x", tc);
}

BOOST_AUTO_TEST_CASE( testSelfDeactivatingStateMachineinEntry )
{
string prog = string("StateMachine X {\n")
+ " initial state INIT {\n"
+ " transitions {select FINI} \n"
+ " }\n"
+ " final state FINI {\n"
+ " entry{\n"
+ " try scripting.deactivateStateMachine(\"x\")\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "RootMachine X x()\n";
this->parseState( prog, tc );
StateMachinePtr sm = sa->getStateMachine("x");
BOOST_REQUIRE( sm );
// causes deactivation of SM:
runState( "x", tc, false);//without trace
BOOST_CHECK( !sm->isActive() );
// causes deactivation of SM:
runState( "x", tc, true);//with trace
BOOST_CHECK( !sm->isActive() );

}

BOOST_AUTO_TEST_CASE( testSelfDeactivatingStateMachineinRun )
{
string prog = string("StateMachine X {\n")
+ " initial state INIT {\n"
+ " transitions {select FINI} \n"
+ " }\n"
+ " final state FINI {\n"
+ " run{\n"
+ " try scripting.deactivateStateMachine(\"x\")\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "RootMachine X x()\n";
this->parseState( prog, tc );
StateMachinePtr sm = sa->getStateMachine("x");
BOOST_REQUIRE( sm );
// causes deactivation of SM:
runState( "x", tc, true, 1000, false);//without trace
BOOST_CHECK( !sm->isActive() );
// causes deactivation of SM:
runState( "x", tc, true, 1000, true);//with trace
BOOST_CHECK( !sm->isActive() );
}

BOOST_AUTO_TEST_CASE( testSelfDeactivatingStateMachineinHandle )
{
string prog = string("StateMachine X {\n")
+ " initial state INIT {\n"
+ " handle{\n"
+ " try scripting.deactivateStateMachine(\"x\")\n"
+ " }\n"
+ " transition if false == true then select FINI \n"
+ " }\n"
+ " final state FINI {\n"
+ " }\n"
+ "}\n"
+ "RootMachine X x()\n";
this->parseState( prog, tc );
StateMachinePtr sm = sa->getStateMachine("x");
BOOST_REQUIRE( sm );
// causes deactivation of SM:
runState( "x", tc, true, 1000, false);//without trace
BOOST_CHECK( !sm->isActive() );
// causes deactivation of SM:
runState( "x", tc, true, 1000, true);//with trace
BOOST_CHECK( !sm->isActive() );
}

BOOST_AUTO_TEST_CASE( testSelfDeactivatingStateMachineinExit )
{
string prog = string("StateMachine X {\n")
+ " initial state INIT {\n"
+ " exit{\n"
+ " try scripting.deactivateStateMachine(\"x\")\n"
+ " }\n"
+ " transitions {select FINI} \n"
+ " }\n"
+ " final state FINI {\n"
+ " }\n"
+ "}\n"
+ "RootMachine X x()\n";
this->parseState( prog, tc );
StateMachinePtr sm = sa->getStateMachine("x");
BOOST_REQUIRE( sm );
// causes deactivation of SM:
runState( "x", tc, false);//without trace
BOOST_CHECK( !sm->isActive() );
// causes deactivation of SM:
runState( "x", tc, true);//with trace
BOOST_CHECK( !sm->isActive() );
}

BOOST_AUTO_TEST_CASE( testSelfDeactivatingStateMachineinTransition )
{
string prog = string("StateMachine X {\n")
+ " initial state INIT {\n"
+ " transition if true then {\n"
+ " scripting.deactivateStateMachine(\"x\")\n"
+ " }select FINI \n"
+ " }\n"
+ " final state FINI {\n"
+ " }\n"
+ "}\n"
+ "RootMachine X x()\n";
this->parseState( prog, tc );
StateMachinePtr sm = sa->getStateMachine("x");
BOOST_REQUIRE( sm );
// causes deactivation of SM:
runState( "x", tc, true, 1000, false);//without trace
BOOST_CHECK( !sm->isActive() );
// causes deactivation of SM:
runState( "x", tc, true, 1000, true);//with trace
BOOST_CHECK( !sm->isActive() );
}

BOOST_AUTO_TEST_SUITE_END()

void StateTest::doState( const std::string& name, const std::string& prog, TaskContext* tc, bool test, int runs )
Expand Down Expand Up @@ -1709,11 +1828,11 @@ void StateTest::parseState(const std::string& prog, TaskContext* tc, bool test )
}
}

void StateTest::runState(const std::string& name, TaskContext* tc, bool test, int runs )
void StateTest::runState(const std::string& name, TaskContext* tc, bool test, int runs, bool trace )
{
StateMachinePtr sm = sa->getStateMachine(name);
BOOST_REQUIRE( sm );
sm->trace(true);
sm->trace(trace);
OperationCaller<bool(StateMachine*)> act = tc->provides(name)->getOperation("activate");
OperationCaller<bool(StateMachine*)> autom = tc->provides(name)->getOperation("automatic");
BOOST_CHECK( act(sm.get()) );
Expand Down

0 comments on commit 6537ae7

Please sign in to comment.