2008-12-31 05:06:17 +01:00
|
|
|
|
/*
|
|
|
|
|
|
SubsystemRunner(Test) - validate starting and stopping of dependent subsystems
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2017-02-22 01:54:20 +01:00
|
|
|
|
/** @file subsystem-runner-test.cpp
|
2023-10-03 20:38:16 +02:00
|
|
|
|
** The \ref SubsystemRunner_test performs various scenarios
|
2025-04-26 23:59:29 +02:00
|
|
|
|
** regarding start, stop and failure of _Subsystems_. Its primary
|
2023-10-03 20:38:16 +02:00
|
|
|
|
** purpose is to cover the \ref SubsystemRunner.
|
2016-11-03 18:20:10 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
2009-09-29 02:11:34 +02:00
|
|
|
|
#include "lib/test/test-helper.hpp"
|
2008-12-31 05:06:17 +01:00
|
|
|
|
#include "common/subsys.hpp"
|
|
|
|
|
|
#include "common/subsystem-runner.hpp"
|
2009-01-02 10:57:13 +01:00
|
|
|
|
#include "common/option.hpp"
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2009-09-24 23:02:40 +02:00
|
|
|
|
#include "lib/symbol.hpp"
|
2023-10-03 20:38:16 +02:00
|
|
|
|
#include "lib/thread.hpp"
|
|
|
|
|
|
#include "lib/sync-barrier.hpp"
|
2012-12-03 00:18:18 +01:00
|
|
|
|
#include "lib/query-util.hpp"
|
2016-01-07 03:58:29 +01:00
|
|
|
|
#include "lib/format-cout.hpp"
|
2008-12-31 05:06:17 +01:00
|
|
|
|
#include "lib/error.hpp"
|
|
|
|
|
|
#include "lib/util.hpp"
|
2008-12-31 06:56:31 +01:00
|
|
|
|
#include "lib/sync.hpp"
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
#include <memory>
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
|
#include <chrono>
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
using util::isnil;
|
|
|
|
|
|
using test::Test;
|
2012-11-26 01:22:01 +01:00
|
|
|
|
using lib::Literal;
|
2012-12-03 00:18:18 +01:00
|
|
|
|
using lib::query::extractID;
|
2023-10-03 20:38:16 +02:00
|
|
|
|
using lib::Thread;
|
|
|
|
|
|
using std::unique_ptr;
|
|
|
|
|
|
using std::atomic_bool;
|
|
|
|
|
|
using std::this_thread::sleep_for;
|
|
|
|
|
|
using std::chrono::milliseconds;
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lumiera {
|
2009-09-29 02:11:34 +02:00
|
|
|
|
namespace test {
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2009-01-03 13:32:24 +01:00
|
|
|
|
namespace { // private test classes and data...
|
|
|
|
|
|
|
2012-12-03 00:18:18 +01:00
|
|
|
|
using lib::query::extractID;
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
/** limit for the randomly selected duration of
|
|
|
|
|
|
* subsystem's running phase (milliseconds) */
|
2009-01-03 13:32:24 +01:00
|
|
|
|
const uint MAX_RUNNING_TIME_ms = 80;
|
2009-09-29 02:11:34 +02:00
|
|
|
|
const uint MIN_RUNNING_TIME_ms = 20;
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2024-11-13 02:23:23 +01:00
|
|
|
|
inline int
|
|
|
|
|
|
draw_rand_runtime()
|
|
|
|
|
|
{
|
|
|
|
|
|
return MIN_RUNNING_TIME_ms
|
|
|
|
|
|
+ rani (MAX_RUNNING_TIME_ms - MIN_RUNNING_TIME_ms);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-12-31 05:06:17 +01:00
|
|
|
|
/** the "running" subsystem checks for a
|
2009-01-03 13:32:24 +01:00
|
|
|
|
* shutdown request every XX milliseconds */
|
2008-12-31 05:06:17 +01:00
|
|
|
|
const uint TICK_DURATION_ms = 5;
|
|
|
|
|
|
|
2010-02-07 17:31:28 +01:00
|
|
|
|
/** due to a shortcoming of this test fixture,
|
|
|
|
|
|
* a floundering subsystem continues to run for
|
|
|
|
|
|
* a short time after the sync barrier.
|
|
|
|
|
|
* Relevant for singleSubsys_start_failure().
|
|
|
|
|
|
*/
|
|
|
|
|
|
const uint DELAY_FOR_FLOUNDERING_THRAD_ms = 20;
|
|
|
|
|
|
|
2009-01-02 10:57:13 +01:00
|
|
|
|
/** dummy options just to be ignored */
|
2011-02-05 23:53:37 +01:00
|
|
|
|
lib::Cmdline dummyArgs ("");
|
2009-01-02 10:57:13 +01:00
|
|
|
|
lumiera::Option dummyOpt (dummyArgs);
|
|
|
|
|
|
|
2009-01-03 01:11:21 +01:00
|
|
|
|
/** marker for simulated failure exceptions */
|
|
|
|
|
|
LUMIERA_ERROR_DEFINE( TEST, "simulated failure.");
|
2009-01-03 13:32:24 +01:00
|
|
|
|
|
2024-03-16 02:04:47 +01:00
|
|
|
|
using LERR_(LOGIC);
|
|
|
|
|
|
using LERR_(STATE);
|
2009-09-29 02:11:34 +02:00
|
|
|
|
|
2009-01-03 01:11:21 +01:00
|
|
|
|
|
2009-01-02 10:57:13 +01:00
|
|
|
|
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* A simulated "Lumiera Subsystem".
|
2010-02-07 17:31:28 +01:00
|
|
|
|
* It is capable of starting a separate thread, which may terminate regularly
|
|
|
|
|
|
* after a random time, or may fail in various ways. The behaviour is controlled
|
|
|
|
|
|
* by a number of definitions, given at construction in logic predicate notation.
|
2008-12-31 05:06:17 +01:00
|
|
|
|
*/
|
|
|
|
|
|
class MockSys
|
2010-01-21 01:49:56 +01:00
|
|
|
|
: public lumiera::Subsys
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2023-10-03 20:38:16 +02:00
|
|
|
|
const string id_;
|
2009-09-24 23:02:40 +02:00
|
|
|
|
const string spec_;
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
atomic_bool isUp_{false};
|
|
|
|
|
|
atomic_bool didRun_{false};
|
|
|
|
|
|
atomic_bool started_{false};
|
|
|
|
|
|
atomic_bool termRequest_{false};
|
|
|
|
|
|
int running_duration_{0};
|
2024-11-13 02:23:23 +01:00
|
|
|
|
const int TIME_GOAL{draw_rand_runtime()};
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
lib::SyncBarrier barrier_{};
|
|
|
|
|
|
unique_ptr<Thread> thread_{};
|
2010-02-04 18:48:47 +01:00
|
|
|
|
|
2009-01-03 13:32:24 +01:00
|
|
|
|
bool
|
2016-12-12 01:18:19 +01:00
|
|
|
|
shouldStart (lumiera::Option&) override
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2009-09-24 23:02:40 +02:00
|
|
|
|
string startSpec (extractID ("start",spec_));
|
2008-12-31 05:06:17 +01:00
|
|
|
|
return "true" ==startSpec
|
2023-10-03 20:38:16 +02:00
|
|
|
|
or "fail" ==startSpec
|
|
|
|
|
|
or "throw"==startSpec;
|
2008-12-31 05:06:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-01-10 18:01:09 +01:00
|
|
|
|
|
2008-12-31 05:06:17 +01:00
|
|
|
|
bool
|
2016-12-12 01:18:19 +01:00
|
|
|
|
start (lumiera::Option&, Subsys::SigTerm termination) override
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not (isUp_ or started_ or didRun_), "attempt to start %s twice!", cStr(*this));
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2009-09-29 02:00:52 +02:00
|
|
|
|
string startSpec (extractID ("start",spec_));
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not isnil (startSpec));
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
if ("true"==startSpec) //----simulate successful subsystem start
|
2010-01-21 01:49:56 +01:00
|
|
|
|
{
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not started_);
|
2010-02-04 18:48:47 +01:00
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
// start »Subsystem operation« in a dedicated thread....
|
|
|
|
|
|
thread_.reset (new Thread{id_, &MockSys::run, this, termination});
|
|
|
|
|
|
barrier_.sync(); //---run-status handshake
|
2010-02-04 18:48:47 +01:00
|
|
|
|
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (started_);
|
2008-12-31 05:06:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
else
|
2023-10-03 20:38:16 +02:00
|
|
|
|
if ("fail"==startSpec) //---not starting, incorrectly reporting success
|
2009-01-03 01:11:21 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
else
|
2008-12-31 05:06:17 +01:00
|
|
|
|
if ("throw"==startSpec) //---starting flounders
|
2024-03-16 02:04:47 +01:00
|
|
|
|
throw error::Fatal("simulated failure to start the subsystem", LUMIERA_ERROR_TEST);
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2009-09-29 02:00:52 +02:00
|
|
|
|
return started_;
|
2008-12-31 05:06:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2016-12-12 01:18:19 +01:00
|
|
|
|
triggerShutdown () noexcept override
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2009-01-03 04:29:59 +01:00
|
|
|
|
// note: *not* locking here...
|
2008-12-31 05:06:17 +01:00
|
|
|
|
termRequest_ = true;
|
2009-01-03 13:32:24 +01:00
|
|
|
|
|
|
|
|
|
|
INFO (test, "triggerShutdown() --> %s....", cStr(*this));
|
2008-12-31 05:06:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2016-12-12 01:18:19 +01:00
|
|
|
|
checkRunningState () noexcept override
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2009-01-03 04:29:59 +01:00
|
|
|
|
// note: *not* locking here...
|
2008-12-31 05:06:17 +01:00
|
|
|
|
return isUp_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-09-29 02:00:52 +02:00
|
|
|
|
/** executes in a separate thread and
|
|
|
|
|
|
* simulates a "running" subsystem.
|
|
|
|
|
|
* Behaviour determined by run(XX) spec:
|
|
|
|
|
|
* - run(true) : start, run, terminate normally
|
|
|
|
|
|
* - run(throw): start, run, signal abnormal termination
|
|
|
|
|
|
* - run(fail) : set didRun_, but abort, never enter running state
|
|
|
|
|
|
* - run(false): just handshake, but then abort without further action
|
|
|
|
|
|
*/
|
2008-12-31 05:06:17 +01:00
|
|
|
|
void
|
2009-09-29 02:00:52 +02:00
|
|
|
|
run (Subsys::SigTerm termination)
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2009-09-24 23:02:40 +02:00
|
|
|
|
string runSpec (extractID ("run",spec_));
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not isnil (runSpec));
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2010-02-04 18:48:47 +01:00
|
|
|
|
// run-status handshake
|
2010-01-21 01:49:56 +01:00
|
|
|
|
started_ = true;
|
|
|
|
|
|
isUp_ = ("true"==runSpec || "throw"==runSpec);
|
|
|
|
|
|
didRun_ = ("false"!=runSpec); // includes "fail" and "throw"
|
2023-10-03 20:38:16 +02:00
|
|
|
|
|
|
|
|
|
|
// coordinate startup with controlling thread
|
|
|
|
|
|
barrier_.sync();
|
2009-09-29 02:00:52 +02:00
|
|
|
|
|
|
|
|
|
|
if (isUp_) //-------------actually enter running state for some time
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2024-11-13 02:23:23 +01:00
|
|
|
|
running_duration_ = TIME_GOAL; // prepared when creating instance
|
2008-12-31 06:56:31 +01:00
|
|
|
|
|
2009-01-03 13:32:24 +01:00
|
|
|
|
INFO (test, "thread %s now running....", cStr(*this));
|
|
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
while (not shouldTerminate())
|
2010-02-07 02:56:30 +01:00
|
|
|
|
{
|
2023-10-03 20:38:16 +02:00
|
|
|
|
sleep_for (milliseconds{TICK_DURATION_ms});
|
2010-02-07 02:56:30 +01:00
|
|
|
|
running_duration_ -= TICK_DURATION_ms;
|
|
|
|
|
|
}
|
2009-09-29 02:00:52 +02:00
|
|
|
|
|
|
|
|
|
|
INFO (test, "thread %s about to terminate...", cStr(*this));
|
|
|
|
|
|
isUp_ = false;
|
2008-12-31 05:06:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-09-29 02:00:52 +02:00
|
|
|
|
if ("fail" ==runSpec) return; // terminate without further notice
|
|
|
|
|
|
if ("true" ==runSpec) termination(0); // signal regular termination
|
|
|
|
|
|
if ("throw"==runSpec)
|
|
|
|
|
|
{
|
2024-03-16 02:04:47 +01:00
|
|
|
|
Error problemIndicator("simulated Problem terminating subsystem",LUMIERA_ERROR_TEST);
|
2009-09-29 02:00:52 +02:00
|
|
|
|
lumiera_error(); // reset error state....
|
|
|
|
|
|
// Note: in real life this actually
|
|
|
|
|
|
// would be an catched exception!
|
|
|
|
|
|
string problemReport (problemIndicator.what());
|
|
|
|
|
|
termination (&problemReport);
|
|
|
|
|
|
}
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
2009-01-11 12:25:44 +01:00
|
|
|
|
}
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2010-02-07 02:56:30 +01:00
|
|
|
|
shouldTerminate () ///< simulates async termination, either on request or by timing
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
|
|
|
|
|
return termRequest_ || running_duration_ <= 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
MockSys(Literal id, Literal spec)
|
2023-10-03 20:38:16 +02:00
|
|
|
|
: id_(id)
|
|
|
|
|
|
, spec_(spec)
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{ }
|
|
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
~MockSys() { }
|
2008-12-31 06:56:31 +01:00
|
|
|
|
|
|
|
|
|
|
operator string () const { return "MockSys(\""+id_+"\")"; }
|
|
|
|
|
|
|
2009-01-02 10:57:13 +01:00
|
|
|
|
bool didRun () const { return didRun_; }
|
2008-12-31 05:06:17 +01:00
|
|
|
|
};
|
2009-01-03 13:32:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
} // (End) test classes and data....
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-24 23:06:36 +02:00
|
|
|
|
/**********************************************************************//**
|
2008-12-31 05:06:17 +01:00
|
|
|
|
* @test managing start and stop of several dependent "subsystems"
|
|
|
|
|
|
* under various conditions. Using mock-subsystems, which actually
|
|
|
|
|
|
* spawn a thread and finish by themselves and generally behave sane.
|
2009-01-03 13:32:24 +01:00
|
|
|
|
* For each such MockSys, we can define a behaviour pattern, e.g.
|
|
|
|
|
|
* weather the start succeeds and if the run terminates with error.
|
2008-12-31 05:06:17 +01:00
|
|
|
|
*
|
|
|
|
|
|
* @see lumiera::Subsys
|
|
|
|
|
|
* @see lumiera::SubsystemRunner
|
|
|
|
|
|
* @see lumiera::AppState
|
|
|
|
|
|
* @see main.cpp
|
|
|
|
|
|
*/
|
|
|
|
|
|
class SubsystemRunner_test : public Test
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
virtual void
|
2009-01-03 13:32:24 +01:00
|
|
|
|
run (Arg)
|
2008-12-31 05:06:17 +01:00
|
|
|
|
{
|
2024-11-13 02:23:23 +01:00
|
|
|
|
seedRand();
|
2009-01-02 10:57:13 +01:00
|
|
|
|
singleSubsys_complete_cycle();
|
2010-02-07 17:31:28 +01:00
|
|
|
|
singleSubsys_start_failure();
|
2010-02-07 02:56:30 +01:00
|
|
|
|
singleSubsys_emegency_exit();
|
2009-01-03 01:11:21 +01:00
|
|
|
|
|
2010-02-07 02:56:30 +01:00
|
|
|
|
dependentSubsys_complete_cycle();
|
|
|
|
|
|
dependentSubsys_start_failure();
|
2008-12-31 05:06:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-01-02 10:57:13 +01:00
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
singleSubsys_complete_cycle()
|
|
|
|
|
|
{
|
2009-01-03 04:29:59 +01:00
|
|
|
|
cout << "-----singleSubsys_complete_cycle-----\n";
|
|
|
|
|
|
|
2009-01-02 10:57:13 +01:00
|
|
|
|
MockSys unit ("one", "start(true), run(true).");
|
|
|
|
|
|
SubsystemRunner runner(dummyOpt);
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not unit.isRunning());
|
|
|
|
|
|
CHECK (not unit.didRun());
|
2009-01-02 10:57:13 +01:00
|
|
|
|
|
|
|
|
|
|
runner.maybeRun (unit);
|
|
|
|
|
|
bool emergency = runner.wait();
|
|
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not emergency);
|
|
|
|
|
|
CHECK (not unit.isRunning());
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (unit.didRun());
|
2009-01-02 10:57:13 +01:00
|
|
|
|
}
|
2009-01-03 01:11:21 +01:00
|
|
|
|
|
|
|
|
|
|
|
2010-02-07 17:31:28 +01:00
|
|
|
|
/** @note as this test focuses on the SubsystemRunner, the mock subsystem
|
|
|
|
|
|
* is implemented rather simplistic. Especially, there is a race when a
|
|
|
|
|
|
* subsystem is configured to "fail" -- because in this case the starting
|
|
|
|
|
|
* context may go away before the remainder of the subsystem thread has
|
|
|
|
|
|
* executed after the sync() barrier. Especially in this case, no MockSys
|
|
|
|
|
|
* actually starts without failure, and thus the SubsystemRunner::wait()
|
|
|
|
|
|
* has no guarding effect. This can be considered a shortcoming of the
|
|
|
|
|
|
* test fixture; a well behaved subsystem won't just go away...
|
|
|
|
|
|
*/
|
2009-01-03 01:11:21 +01:00
|
|
|
|
void
|
|
|
|
|
|
singleSubsys_start_failure()
|
|
|
|
|
|
{
|
2009-01-03 04:29:59 +01:00
|
|
|
|
cout << "-----singleSubsys_start_failure-----\n";
|
|
|
|
|
|
|
2009-01-03 01:11:21 +01:00
|
|
|
|
MockSys unit1 ("U1", "start(false), run(false).");
|
|
|
|
|
|
MockSys unit2 ("U2", "start(throw), run(false).");
|
|
|
|
|
|
MockSys unit3 ("U3", "start(fail), run(false)."); // simulates incorrect behaviour
|
2009-09-29 02:11:34 +02:00
|
|
|
|
MockSys unit4 ("U4", "start(true), run(fail)." ); // simulates failure immediately after start
|
2009-01-03 01:11:21 +01:00
|
|
|
|
SubsystemRunner runner(dummyOpt);
|
|
|
|
|
|
|
2009-01-10 18:01:09 +01:00
|
|
|
|
runner.maybeRun (unit1); // this one doesn't start at all, which isn't considered an error
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not unit1.didRun());
|
2009-01-10 18:01:09 +01:00
|
|
|
|
|
2009-09-29 02:11:34 +02:00
|
|
|
|
VERIFY_ERROR (TEST, runner.maybeRun (unit2) );
|
|
|
|
|
|
VERIFY_ERROR (LOGIC, runner.maybeRun (unit3) ); // incorrect behaviour trapped
|
|
|
|
|
|
VERIFY_ERROR (LOGIC, runner.maybeRun (unit4) ); // detected that the subsystem didn't come up
|
2009-01-03 01:11:21 +01:00
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
sleep_for (milliseconds{DELAY_FOR_FLOUNDERING_THRAD_ms}); // preempt to allow unit4 to go away
|
2009-01-10 21:35:43 +01:00
|
|
|
|
runner.wait();
|
2009-01-03 01:11:21 +01:00
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not unit1.isRunning());
|
|
|
|
|
|
CHECK (not unit2.isRunning());
|
|
|
|
|
|
CHECK (not unit3.isRunning());
|
|
|
|
|
|
CHECK (not unit4.isRunning());
|
|
|
|
|
|
CHECK (not unit1.didRun());
|
|
|
|
|
|
CHECK (not unit2.didRun());
|
|
|
|
|
|
CHECK (not unit3.didRun());
|
|
|
|
|
|
CHECK (unit4.didRun()); // ...but it failed immediately
|
2009-01-03 01:11:21 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
singleSubsys_emegency_exit()
|
|
|
|
|
|
{
|
2009-01-03 04:29:59 +01:00
|
|
|
|
cout << "-----singleSubsys_emegency_exit-----\n";
|
|
|
|
|
|
|
2009-09-29 02:11:34 +02:00
|
|
|
|
MockSys unit ("one", "start(true), run(throw).");
|
2009-01-03 01:11:21 +01:00
|
|
|
|
SubsystemRunner runner(dummyOpt);
|
|
|
|
|
|
|
|
|
|
|
|
runner.maybeRun (unit);
|
|
|
|
|
|
bool emergency = runner.wait();
|
|
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (emergency == true); // emergency state was propagated
|
|
|
|
|
|
CHECK (not unit.isRunning());
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (unit.didRun());
|
2009-01-03 01:11:21 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
dependentSubsys_complete_cycle()
|
|
|
|
|
|
{
|
2009-01-03 04:29:59 +01:00
|
|
|
|
cout << "-----dependentSubsys_complete_cycle-----\n";
|
|
|
|
|
|
|
2009-01-03 01:11:21 +01:00
|
|
|
|
MockSys unit1 ("U1", "start(true), run(true).");
|
|
|
|
|
|
MockSys unit2 ("U2", "start(true), run(true).");
|
|
|
|
|
|
MockSys unit3 ("U3", "start(true), run(true).");
|
|
|
|
|
|
MockSys unit4 ("U4", "start(true), run(true).");
|
|
|
|
|
|
unit2.depends (unit1);
|
|
|
|
|
|
unit4.depends (unit3);
|
|
|
|
|
|
unit4.depends (unit1);
|
|
|
|
|
|
unit3.depends (unit2);
|
|
|
|
|
|
SubsystemRunner runner(dummyOpt);
|
|
|
|
|
|
|
|
|
|
|
|
runner.maybeRun (unit4);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (unit1.isRunning());
|
|
|
|
|
|
CHECK (unit2.isRunning());
|
|
|
|
|
|
CHECK (unit3.isRunning());
|
|
|
|
|
|
CHECK (unit4.isRunning());
|
2009-01-03 01:11:21 +01:00
|
|
|
|
|
|
|
|
|
|
bool emergency = runner.wait();
|
|
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not emergency);
|
|
|
|
|
|
CHECK (not unit1.isRunning());
|
|
|
|
|
|
CHECK (not unit2.isRunning());
|
|
|
|
|
|
CHECK (not unit3.isRunning());
|
|
|
|
|
|
CHECK (not unit4.isRunning());
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (unit1.didRun());
|
|
|
|
|
|
CHECK (unit2.didRun());
|
|
|
|
|
|
CHECK (unit3.didRun());
|
|
|
|
|
|
CHECK (unit4.didRun());
|
2009-01-03 01:11:21 +01:00
|
|
|
|
}
|
2009-01-03 13:32:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
dependentSubsys_start_failure()
|
|
|
|
|
|
{
|
|
|
|
|
|
cout << "-----dependentSubsys_start_failure-----\n";
|
|
|
|
|
|
|
|
|
|
|
|
MockSys unit1 ("U1", "start(true), run(true).");
|
|
|
|
|
|
MockSys unit2 ("U2", "start(true), run(true).");
|
|
|
|
|
|
MockSys unit3 ("U3", "start(false),run(false)."); // note
|
|
|
|
|
|
MockSys unit4 ("U4", "start(true), run(true).");
|
|
|
|
|
|
unit2.depends (unit1);
|
|
|
|
|
|
unit4.depends (unit3);
|
|
|
|
|
|
unit4.depends (unit1);
|
|
|
|
|
|
unit3.depends (unit2);
|
|
|
|
|
|
SubsystemRunner runner(dummyOpt);
|
|
|
|
|
|
|
2011-06-26 04:02:39 +02:00
|
|
|
|
VERIFY_ERROR (STATE, runner.maybeRun (unit4) ); // failure to bring up prerequisites is detected
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK ( unit1.isRunning());
|
|
|
|
|
|
CHECK ( unit2.isRunning());
|
|
|
|
|
|
CHECK (not unit3.isRunning());
|
2009-01-03 13:32:24 +01:00
|
|
|
|
// shutdown has been triggered for unit4, but may require some time
|
|
|
|
|
|
|
|
|
|
|
|
bool emergency = runner.wait();
|
|
|
|
|
|
|
2023-10-03 20:38:16 +02:00
|
|
|
|
CHECK (not emergency); // no problems with the subsystems actually running...
|
|
|
|
|
|
CHECK (not unit1.isRunning());
|
|
|
|
|
|
CHECK (not unit2.isRunning());
|
|
|
|
|
|
CHECK (not unit3.isRunning());
|
|
|
|
|
|
CHECK (not unit4.isRunning());
|
|
|
|
|
|
CHECK ( unit1.didRun());
|
|
|
|
|
|
CHECK ( unit2.didRun());
|
|
|
|
|
|
CHECK (not unit3.didRun());
|
2009-01-03 13:32:24 +01:00
|
|
|
|
// can't say for sure if unit4 actually did run
|
|
|
|
|
|
}
|
2008-12-31 05:06:17 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2009-01-03 13:32:24 +01:00
|
|
|
|
|
2008-12-31 05:06:17 +01:00
|
|
|
|
|
|
|
|
|
|
/** Register this test class... */
|
|
|
|
|
|
LAUNCHER (SubsystemRunner_test, "function common");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-09-29 02:11:34 +02:00
|
|
|
|
}} // namespace lumiera::test
|