45 using std::unique_ptr;
46 using std::atomic_bool;
47 using std::this_thread::sleep_for;
48 using std::chrono::milliseconds;
56 using lib::query::extractID;
61 const uint MIN_RUNNING_TIME_ms = 20;
66 return MIN_RUNNING_TIME_ms
67 +
rani (MAX_RUNNING_TIME_ms - MIN_RUNNING_TIME_ms);
106 atomic_bool isUp_{
false};
107 atomic_bool didRun_{
false};
108 atomic_bool started_{
false};
109 atomic_bool termRequest_{
false};
110 int running_duration_{0};
111 const int TIME_GOAL{draw_rand_runtime()};
114 unique_ptr<Thread> thread_{};
119 string startSpec (extractID (
"start",spec_));
120 return "true" ==startSpec
121 or
"fail" ==startSpec
122 or
"throw"==startSpec;
129 CHECK (not (isUp_ or started_ or didRun_),
"attempt to start %s twice!",
cStr(*
this));
131 string startSpec (extractID (
"start",spec_));
132 CHECK (not isnil (startSpec));
134 if (
"true"==startSpec)
136 CHECK (not started_);
139 thread_.reset (
new Thread{id_, &MockSys::run,
this, termination});
145 if (
"fail"==startSpec)
148 if (
"throw"==startSpec)
149 throw error::Fatal(
"simulated failure to start the subsystem", LUMIERA_ERROR_TEST);
160 INFO (
test,
"triggerShutdown() --> %s....",
cStr(*
this));
180 run (Subsys::SigTerm termination)
182 string runSpec (extractID (
"run",spec_));
183 CHECK (not isnil (runSpec));
187 isUp_ = (
"true"==runSpec ||
"throw"==runSpec);
188 didRun_ = (
"false"!=runSpec);
195 running_duration_ = TIME_GOAL;
197 INFO (
test,
"thread %s now running....",
cStr(*
this));
199 while (not shouldTerminate())
201 sleep_for (milliseconds{TICK_DURATION_ms});
205 INFO (
test,
"thread %s about to terminate...",
cStr(*
this));
209 if (
"fail" ==runSpec)
return;
210 if (
"true" ==runSpec) termination(0);
211 if (
"throw"==runSpec)
213 Error problemIndicator(
"simulated Problem terminating subsystem",LUMIERA_ERROR_TEST);
217 string problemReport (problemIndicator.
what());
218 termination (&problemReport);
227 return termRequest_ || running_duration_ <= 0;
240 operator string ()
const {
return "MockSys(\""+id_+
"\")"; }
242 bool didRun ()
const {
return didRun_; }
277 singleSubsys_complete_cycle();
278 singleSubsys_start_failure();
279 singleSubsys_emegency_exit();
281 dependentSubsys_complete_cycle();
282 dependentSubsys_start_failure();
287 singleSubsys_complete_cycle()
289 cout <<
"-----singleSubsys_complete_cycle-----\n";
291 MockSys unit (
"one",
"start(true), run(true).");
293 CHECK (not unit.isRunning());
294 CHECK (not unit.didRun());
296 runner.maybeRun (unit);
297 bool emergency = runner.wait();
299 CHECK (not emergency);
300 CHECK (not unit.isRunning());
301 CHECK (unit.didRun());
317 cout <<
"-----singleSubsys_start_failure-----\n";
319 MockSys unit1 (
"U1",
"start(false), run(false).");
320 MockSys unit2 (
"U2",
"start(throw), run(false).");
321 MockSys unit3 (
"U3",
"start(fail), run(false).");
322 MockSys unit4 (
"U4",
"start(true), run(fail)." );
325 runner.maybeRun (unit1);
326 CHECK (not unit1.didRun());
335 CHECK (not unit1.isRunning());
336 CHECK (not unit2.isRunning());
337 CHECK (not unit3.isRunning());
338 CHECK (not unit4.isRunning());
339 CHECK (not unit1.didRun());
340 CHECK (not unit2.didRun());
341 CHECK (not unit3.didRun());
342 CHECK (unit4.didRun());
347 singleSubsys_emegency_exit()
349 cout <<
"-----singleSubsys_emegency_exit-----\n";
351 MockSys unit (
"one",
"start(true), run(throw).");
354 runner.maybeRun (unit);
355 bool emergency = runner.wait();
357 CHECK (emergency ==
true);
358 CHECK (not unit.isRunning());
359 CHECK (unit.didRun());
364 dependentSubsys_complete_cycle()
366 cout <<
"-----dependentSubsys_complete_cycle-----\n";
368 MockSys unit1 (
"U1",
"start(true), run(true).");
369 MockSys unit2 (
"U2",
"start(true), run(true).");
370 MockSys unit3 (
"U3",
"start(true), run(true).");
371 MockSys unit4 (
"U4",
"start(true), run(true).");
372 unit2.depends (unit1);
373 unit4.depends (unit3);
374 unit4.depends (unit1);
375 unit3.depends (unit2);
378 runner.maybeRun (unit4);
379 CHECK (unit1.isRunning());
380 CHECK (unit2.isRunning());
381 CHECK (unit3.isRunning());
382 CHECK (unit4.isRunning());
384 bool emergency = runner.wait();
386 CHECK (not emergency);
387 CHECK (not unit1.isRunning());
388 CHECK (not unit2.isRunning());
389 CHECK (not unit3.isRunning());
390 CHECK (not unit4.isRunning());
391 CHECK (unit1.didRun());
392 CHECK (unit2.didRun());
393 CHECK (unit3.didRun());
394 CHECK (unit4.didRun());
399 dependentSubsys_start_failure()
401 cout <<
"-----dependentSubsys_start_failure-----\n";
403 MockSys unit1 (
"U1",
"start(true), run(true).");
404 MockSys unit2 (
"U2",
"start(true), run(true).");
405 MockSys unit3 (
"U3",
"start(false),run(false).");
406 MockSys unit4 (
"U4",
"start(true), run(true).");
407 unit2.depends (unit1);
408 unit4.depends (unit3);
409 unit4.depends (unit1);
410 unit3.depends (unit2);
414 CHECK ( unit1.isRunning());
415 CHECK ( unit2.isRunning());
416 CHECK (not unit3.isRunning());
419 bool emergency = runner.wait();
421 CHECK (not emergency);
422 CHECK (not unit1.isRunning());
423 CHECK (not unit2.isRunning());
424 CHECK (not unit3.isRunning());
425 CHECK (not unit4.isRunning());
426 CHECK ( unit1.didRun());
427 CHECK ( unit2.didRun());
428 CHECK (not unit3.didRun());
bool start(lumiera::Option &, Subsys::SigTerm termination) override
attempt to bring up this subsystem up.
Dependencies and lifecycle of a partially independent Subsystem of the Application.
Utilities to support working with predicate queries.
const uint TICK_DURATION_ms
the "running" subsystem checks for a shutdown request every XX milliseconds
void triggerShutdown() noexcept override
initiate termination of this subsystem.
CStr cStr(std::string const &rendered)
convenience shortcut: forced conversion to c-String via string.
A simulated "Lumiera Subsystem".
const uint MAX_RUNNING_TIME_ms
limit for the randomly selected duration of subsystem's running phase (milliseconds) ...
inline string literal This is a marker type to indicate that
virtual CStr what() const noexcept override
std::exception interface : yield a diagnostic message
const uint DELAY_FOR_FLOUNDERING_THRAD_ms
due to a shortcoming of this test fixture, a floundering subsystem continues to run for a short time ...
void run(Subsys::SigTerm termination)
executes in a separate thread and simulates a "running" subsystem.
int rani(uint bound=_iBOUND())
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Frontend for handling the Lumiera application commandline arguments.
void singleSubsys_start_failure()
Object Monitor based synchronisation.
Derived specific exceptions within Lumiera's exception hierarchy.
string extractID(Symbol sym, const string &termString)
(preliminary) helper: instead of really parsing and evaluating the terms, just do a regular expressio...
Abstract Base Class for all testcases.
Marker types to indicate a literal string and a Symbol.
Implementation helper for managing execution of a collection of subsystems, which may depend on one a...
Describing dependencies and lifecycle of the application's primary parts.
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
bool shouldStart(lumiera::Option &) override
query application option state to determine if this subsystem should be activated.
lumiera_err lumiera_error(void)
Get and clear current error state.
front-end for handling the commandline arguments.
Convenience front-end to simplify and codify basic thread handling.
bool checkRunningState() noexcept override
whether this subsystem is actually operational.
A collection of frequently used helper functions to support unit testing.
lib::Cmdline dummyArgs("")
dummy options just to be ignored
Lumiera error handling (C++ interface).
A one time N-fold mutual synchronisation barrier.
Manage execution of the independent Subsystems of the Lumiera application.
Lumiera public interface.
A thin convenience wrapper to simplify thread-handling.
Abstraction of the usual int argc, int** argv-Commandline, to be able to treat it as a vector of stri...
Interface and Base definition for all Lumiera Exceptions.
A N-fold synchronisation latch using yield-wait until fulfilment.
#define LUMIERA_ERROR_DEFINE(err, msg)
Definition and initialisation of an error constant.