54 using std::unique_ptr;
55 using std::atomic_bool;
56 using std::this_thread::sleep_for;
57 using std::chrono::milliseconds;
65 using lib::query::extractID;
70 const uint MIN_RUNNING_TIME_ms = 20;
108 atomic_bool isUp_{
false};
109 atomic_bool didRun_{
false};
110 atomic_bool started_{
false};
111 atomic_bool termRequest_{
false};
112 int running_duration_{0};
115 unique_ptr<Thread> thread_{};
120 string startSpec (extractID (
"start",spec_));
121 return "true" ==startSpec
122 or
"fail" ==startSpec
123 or
"throw"==startSpec;
130 CHECK (not (isUp_ or started_ or didRun_),
"attempt to start %s twice!",
cStr(*
this));
132 string startSpec (extractID (
"start",spec_));
133 CHECK (not isnil (startSpec));
135 if (
"true"==startSpec)
137 CHECK (not started_);
140 thread_.reset (
new Thread{id_, &MockSys::run,
this, termination});
146 if (
"fail"==startSpec)
149 if (
"throw"==startSpec)
150 throw error::Fatal(
"simulated failure to start the subsystem", LUMIERA_ERROR_TEST);
161 INFO (
test,
"triggerShutdown() --> %s....",
cStr(*
this));
181 run (Subsys::SigTerm termination)
183 string runSpec (extractID (
"run",spec_));
184 CHECK (not isnil (runSpec));
188 isUp_ = (
"true"==runSpec ||
"throw"==runSpec);
189 didRun_ = (
"false"!=runSpec);
196 running_duration_ = MIN_RUNNING_TIME_ms;
197 running_duration_ += (rand() % (MAX_RUNNING_TIME_ms - MIN_RUNNING_TIME_ms));
199 INFO (
test,
"thread %s now running....",
cStr(*
this));
201 while (not shouldTerminate())
203 sleep_for (milliseconds{TICK_DURATION_ms});
207 INFO (
test,
"thread %s about to terminate...",
cStr(*
this));
211 if (
"fail" ==runSpec)
return;
212 if (
"true" ==runSpec) termination(0);
213 if (
"throw"==runSpec)
215 Error problemIndicator(
"simulated Problem terminating subsystem",LUMIERA_ERROR_TEST);
219 string problemReport (problemIndicator.
what());
220 termination (&problemReport);
229 return termRequest_ || running_duration_ <= 0;
242 operator string ()
const {
return "MockSys(\""+id_+
"\")"; }
244 bool didRun ()
const {
return didRun_; }
278 singleSubsys_complete_cycle();
279 singleSubsys_start_failure();
280 singleSubsys_emegency_exit();
282 dependentSubsys_complete_cycle();
283 dependentSubsys_start_failure();
288 singleSubsys_complete_cycle()
290 cout <<
"-----singleSubsys_complete_cycle-----\n";
292 MockSys unit (
"one",
"start(true), run(true).");
294 CHECK (not unit.isRunning());
295 CHECK (not unit.didRun());
297 runner.maybeRun (unit);
298 bool emergency = runner.wait();
300 CHECK (not emergency);
301 CHECK (not unit.isRunning());
302 CHECK (unit.didRun());
318 cout <<
"-----singleSubsys_start_failure-----\n";
320 MockSys unit1 (
"U1",
"start(false), run(false).");
321 MockSys unit2 (
"U2",
"start(throw), run(false).");
322 MockSys unit3 (
"U3",
"start(fail), run(false).");
323 MockSys unit4 (
"U4",
"start(true), run(fail)." );
326 runner.maybeRun (unit1);
327 CHECK (not unit1.didRun());
336 CHECK (not unit1.isRunning());
337 CHECK (not unit2.isRunning());
338 CHECK (not unit3.isRunning());
339 CHECK (not unit4.isRunning());
340 CHECK (not unit1.didRun());
341 CHECK (not unit2.didRun());
342 CHECK (not unit3.didRun());
343 CHECK (unit4.didRun());
348 singleSubsys_emegency_exit()
350 cout <<
"-----singleSubsys_emegency_exit-----\n";
352 MockSys unit (
"one",
"start(true), run(throw).");
355 runner.maybeRun (unit);
356 bool emergency = runner.wait();
358 CHECK (emergency ==
true);
359 CHECK (not unit.isRunning());
360 CHECK (unit.didRun());
365 dependentSubsys_complete_cycle()
367 cout <<
"-----dependentSubsys_complete_cycle-----\n";
369 MockSys unit1 (
"U1",
"start(true), run(true).");
370 MockSys unit2 (
"U2",
"start(true), run(true).");
371 MockSys unit3 (
"U3",
"start(true), run(true).");
372 MockSys unit4 (
"U4",
"start(true), run(true).");
373 unit2.depends (unit1);
374 unit4.depends (unit3);
375 unit4.depends (unit1);
376 unit3.depends (unit2);
379 runner.maybeRun (unit4);
380 CHECK (unit1.isRunning());
381 CHECK (unit2.isRunning());
382 CHECK (unit3.isRunning());
383 CHECK (unit4.isRunning());
385 bool emergency = runner.wait();
387 CHECK (not emergency);
388 CHECK (not unit1.isRunning());
389 CHECK (not unit2.isRunning());
390 CHECK (not unit3.isRunning());
391 CHECK (not unit4.isRunning());
392 CHECK (unit1.didRun());
393 CHECK (unit2.didRun());
394 CHECK (unit3.didRun());
395 CHECK (unit4.didRun());
400 dependentSubsys_start_failure()
402 cout <<
"-----dependentSubsys_start_failure-----\n";
404 MockSys unit1 (
"U1",
"start(true), run(true).");
405 MockSys unit2 (
"U2",
"start(true), run(true).");
406 MockSys unit3 (
"U3",
"start(false),run(false).");
407 MockSys unit4 (
"U4",
"start(true), run(true).");
408 unit2.depends (unit1);
409 unit4.depends (unit3);
410 unit4.depends (unit1);
411 unit3.depends (unit2);
415 CHECK ( unit1.isRunning());
416 CHECK ( unit2.isRunning());
417 CHECK (not unit3.isRunning());
420 bool emergency = runner.wait();
422 CHECK (not emergency);
423 CHECK (not unit1.isRunning());
424 CHECK (not unit2.isRunning());
425 CHECK (not unit3.isRunning());
426 CHECK (not unit4.isRunning());
427 CHECK ( unit1.didRun());
428 CHECK ( unit2.didRun());
429 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.
#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.
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.