55 using std::unique_ptr;
56 using std::atomic_bool;
57 using std::this_thread::sleep_for;
58 using std::chrono::milliseconds;
66 using lib::query::extractID;
71 const uint MIN_RUNNING_TIME_ms = 20;
91 using error::LERR_(LOGIC);
92 using error::LERR_(STATE);
109 atomic_bool isUp_{
false};
110 atomic_bool didRun_{
false};
111 atomic_bool started_{
false};
112 atomic_bool termRequest_{
false};
113 int running_duration_{0};
116 unique_ptr<Thread> thread_{};
121 string startSpec (extractID (
"start",spec_));
122 return "true" ==startSpec
123 or
"fail" ==startSpec
124 or
"throw"==startSpec;
131 CHECK (not (isUp_ or started_ or didRun_),
"attempt to start %s twice!", cStr(*
this));
133 string startSpec (extractID (
"start",spec_));
134 CHECK (not isnil (startSpec));
136 if (
"true"==startSpec)
138 CHECK (not started_);
141 thread_.reset (
new Thread{id_, &MockSys::run,
this, termination});
147 if (
"fail"==startSpec)
150 if (
"throw"==startSpec)
151 throw error::Fatal(
"simulated failure to start the subsystem", LERR_(TEST));
162 INFO (
test,
"triggerShutdown() --> %s....", cStr(*
this));
182 run (Subsys::SigTerm termination)
184 string runSpec (extractID (
"run",spec_));
185 CHECK (not isnil (runSpec));
189 isUp_ = (
"true"==runSpec ||
"throw"==runSpec);
190 didRun_ = (
"false"!=runSpec);
197 running_duration_ = MIN_RUNNING_TIME_ms;
198 running_duration_ += (rand() % (MAX_RUNNING_TIME_ms - MIN_RUNNING_TIME_ms));
200 INFO (
test,
"thread %s now running....", cStr(*
this));
202 while (not shouldTerminate())
204 sleep_for (milliseconds{TICK_DURATION_ms});
208 INFO (
test,
"thread %s about to terminate...", cStr(*
this));
212 if (
"fail" ==runSpec)
return;
213 if (
"true" ==runSpec) termination(0);
214 if (
"throw"==runSpec)
216 Error problemIndicator(
"simulated Problem terminating subsystem",LERR_(TEST));
220 string problemReport (problemIndicator.
what());
221 termination (&problemReport);
230 return termRequest_ || running_duration_ <= 0;
243 operator string ()
const {
return "MockSys(\""+id_+
"\")"; }
245 bool didRun ()
const {
return didRun_; }
279 singleSubsys_complete_cycle();
280 singleSubsys_start_failure();
281 singleSubsys_emegency_exit();
283 dependentSubsys_complete_cycle();
284 dependentSubsys_start_failure();
289 singleSubsys_complete_cycle()
291 cout <<
"-----singleSubsys_complete_cycle-----\n";
293 MockSys unit (
"one",
"start(true), run(true).");
295 CHECK (not unit.isRunning());
296 CHECK (not unit.didRun());
298 runner.maybeRun (unit);
299 bool emergency = runner.wait();
301 CHECK (not emergency);
302 CHECK (not unit.isRunning());
303 CHECK (unit.didRun());
319 cout <<
"-----singleSubsys_start_failure-----\n";
321 MockSys unit1 (
"U1",
"start(false), run(false).");
322 MockSys unit2 (
"U2",
"start(throw), run(false).");
323 MockSys unit3 (
"U3",
"start(fail), run(false).");
324 MockSys unit4 (
"U4",
"start(true), run(fail)." );
327 runner.maybeRun (unit1);
328 CHECK (not unit1.didRun());
337 CHECK (not unit1.isRunning());
338 CHECK (not unit2.isRunning());
339 CHECK (not unit3.isRunning());
340 CHECK (not unit4.isRunning());
341 CHECK (not unit1.didRun());
342 CHECK (not unit2.didRun());
343 CHECK (not unit3.didRun());
344 CHECK (unit4.didRun());
349 singleSubsys_emegency_exit()
351 cout <<
"-----singleSubsys_emegency_exit-----\n";
353 MockSys unit (
"one",
"start(true), run(throw).");
356 runner.maybeRun (unit);
357 bool emergency = runner.wait();
359 CHECK (emergency ==
true);
360 CHECK (not unit.isRunning());
361 CHECK (unit.didRun());
366 dependentSubsys_complete_cycle()
368 cout <<
"-----dependentSubsys_complete_cycle-----\n";
370 MockSys unit1 (
"U1",
"start(true), run(true).");
371 MockSys unit2 (
"U2",
"start(true), run(true).");
372 MockSys unit3 (
"U3",
"start(true), run(true).");
373 MockSys unit4 (
"U4",
"start(true), run(true).");
374 unit2.depends (unit1);
375 unit4.depends (unit3);
376 unit4.depends (unit1);
377 unit3.depends (unit2);
380 runner.maybeRun (unit4);
381 CHECK (unit1.isRunning());
382 CHECK (unit2.isRunning());
383 CHECK (unit3.isRunning());
384 CHECK (unit4.isRunning());
386 bool emergency = runner.wait();
388 CHECK (not emergency);
389 CHECK (not unit1.isRunning());
390 CHECK (not unit2.isRunning());
391 CHECK (not unit3.isRunning());
392 CHECK (not unit4.isRunning());
393 CHECK (unit1.didRun());
394 CHECK (unit2.didRun());
395 CHECK (unit3.didRun());
396 CHECK (unit4.didRun());
401 dependentSubsys_start_failure()
403 cout <<
"-----dependentSubsys_start_failure-----\n";
405 MockSys unit1 (
"U1",
"start(true), run(true).");
406 MockSys unit2 (
"U2",
"start(true), run(true).");
407 MockSys unit3 (
"U3",
"start(false),run(false).");
408 MockSys unit4 (
"U4",
"start(true), run(true).");
409 unit2.depends (unit1);
410 unit4.depends (unit3);
411 unit4.depends (unit1);
412 unit3.depends (unit2);
416 CHECK ( unit1.isRunning());
417 CHECK ( unit2.isRunning());
418 CHECK (not unit3.isRunning());
421 bool emergency = runner.wait();
423 CHECK (not emergency);
424 CHECK (not unit1.isRunning());
425 CHECK (not unit2.isRunning());
426 CHECK (not unit3.isRunning());
427 CHECK (not unit4.isRunning());
428 CHECK ( unit1.didRun());
429 CHECK ( unit2.didRun());
430 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.
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.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify a statement indeed raises an exception.
const char * cStr(string const &org)
convenience shortcut: conversion to c-String via string.
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.
Simple 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.