Lumiera  0.pre.03
»edit your freedom«
scheduler-activity-test.cpp
Go to the documentation of this file.
1 /*
2  SchedulerActivity(Test) - verify activities processed in the scheduler
3 
4  Copyright (C) Lumiera.org
5  2023, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
28 #include "lib/test/run.hpp"
29 #include "lib/test/test-helper.hpp"
30 #include "activity-detector.hpp"
32 #include "vault/real-clock.hpp"
33 #include "lib/time/timevalue.hpp"
34 #include "lib/format-cout.hpp"
35 
36 
37 using test::Test;
38 using lib::time::Time;
39 using lib::time::FSecs;
40 
41 
42 namespace vault{
43 namespace gear {
44 namespace test {
45 
46 
47 
48  /*****************************************************************/
54  {
55 
56  virtual void
57  run (Arg)
58  {
59  simpleUsage();
60 
69 
70  termBuilder();
71  dispatchChain();
72 
77  }
78 
79 
81  void
83  {
84  // Activities are »POD with constructor«
86  CHECK (start.verb_ == Activity::WORKSTART);
87  CHECK (start.next == nullptr);
88  CHECK (start.data_.timing.instant == Time::NEVER);
89  CHECK (start.data_.timing.quality == 0);
90 
91  // use the ActivityDetector for test instrumentation...
92  ActivityDetector detector;
93 
94  // Activities can be invoked within an ExecutionContext
95  Time now = RealClock::now();
96  start.activate (now, detector.executionCtx);
97 
98  // In this case, activation causes invocation of λ-work on the context
99  CHECK (detector.verifyInvocation("CTX-work").arg(now, 0));
100 
101 // cout << detector.showLog()<<endl; // HINT: use this for investigation...
102  }
103 
104 
105 
113  void
115  {
116  Activity chain;
117  Activity post{Time{0,11}, Time{0,22}, &chain};
118  CHECK (chain.is (Activity::TICK));
119  CHECK (post .is (Activity::POST));
120  CHECK (Time(0,11) == post.data_.timeWindow.life);
121  CHECK (Time(0,22) == post.data_.timeWindow.dead);
122  CHECK ( & chain == post.next);
123 
124  ActivityDetector detector;
125  Time tt{5,5};
126  post.activate (tt, detector.executionCtx);
127 
128  CHECK (detector.verifyInvocation("CTX-post").arg("11.000","22.000", "Act(POST", "≺test::CTX≻"));
129  }
130 
131 
132 
138  void
140  {
141  ActivityDetector detector;
142 
143  uint64_t x1=rand(), x2=rand();
144  Time nomTime = lib::test::randTime();
145  Activity feed{x1,x2};
146  Activity feed2{x1+1,x1+2};
147  feed.next = &feed2;
148  Activity invoke{detector.buildMockJobFunctor("job"), nomTime, feed};
149 
150  Time realTime = RealClock::now();
151  CHECK (activity::PASS == invoke.activate (realTime, detector.executionCtx));
152 
153  CHECK (detector.verifyInvocation ("job").arg(nomTime, x1));
154  }
155 
156 
157 
168  void
170  {
171  Activity chain;
172  Activity notify{&chain};
173 
174  ActivityDetector detector;
175  Time tt{111,11};
176  notify.activate (tt, detector.executionCtx);
177  CHECK (detector.verifyInvocation("CTX-post").arg("11.111", Time::NEVER, "Act(TICK", "≺test::CTX≻"));
178 
179  detector.incrementSeq();
180  // now we use a `GATE` as target
181  Time ts{333,33};
182  Time td{555,55};
183  Activity gate{1,td};
184  notify.data_.notification.target = &gate;
185  notify.data_.notification.timing = ts; // start time hint can be packaged into the notification
186 
187  notify.activate (tt, detector.executionCtx);
188  CHECK (detector.verifySeqIncrement(1)
189  .beforeInvocation("CTX-post").arg("33.333", "55.555", "Act(GATE", "≺test::CTX≻"));
190  // NOTE: △△△ start △△△ deadline
191  }
192 
193 
194 
199  void
201  {
202  Activity chain;
203  Activity gate{0};
204  gate.next = &chain;
205 
206  ActivityDetector detector;
207  Activity& wiring = detector.buildGateWatcher (gate);
208 
209  Time tt{333,33};
210  CHECK (activity::PASS == wiring.activate (tt, detector.executionCtx));
211  CHECK (detector.verifyInvocation("tap-GATE").arg("33.333 ⧐ Act(GATE"));
212  }
213 
214 
215 
219  void
221  {
222  Activity chain;
223  Activity gate{0, Time{333,33}};
224  gate.next = &chain;
225 
226  ActivityDetector detector;
227  Activity& wiring = detector.buildGateWatcher (gate);
228 
229  Time t1{330,33}; // still before the deadline
230  Time t2{333,33}; // exactly at deadline => rejected
231  Time t3{335,33}; // after the deadline => rejected
232 
233  CHECK (activity::PASS == wiring.activate (t1, detector.executionCtx));
234  CHECK (detector.verifyInvocation("tap-GATE").arg("33.330 ⧐ Act(GATE").seq(0));
235 
236  detector.incrementSeq();
237  CHECK (activity::SKIP == wiring.activate (t2, detector.executionCtx));
238  CHECK (detector.verifyInvocation("tap-GATE").arg("33.333 ⧐ Act(GATE").seq(1));
239 
240  detector.incrementSeq();
241  CHECK (activity::SKIP == wiring.activate (t3, detector.executionCtx));
242  CHECK (detector.verifyInvocation("tap-GATE").arg("33.335 ⧐ Act(GATE").seq(2));
243  }
244 
245 
246 
254  void
256  {
257  Activity chain;
258  Activity gate{23};
259  gate.next = &chain;
260 
261  ActivityDetector detector;
262  Activity& wiring = detector.buildGateWatcher (gate);
263 
264  Time tt{333,33};
265  CHECK (activity::SKIP == wiring.activate (tt, detector.executionCtx));
266  CHECK (23 == gate.data_.condition.rest); // prerequisite-count not altered
267 
268  CHECK (detector.verifyInvocation("tap-GATE").arg("33.333 ⧐ Act(GATE"));
269  }
270 
271 
272 
280  void
282  {
283  Activity chain;
284  Activity gate{23};
285  gate.next = &chain;
286 
287  ActivityDetector detector;
288  Activity& entrance = detector.buildGateWatcher (gate);
289 
290  Time tt{333,33};
291  CHECK (activity::SKIP == entrance.dispatch (tt, detector.executionCtx));
292  CHECK (22 == gate.data_.condition.rest); // prerequisite-count decremented
293 
294  CHECK (detector.verifyInvocation("tap-GATE").arg("33.333 --notify-↯> Act(GATE"));
295  }
296 
297 
298 
309  void
311  {
312  Time tt{333,33};
313  Time td{555,55};
314 
315  Activity chain;
316  Activity gate{1,td};
317  gate.next = &chain;
318  // Conditionals in the gate block invocations
319  CHECK (gate.data_.condition.isHold());
320  CHECK (gate.data_.condition.rest == 1);
321  CHECK (gate.data_.condition.dead == td);
322 
323  ActivityDetector detector;
324  Activity& entrance = detector.buildGateWatcher (gate);
325 
326  // an attempt to activate blocks (returning SKIP, nothing else happens)
327  CHECK (activity::SKIP == entrance.activate (tt, detector.executionCtx));
328  CHECK (1 == gate.data_.condition.rest); // unchanged (and locked)...
329  CHECK (detector.verifyInvocation("tap-GATE").arg("33.333 ⧐ Act(GATE"));
330 
331  detector.incrementSeq();
332  // Gate receives a notification from some prerequisite Activity
333  CHECK (activity::PASS == entrance.dispatch(tt, detector.executionCtx));
334  CHECK (0 == gate.data_.condition.rest); // condition has been decremented...
335 
336  CHECK (detector.verifyInvocation("tap-GATE").seq(0).arg("33.333 ⧐ Act(GATE")
337  .beforeInvocation("tap-GATE").seq(1).arg("33.333 --notify-↯> Act(GATE"));
338  CHECK (gate.data_.condition.dead == Time::MIN);
339 
340  detector.incrementSeq();
341  Time ttt{444,44};
342  // when another activation happens later, it is blocked to prevent double activation
343  CHECK (activity::SKIP == entrance.activate (ttt, detector.executionCtx));
344  CHECK (detector.verifyInvocation("tap-GATE").seq(2).arg("44.444 ⧐ Act(GATE"));
345  CHECK (detector.ensureNoInvocation("CTX-post").seq(2)
346  .afterInvocation("tap-GATE").seq(2));
347  CHECK (gate.data_.condition.dead == Time::MIN);
348 
349  detector.incrementSeq();
350  // even a further notification has no effect now....
351  CHECK (activity::SKIP == entrance.dispatch (ttt, detector.executionCtx));
352  // conditionals were not touched:
353  CHECK (gate.data_.condition.dead == Time::MIN);
354  CHECK (gate.data_.condition.rest == 0);
355  // the log shows the further notification (at Seq=3) but no dispatch happens anymore
356  CHECK (detector.verifySeqIncrement(3)
357  .beforeInvocation("tap-GATE").seq(3).arg("44.444 --notify-↯> Act(GATE"));
358 
359 // cout << detector.showLog()<<endl; // HINT: use this for investigation...
360  }
361 
362 
363 
370  void
372  {
373  ActivityDetector detector;
374 
375  BlockFlowAlloc bFlow;
376  ActivityLang activityLang{bFlow};
377 
378  Time start{0,1};
379  Time dead{0,10};
380  Activity* act{nullptr};
381  {
382  auto term = activityLang.buildCalculationJob (detector.buildMockJob(), start,dead);
383 
384  act = & term.post();
385  }// NOTE: generated Activity chain remains valid after term goes out of scope
386 
387  // Values reported for the BlockFlow allocator look sane...
388  CHECK (watch(bFlow).cntElm() == 7); // POST, GATE, WORKSTART, INVOKE, FEED, FEED, WORKSTOP
389  CHECK (watch(bFlow).cntEpochs() == 1); // all placed into a single epoch...
390  CHECK (watch(bFlow).find(*act) > dead); // which terminates shortly after the given deadline
391  CHECK (watch(bFlow).find(*act) < dead+Time(500,0));
392 
393  // Time window parameters have been included
394  CHECK (act->is (Activity::POST));
395  CHECK (start == act->data_.timeWindow.life);
396  CHECK (dead == act->data_.timeWindow.dead);
397 
398  // sane wiring, leading to an INVOCATE eventually
399  while (not act->is (Activity::INVOKE))
400  act = act->next;
401 
402  CHECK (act->is (Activity::INVOKE));
403  CHECK (watch(bFlow).find(*act) != Time::NEVER); // can also be found within the BlockFlow allocator
404 
405  // this invocation is properly defined and executable
406  Time now{55,5};
407  CHECK (activity::PASS == act->activate (now, detector.executionCtx));
408  CHECK (detector.verifyInvocation("mockJob"));
409  }
410 
411 
412 
423  void
425  {
426  Time tt{11,1};
427  Time td{22,2};
428  Activity tick;
429  Activity gate{0,td};
430  gate.next = &tick;
431  Activity post{tt, &gate};
432  // so now we have POST ⟶ GATE ⟶ TICK;
433 
434  ActivityDetector detector;
435  detector.executionCtx.getSchedTime = [&]{ return tt; };
436  // insert instrumentation to trace activation
437  detector.watchGate (post.next, "Gate");
438 
439  CHECK (activity::PASS == ActivityLang::dispatchChain (&post, detector.executionCtx)); // start execution (case/seq == 0)
440  CHECK (detector.verifyInvocation("Gate") .arg("1.011 ⧐ Act(GATE") // ...first the Gate was activated
441  .beforeInvocation("after-Gate").arg("1.011 ⧐ Act(TICK") // ...then activation passed out of Gate...
442  .beforeInvocation("CTX-tick") .arg("1.011")); // ...and finally the TICK invoked the λ-tick
443 
444  detector.incrementSeq();
445  gate.data_.condition.incDependencies(); // Gate is blocked
446  CHECK (activity::PASS == ActivityLang::dispatchChain (&post, detector.executionCtx)); // start execution (case/seq == 1)
447  CHECK (detector.verifyInvocation("Gate").seq(1).arg("1.011 ⧐ Act(GATE")); // ...the Gate was activated, but blocked...
448  CHECK (detector.ensureNoInvocation("after-Gate").seq(1) // verify activation was not passed out behind Gate
449  .afterInvocation("Gate").seq(1));
450  CHECK (detector.ensureNoInvocation("CTX-tick").seq(1) // verify also the λ-tick was not invoked this time
451  .afterInvocation("Gate").seq(1));
452 
453  detector.incrementSeq();
454  // Notification via instrumented connection to the Gate (activate(NOTIFY) -> λ-post(target) -> notify GATE
455  CHECK (activity::PASS == ActivityLang::dispatchChain (post.next, detector.executionCtx)); // dispatch a notification (case/seq == 2)
456  CHECK (0 == gate.data_.condition.rest); // Effect of the notification is to decrement the latch
457  CHECK (detector.verifyInvocation("Gate") .seq(2).arg("1.011 --notify-↯> Act(GATE") // ...notification dispatched towards the Gate
458  .beforeInvocation("after-Gate").seq(2).arg("1.011 ⧐ Act(TICK") // ...this opened the Gate, passing activation...
459  .beforeInvocation("CTX-tick") .seq(2).arg("1.011")); // ...to the chain, finally invoking λ-tick
460  }
461 
462 
463 
464 
469  void
471  {
472  Time nominal{7,7};
473 
474  Time start{0,1};
475  Time dead{0,10};
476 
477  ActivityDetector detector;
478  Job testJob{detector.buildMockJob("testJob", nominal, 12345)};
479 
480  TimeVar now = Time{5,5};
481  detector.executionCtx.getSchedTime = [&]{ // increase "current" time on each access
482  now += FSecs(1,20);
483  return now;
484  };
485  BlockFlowAlloc bFlow;
486  ActivityLang activityLang{bFlow};
487 
488  // Build the Activity-Term for a simple calculation job...
489  Activity& anchor = activityLang.buildCalculationJob (testJob, start,dead)
490  .post(); // retrieve the entrance point to the chain
491 
492  // insert instrumentation to trace activation
493  detector.watchGate (anchor.next, "theGate");
494 
495  CHECK (activity::PASS == ActivityLang::dispatchChain (&anchor, detector.executionCtx));
496 
497  CHECK (detector.verifyInvocation("theGate").arg("5.105 ⧐ Act(GATE")
498  .beforeInvocation("after-theGate").arg("⧐ Act(WORKSTART")
499  .beforeInvocation("CTX-work").arg("5.155","")
500  .beforeInvocation("testJob") .arg("7.007",12345)
501  .beforeInvocation("CTX-done").arg("5.355",""));
502  }
503 
504 
505 
513  void
515  {
516  Time nominal{7,7};
517  Time start{0,1};
518  Time dead{0,10};
519 
520  ActivityDetector detector;
521  Job testJob{detector.buildMockJob("testJob", nominal, 12345)};
522 
523  BlockFlowAlloc bFlow;
524  ActivityLang activityLang{bFlow};
525 
526  // emulate a blocking prerequisite dependency
527  Activity trigger{Activity::NOTIFY};
528 
529  // Build the Activity-Term...
530  auto term = activityLang.buildCalculationJob (testJob, start,dead)
531  .expectNotification (trigger) // ...require notification from prerequisite
532  .requireDirectActivation(); // ...additionally insert inhibition to avoid activation
533  // before the primary-chain has been scheduled
534  Activity& anchor = term.post();
535  CHECK (anchor.is (Activity::POST));
536  CHECK (anchor.next->is (Activity::NOTIFY));
537  CHECK (anchor.next->next->is (Activity::GATE));
538  CHECK (anchor.next->next->next->is (Activity::WORKSTART));
539  CHECK (anchor.next->next->next->next->is (Activity::INVOKE));
540  CHECK (anchor.next->next->next->next->next->is (Activity::FEED));
541  CHECK (anchor.next->next->next->next->next->next->is (Activity::FEED));
542  CHECK (anchor.next->next->next->next->next->next->next->is (Activity::WORKSTOP));
543  CHECK (anchor.next->next->next->next->next->next->next->next == nullptr);
544 
545  // insert test-instrumentation to trace activation
546  detector.watchGate (anchor.next->next, "theGate");
547  detector.insertActivationTap(trigger.data_.notification.target, "trigger");
548  detector.insertActivationTap(anchor.next->data_.notification.target, "deBlock");
549 
550  // rig the λ-post to forward dispatch as expected in real usage
551  detector.executionCtx.post.implementedAs(
552  [&](Time, Time, Activity* postedAct, auto& ctx)
553  {
554  return ActivityLang::dispatchChain (postedAct, ctx);
555  });
556 
558  CHECK (activity::PASS == ActivityLang::dispatchChain (&trigger, detector.executionCtx));
559  CHECK (detector.verifyInvocation("CTX-post").seq(0).arg("01.000","10.000","trigger","≺test::CTX≻") // notification is POSTed (with time and deadline from target)
560  .beforeInvocation("trigger") .seq(0).arg("5.555 --notify-↯> Act(GATE") // notification dispatched to the Gate (note: now using curr-sched-time 5.555)
561  .arg("<2, until 0:00:10.000")); // Note: the Gate-latch expects 2 notifications
562  CHECK (detector.ensureNoInvocation("testJob") // ==> the latch was decremented but no invocation yet
563  .afterInvocation("trigger"));
564 
566  detector.incrementSeq();
567  CHECK (activity::PASS == ActivityLang::dispatchChain (&anchor, detector.executionCtx));
568  CHECK (detector.verifyInvocation("CTX-post").seq(1).arg("01.000","10.000","deBlock","≺test::CTX≻") // at begin, the internal self-notification is POSTed (with time and deadline this chain)
569  .beforeInvocation("deBlock") .seq(1).arg("5.555 --notify-↯> Act(GATE") // and this call is immediately dispatched towards the Gate (using curr-sched-time 5.555)
570  .arg("<1, until 0:00:10.000") // Note: at this point, the Gate-latch expects 1 notifications ==> latch decremented, Gate OPENS
571  .beforeInvocation("after-theGate") .arg("5.555 ⧐ Act(WORKSTART") // ...causing the activation to pass behind the Gate
572  .beforeInvocation("CTX-work").seq(1).arg("5.555","") // ...through WORKSTART
573  .beforeInvocation("testJob") .seq(1).arg("7.007",12345) // ...then invoke the JobFunctor itself (with the nominal Time{7,7})
574  .beforeInvocation("CTX-done").seq(1).arg("5.555","") // ...and finally the WORKSTOP
575  .beforeInvocation("theGate") .seq(1).arg("5.555 ⧐ Act(GATE") // RETURN to the primary-chain activation (after the internal self-notification)
576  .arg("<0, until -85401592:56:01.825")); // -- however, after opening the Gate, the notification has blocked it permanently
577  CHECK (detector.ensureNoInvocation("testJob") // ==> thus no further (redundant) activation of the JobFunctor
578  .afterInvocation("CTX-done").seq(1));
579 
580  detector.incrementSeq();
581  CHECK (activity::PASS == ActivityLang::dispatchChain (&trigger, detector.executionCtx)); // and any further external trigger is likewise blocked:
582  CHECK (detector.verifyInvocation("CTX-post").seq(2).arg("01.000",Time::NEVER,"trigger","≺test::CTX≻") // notification is POSTed (in the real Scheduler the deadline will block already here)
583  .beforeInvocation("trigger") .seq(2).arg("5.555 --notify-↯> Act(GATE") // ... but even if it would reach the Gate...
584  .arg("<0, until -85401592:56:01.825")); // ... the Gate has been closed permanently (by setting the deadline to Time::MIN)
585  CHECK (detector.ensureNoInvocation("testJob") // ==> no further invocation
586  .afterInvocation("trigger").seq(2));
587 
588 // cout << detector.showLog()<<endl; // HINT: use this for investigation...
589  }
590 
591 
592 
598  void
600  {
601  Time nominal{7,7};
602  Time start{0,1};
603  Time dead{0,10};
604 
605  ActivityDetector detector;
606  Job loadJob{detector.buildMockJob("loadJob", nominal, 12345)};
607  Job calcJob{detector.buildMockJob("calcJob")};
608 
609  BlockFlowAlloc bFlow;
610  ActivityLang activityLang{bFlow};
611 
612  auto followup = activityLang.buildCalculationJob (calcJob, start,dead);
613  auto loadTerm = activityLang.buildAsyncLoadJob (loadJob, start,dead)
614  .appendNotificationTo (followup);
615 
616  Activity& anchor = loadTerm.post();
617  Activity& notify = loadTerm.callback();
618 
619  CHECK (anchor.is (Activity::POST));
620  CHECK (anchor.next->is (Activity::WORKSTART));
621  CHECK (anchor.next->next->is (Activity::INVOKE));
622  CHECK (anchor.next->next->next->is (Activity::FEED));
623  CHECK (anchor.next->next->next->next->is (Activity::FEED));
624  CHECK (anchor.next->next->next->next->next == nullptr); // Note: chain is severed here
625 
626  CHECK (notify.is (Activity::WORKSTOP)); // ...WORKSTOP will be emitted from callback
627  CHECK (notify.next->is (Activity::NOTIFY)); // ...followed by notification of dependent job(s)
628  CHECK (notify.next->next == nullptr);
629 
630  CHECK (notify.next->data_.notification.target == followup.post().next); // was wired to the GATE of the follow-up activity Term
631  CHECK (followup.post().next->is (Activity::GATE));
632 
633  // rig the λ-post to forward dispatch as expected in real usage
634  detector.executionCtx.post.implementedAs(
635  [&](Time, Time, Activity* postedAct, auto& ctx)
636  {
637  return ActivityLang::dispatchChain (postedAct, ctx);
638  });
639 
640 
642  CHECK (activity::PASS == ActivityLang::dispatchChain (&anchor, detector.executionCtx));
643  CHECK (detector.verifyInvocation("CTX-work").seq(0).arg("5.555", "") // activation of WORKSTART
644  .beforeInvocation("loadJob") .seq(0).arg("7.007", 12345)); // activation of JobFunctor
645  CHECK (detector.ensureNoInvocation("CTX-done").seq(0) // IO operation just runs, no further activity yet
646  .afterInvocation("loadJob").seq(0));
647 
648 
650  detector.incrementSeq();
651  CHECK (activity::PASS == ActivityLang::dispatchChain (&notify, detector.executionCtx));
652  CHECK (detector.verifyInvocation("CTX-done").seq(1).arg("5.555", "") // activation of WORKSTOP via callback
653  .beforeInvocation("CTX-post").seq(1).arg("01.00","10.00","GATE","≺test::CTX≻") // the notification posts the GATE of the follow-up chain
654  .beforeInvocation("CTX-work").seq(1).arg("5.555", "") // GATE passes -> activation of the follow-up work commences
655  .beforeInvocation("calcJob") .seq(1)
656  .beforeInvocation("CTX-done").seq(1).arg("5.555", ""));
657  }
658 
659 
660 
668  void
670  {
671  Time nominal{7,7};
672  Time start{0,1};
673  Time dead{0,10};
674 
675  ActivityDetector detector;
676  Job testJob{detector.buildMockJob("metaJob", nominal, 12345)};
677 
678  BlockFlowAlloc bFlow;
679  ActivityLang activityLang{bFlow};
680 
681  // Build Activity-Term with a chain defining a meta-job...
682  Activity& anchor = activityLang.buildMetaJob (testJob, start,dead)
683  .post();
684 
685  CHECK (anchor.is (Activity::POST));
686  CHECK (anchor.next->is (Activity::INVOKE));
687  CHECK (anchor.next->next->is (Activity::FEED));
688  CHECK (anchor.next->next->next->is (Activity::FEED));
689  CHECK (anchor.next->next->next->next == nullptr);
690 
691  // insert test-instrumentation
692  detector.insertActivationTap(anchor.next);
693 
694  CHECK (activity::PASS == ActivityLang::dispatchChain (&anchor, detector.executionCtx));
695 
696  CHECK (detector.verifyInvocation("tap-INVOKE").arg("5.555 ⧐ Act(INVOKE")
697  .beforeInvocation("metaJob") .arg("7.007",12345));
698  }
699  };
700 
701 
703  LAUNCHER (SchedulerActivity_test, "unit engine");
704 
705 
706 
707 }}} // namespace vault::gear::test
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:241
signal start of some processing and transition grooming mode ⟼ *work mode
Definition: activity.hpp:242
Record to describe an Activity, to happen within the Scheduler&#39;s control flow.
Definition: activity.hpp:235
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:49
Activity & insertActivationTap(Activity *&wiring, string id="")
build ActivationProbe to record each activation before passing it to the subject
correspondingly signal end of some processing
Definition: activity.hpp:243
supply additional payload data for a preceding Activity
Definition: activity.hpp:247
activity::Proc activate(Time now, EXE &executionCtx)
Core Operation: Activate and perform this Activity.
Definition: activity.hpp:635
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
post a message providing a chain of further time-bound Activities
Definition: activity.hpp:246
Abstract Base Class for all testcases.
Definition: run.hpp:62
Term builder and execution framework to perform chains of scheduler Activities.
ActivityMatch & seq(uint seqNr)
qualifier: additionally require the indicated sequence number
Diagnostic context to record and evaluate activations within the Scheduler.
Simple test class runner.
A language framework to define and interconnect scheduler activity verbs.
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Definition: timevalue.hpp:229
A collection of frequently used helper functions to support unit testing.
activity::Proc dispatch(Time now, EXE &executionCtx)
Entrance point for an activation, which has been dispatched indirectly through the dispatch and/or pr...
Definition: activity.hpp:685
uint incrementSeq()
increment the internal invocation sequence number
probe window + count-down; activate next Activity, else re-schedule
Definition: activity.hpp:245
Activity * next
Activities are organised into chains to represent relations based on verbs.
Definition: activity.hpp:258
Diagnostic setup to instrument and observe Activity activations.
internal engine »heart beat« for internal maintenance hook(s)
Definition: activity.hpp:249
dispatch a JobFunctor into a worker thread
Definition: activity.hpp:241
push a message to another Activity
Definition: activity.hpp:244
static const Time NEVER
border condition marker value. NEVER >= any time value
Definition: timevalue.hpp:323
static activity::Proc dispatchChain(Activity *chain, EXE &executionCtx)
Execution Framework: dispatch performance of a chain of Activities.
Individual frame rendering task, forwarding to a closure.
Definition: job.h:277
a family of time value like entities and their relationships.
Front-end for simplified access to the current wall clock time.
ActivityMatch & arg(ARGS const &...args)
qualifier: additionally match the function arguments
Vault-Layer implementation namespace root.