From 74d301a16f4fac69360333e1be2b5e2dd6d449f2 Mon Sep 17 00:00:00 2001 From: Alexey Rybalchenko Date: Mon, 15 Jul 2019 14:10:03 +0200 Subject: [PATCH] Implement Device::TransitionTo() and test it --- fairmq/FairMQDevice.cxx | 48 +++++++++++++++++++++++++++-- fairmq/FairMQDevice.h | 2 ++ test/CMakeLists.txt | 1 + test/device/_transitions.cxx | 58 ++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 test/device/_transitions.cxx diff --git a/fairmq/FairMQDevice.cxx b/fairmq/FairMQDevice.cxx index a8202a79..e3a47980 100644 --- a/fairmq/FairMQDevice.cxx +++ b/fairmq/FairMQDevice.cxx @@ -169,15 +169,15 @@ fair::mq::State FairMQDevice::WaitForNextState() fStatesCV.wait_for(lock, chrono::milliseconds(50)); } - auto result = fStates.front(); + auto state = fStates.front(); - if (result == fair::mq::State::Error) { + if (state == fair::mq::State::Error) { throw DeviceStateError("Device transitioned to error state."); } fStates.pop(); - return result; + return state; } void FairMQDevice::WaitForState(fair::mq::State state) @@ -185,6 +185,48 @@ void FairMQDevice::WaitForState(fair::mq::State state) while (WaitForNextState() != state) {} } +void FairMQDevice::TransitionTo(const fair::mq::State s) +{ + using fair::mq::State; + State currentState = GetCurrentState(); + + while (s != currentState) { + switch (currentState) { + case State::Idle: + if (s == State::Exiting) { ChangeState(Transition::End); } + else { ChangeState(Transition::InitDevice); } + break; + case State::InitializingDevice: + ChangeState(Transition::CompleteInit); + break; + case State::Initialized: + if (s == State::Exiting || s == State::Idle) { ChangeState(Transition::ResetDevice); } + else { ChangeState(Transition::Bind); } + break; + case State::Bound: + if (s == State::DeviceReady || s == State::Ready || s == State::Running) { ChangeState(Transition::Connect); } + else { ChangeState(Transition::ResetDevice); } + break; + case State::DeviceReady: + if (s == State::Running || s == State::Ready) { ChangeState(Transition::InitTask); } + else { ChangeState(Transition::ResetDevice); } + break; + case State::Ready: + if (s == State::Running) { ChangeState(Transition::Run); } + else { ChangeState(Transition::ResetTask); } + break; + case State::Running: + ChangeState(Transition::Stop); + break; + default: // Binding, Connecting, InitializingTask, ResettingDevice, ResettingTask + LOG(debug) << "TransitionTo ignoring state: " << currentState; + break; + } + + currentState = WaitForNextState(); + } +} + bool FairMQDevice::ChangeState(const int transition) { return ChangeState(backwardsCompatibilityChangeStateHelper.at(transition)); diff --git a/fairmq/FairMQDevice.h b/fairmq/FairMQDevice.h index a6ab6da2..cc7c9ad3 100644 --- a/fairmq/FairMQDevice.h +++ b/fairmq/FairMQDevice.h @@ -494,6 +494,8 @@ class FairMQDevice void WaitForState(fair::mq::State state); void WaitForState(const std::string& state) { WaitForState(fair::mq::StateMachine::GetState(state)); } + void TransitionTo(const fair::mq::State state); + void SubscribeToStateChange(const std::string& key, std::function callback) { fStateMachine.SubscribeToStateChange(key, callback); } void UnsubscribeFromStateChange(const std::string& key) { fStateMachine.UnsubscribeFromStateChange(key); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 202b1483..adc5858b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -107,6 +107,7 @@ add_testsuite(Device device/_exceptions.cxx device/_error_state.cxx device/_signals.cxx + device/_transitions.cxx LINKS FairMQ DEPENDS testhelper_runTestDevice diff --git a/test/device/_transitions.cxx b/test/device/_transitions.cxx new file mode 100644 index 00000000..a8d718c2 --- /dev/null +++ b/test/device/_transitions.cxx @@ -0,0 +1,58 @@ +/******************************************************************************** + * Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include + +#include + +#include +#include + +namespace +{ + +using namespace std; +using namespace fair::mq; + +void transitionTo(const std::vector& states, int numExpectedStates) +{ + FairMQDevice device; + + thread t([&] { + for (const auto& s : states) { + device.TransitionTo(s); + } + }); + + int numStates = 0; + + device.SubscribeToStateChange("testRunner", [&numStates](State /* state */) { + numStates++; + }); + + device.RunStateMachine(); + + if (t.joinable()) { + t.join(); + } + + LOG(info) << "expected " << numExpectedStates << ", encountered " << numStates << " states"; + EXPECT_EQ(numStates, numExpectedStates); +} + +TEST(Transitions, TransitionTo) +{ + transitionTo({State::Exiting}, 2); + transitionTo({State::InitializingDevice, State::Initialized, State::Exiting}, 6); + transitionTo({State::Initialized, State::Exiting}, 6); + transitionTo({State::DeviceReady, State::Bound, State::Running, State::Exiting}, 24); + transitionTo({State::Ready, State::Exiting}, 14); + transitionTo({State::Running, State::Exiting}, 16); +} + +} // namespace