2023-07-03 18:40:37 +02:00
/*
SchedulerActivity ( Test ) - verify activities processed in the scheduler
Copyright ( C ) Lumiera . org
2023 , Hermann Vosseler < Ichthyostega @ web . de >
This program 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 .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** @file scheduler-activity-test.cpp
* * unit test \ ref SchedulerActivity_test
*/
# include "lib/test/run.hpp"
2023-08-18 16:54:35 +02:00
# include "lib/test/test-helper.hpp"
2023-08-17 19:37:38 +02:00
# include "activity-detector.hpp"
2023-07-03 18:40:37 +02:00
# include "vault/gear/activity-lang.hpp"
2023-08-18 16:54:35 +02:00
# include "vault/real-clock.hpp"
2023-07-07 03:41:30 +02:00
# include "lib/time/timevalue.hpp"
2023-08-18 16:54:35 +02:00
# include "lib/format-cout.hpp" /////////////////////////////////////TODO
2023-07-03 18:40:37 +02:00
//#include "lib/util.hpp"
//#include <utility>
using test : : Test ;
2023-07-07 03:41:30 +02:00
using lib : : time : : Time ;
using lib : : time : : FSecs ;
2023-07-03 18:40:37 +02:00
//using std::move;
//using util::isSameObject;
namespace vault {
2023-07-13 01:51:21 +02:00
namespace gear {
2023-07-03 18:40:37 +02:00
namespace test {
// using lib::time::FrameRate;
// using lib::time::Offset;
// using lib::time::Time;
/*****************************************************************/ /**
* @ test verify behaviour of the Scheduler _Activity Language . _
* @ see SchedulerCommutator_test
* @ see SchedulerUsage_test
*/
class SchedulerActivity_test : public Test
{
virtual void
run ( Arg )
{
2023-07-13 01:51:21 +02:00
simpleUsage ( ) ;
2023-08-18 16:54:35 +02:00
verifyActivity_Post ( ) ;
2023-08-22 17:37:58 +02:00
verifyActivity_Invoke ( ) ;
verifyActivity_Notify_activate ( ) ;
verifyActivity_Notify_dispatch ( ) ;
2023-08-22 18:57:15 +02:00
verifyActivity_Gate_pass ( ) ;
verifyActivity_Gate_dead ( ) ;
verifyActivity_Gate_block ( ) ;
verifyActivity_Gate_opened ( ) ;
2023-07-13 01:51:21 +02:00
termBuilder ( ) ;
scenario_RenderJob ( ) ;
scenario_IOJob ( ) ;
scenario_MetaJob ( ) ;
2023-07-03 18:40:37 +02:00
}
2023-08-22 17:37:58 +02:00
/** @test demonstrate simple Activity usage */
2023-07-03 18:40:37 +02:00
void
simpleUsage ( )
{
2023-07-06 16:35:42 +02:00
// Activities are »POD with constructor«
2023-08-22 17:37:58 +02:00
Activity start { Activity : : WORKSTART } ;
CHECK ( start . verb_ = = Activity : : WORKSTART ) ;
CHECK ( start . next = = nullptr ) ;
CHECK ( start . data_ . timing . instant = = Time : : NEVER ) ; //////////////////////////////////////////TICKET #1317 : the purpose of this time data is not clear yet
CHECK ( start . data_ . timing . quality = = 0 ) ;
// use the ActivityDetector for test instrumentation...
ActivityDetector detector ;
// Activities can be invoked within an ExecutionContext
Time now = RealClock : : now ( ) ;
start . activate ( now , detector . executionCtx ) ;
// In this case, activation causes invocation of λ-work on the context
CHECK ( detector . verifyInvocation ( " CTX-work " ) . arg ( now , 0 ) ) ;
// cout << detector.showLog()<<endl; // HINT: use this for investigation...
}
/** @test behaviour of Activity::POST
2023-08-22 18:38:40 +02:00
* - invoke the λ - post to dispatch the chain through the queue
* - the chain to be executed is given as ` next `
* - time window for scheduling as data field
2023-08-22 17:37:58 +02:00
*/
void
verifyActivity_Post ( )
{
Activity chain ;
Activity post { Time { 0 , 11 } , Time { 0 , 22 } , & chain } ;
CHECK ( Activity : : TICK = = chain . verb_ ) ;
CHECK ( Activity : : POST = = post . verb_ ) ;
CHECK ( Time ( 0 , 11 ) = = post . data_ . timeWindow . life ) ;
CHECK ( Time ( 0 , 22 ) = = post . data_ . timeWindow . dead ) ;
CHECK ( & chain = = post . next ) ;
ActivityDetector detector ;
Time tt { 11 , 11 } ;
post . activate ( tt , detector . executionCtx ) ;
2023-08-22 18:38:40 +02:00
CHECK ( detector . verifyInvocation ( " CTX-post " ) . arg ( " 11.011 " , " Act(POST " , " ≺test::CTX≻ " ) ) ;
2023-07-03 18:40:37 +02:00
}
2023-08-18 16:54:35 +02:00
/** @test behaviour of Activity::INVOKE
* - setup requires two FEED - Activities to be chained up as arguments
* - use the rigged execution context provided by ActivityDetector
* - can verify this way that the activation leads to JobFunctor invocation
2023-07-03 18:40:37 +02:00
*/
void
2023-07-13 01:51:21 +02:00
verifyActivity_Invoke ( )
2023-07-03 18:40:37 +02:00
{
2023-08-17 19:37:38 +02:00
ActivityDetector detector ;
2023-08-18 16:54:35 +02:00
size_t x1 = rand ( ) , x2 = rand ( ) ;
Time nomTime = lib : : test : : randTime ( ) ;
Activity feed { x1 , x2 } ;
Activity feed2 { x1 + 1 , x1 + 2 } ;
feed . next = & feed2 ;
Activity invoke { detector . buildMockJobFunctor ( " job " ) , nomTime , feed } ;
Time realTime = RealClock : : now ( ) ;
CHECK ( activity : : PASS = = invoke . activate ( realTime , detector . executionCtx ) ) ;
CHECK ( detector . verifyInvocation ( " job " ) . arg ( nomTime , x1 ) ) ;
2023-07-03 18:40:37 +02:00
}
2023-08-22 20:13:13 +02:00
/** @test behaviour of Activity::NOTIFY when _activated_
2023-08-22 17:37:58 +02:00
* - notification is dispatched as special message to an indicated target Activity
* - when activated , a ` NOTIFY ` - Activity _posts itself_ through the Execution Context hook
* - this way , further processing will happen in management mode ( single threaded )
2023-07-03 18:40:37 +02:00
*/
void
2023-08-22 17:37:58 +02:00
verifyActivity_Notify_activate ( )
2023-07-13 01:51:21 +02:00
{
2023-08-22 17:37:58 +02:00
Activity chain ;
Activity notify { & chain } ;
ActivityDetector detector ;
Time tt { 111 , 11 } ;
notify . activate ( tt , detector . executionCtx ) ;
2023-08-22 20:13:13 +02:00
2023-08-22 18:57:15 +02:00
CHECK ( detector . verifyInvocation ( " CTX-post " ) . arg ( " 11.111 " , " Act(NOTIFY " , " ≺test::CTX≻ " ) ) ;
2023-07-13 01:51:21 +02:00
}
2023-08-22 20:13:13 +02:00
/** @test behaviour of Activity::NOTIFY when activation leads to a _dispatch_
2023-08-22 17:37:58 +02:00
* - when _posting_ a ` NOTIFY ` , a dedicated _notification_ function is invoked on the chain
* - what actually happens then depends on the receiver ; here we just activate a test - Tap
2023-08-18 16:54:35 +02:00
*/
void
2023-08-22 17:37:58 +02:00
verifyActivity_Notify_dispatch ( )
2023-08-18 16:54:35 +02:00
{
2023-08-22 17:37:58 +02:00
ActivityDetector detector ;
2023-08-22 18:57:15 +02:00
// use a diagnostic Tap as chain to detect passing of notification
Activity notify { detector . buildActivationProbe ( " notifyTargetActivity " ) } ;
2023-08-22 17:37:58 +02:00
Time tt { 111 , 11 } ;
notify . dispatch ( tt , detector . executionCtx ) ;
2023-08-22 20:13:13 +02:00
2023-08-22 18:57:15 +02:00
CHECK ( detector . verifyInvocation ( " notifyTargetActivity " ) . arg ( " 11.111 " ) ) ;
2023-08-18 16:54:35 +02:00
}
2023-08-22 20:13:13 +02:00
/** @test behaviour of Activity::GATE:
* if conditions are met , the activation is just passed ,
* so the executor ( in the Scheduler ) will just invoke the chain
* @ todo WIP 8 / 23 ✔ define ✔ implement
2023-08-22 18:57:15 +02:00
*/
void
verifyActivity_Gate_pass ( )
{
Activity chain ;
Activity gate { 0 } ;
gate . next = & chain ;
ActivityDetector detector ;
2023-08-22 20:13:13 +02:00
Activity & wiring = detector . buildGateWatcher ( gate ) ;
Time tt { 333 , 33 } ;
CHECK ( activity : : PASS = = wiring . activate ( tt , detector . executionCtx ) ) ;
CHECK ( detector . verifyInvocation ( " tap-GATE " ) . arg ( " 33.333 ⧐ Act(GATE " ) ) ;
2023-08-22 18:57:15 +02:00
}
2023-08-22 20:13:13 +02:00
/** @test TODO behaviour of Activity::GATE:
* the rest of the chain is just skipped in case of deadline violation
* @ todo WIP 8 / 23 ✔ define ✔ implement
2023-07-13 01:51:21 +02:00
*/
void
2023-08-22 18:57:15 +02:00
verifyActivity_Gate_dead ( )
2023-07-13 01:51:21 +02:00
{
2023-08-22 18:57:15 +02:00
Activity chain ;
2023-08-22 20:13:13 +02:00
Activity gate { 0 , Time { 333 , 33 } } ;
2023-08-22 18:57:15 +02:00
gate . next = & chain ;
ActivityDetector detector ;
2023-08-22 20:13:13 +02:00
Activity & wiring = detector . buildGateWatcher ( gate ) ;
Time t1 { 330 , 33 } ; // still before the deadline
Time t2 { 333 , 33 } ; // exactly at deadline => rejected
Time t3 { 335 , 33 } ; // after the deadline => rejected
CHECK ( activity : : PASS = = wiring . activate ( t1 , detector . executionCtx ) ) ;
CHECK ( detector . verifyInvocation ( " tap-GATE " ) . arg ( " 33.330 ⧐ Act(GATE " ) . seq ( 0 ) ) ;
detector . incrementSeq ( ) ;
CHECK ( activity : : SKIP = = wiring . activate ( t2 , detector . executionCtx ) ) ;
CHECK ( detector . verifyInvocation ( " tap-GATE " ) . arg ( " 33.333 ⧐ Act(GATE " ) . seq ( 1 ) ) ;
detector . incrementSeq ( ) ;
CHECK ( activity : : SKIP = = wiring . activate ( t3 , detector . executionCtx ) ) ;
CHECK ( detector . verifyInvocation ( " tap-GATE " ) . arg ( " 33.335 ⧐ Act(GATE " ) . seq ( 2 ) ) ;
2023-08-22 18:57:15 +02:00
cout < < detector . showLog ( ) < < endl ;
}
2023-08-22 20:13:13 +02:00
/** @test TODO behaviour of Activity::GATE:
* the count - down condition determines if activation _passes_
* or will _spin around_ for later re - try
* @ todo WIP 8 / 23 ✔ define ✔ implement
2023-08-22 18:57:15 +02:00
*/
void
verifyActivity_Gate_block ( )
{
Activity chain ;
2023-08-22 20:13:13 +02:00
Activity gate { 23 } ;
2023-08-22 18:57:15 +02:00
gate . next = & chain ;
ActivityDetector detector ;
2023-08-22 20:13:13 +02:00
Activity & wiring = detector . buildGateWatcher ( gate ) ;
Time tt { 333 , 33 } ;
CHECK ( activity : : SKIP = = wiring . activate ( tt , detector . executionCtx ) ) ;
CHECK ( 23 = = gate . data_ . condition . rest ) ; // prerequisite-count not altered
Time reScheduled = detector . executionCtx . spin ( tt ) ;
CHECK ( tt < reScheduled ) ;
2023-08-22 18:57:15 +02:00
cout < < detector . showLog ( ) < < endl ;
2023-08-22 20:13:13 +02:00
CHECK ( detector . verifyInvocation ( " tap-GATE " ) . arg ( " 33.333 ⧐ Act(GATE " )
. beforeInvocation ( " CTX-post " ) . arg ( reScheduled , " Act(GATE " , " ≺test::CTX≻ " ) ) ;
2023-08-22 18:57:15 +02:00
}
/** @test TODO behaviour of Activity::GATE
2023-08-22 20:13:13 +02:00
* @ todo WIP 8 / 23 🔁 define ✔ implement
2023-08-22 18:57:15 +02:00
*/
void
verifyActivity_Gate_opened ( )
{
Activity chain ;
2023-08-22 20:13:13 +02:00
Activity gate { 1 } ;
2023-08-22 18:57:15 +02:00
gate . next = & chain ;
ActivityDetector detector ;
2023-08-22 20:13:13 +02:00
Activity & wiring = detector . buildGateWatcher ( gate ) ;
Time tt { 333 , 33 } ;
CHECK ( activity : : SKIP = = wiring . activate ( tt , detector . executionCtx ) ) ;
CHECK ( 1 = = gate . data_ . condition . rest ) ; // unchanged...
detector . incrementSeq ( ) ;
// Gate receives a notification from some prerequisite Activity
CHECK ( activity : : PASS = = wiring . notify ( tt , detector . executionCtx ) ) ;
CHECK ( 0 = = gate . data_ . condition . rest ) ; // condition has been decremented...
Time reScheduled = detector . executionCtx . spin ( tt ) ;
CHECK ( detector . verifyInvocation ( " tap-GATE " ) . seq ( 0 ) . arg ( " 33.333 ⧐ Act(GATE " )
. beforeInvocation ( " CTX-post " ) . seq ( 0 ) . arg ( reScheduled , " Act(GATE " , " ≺test::CTX≻ " )
. beforeInvocation ( " tap-GATE " ) . seq ( 1 ) . arg ( " 33.333 --notify-↯> Act(GATE " )
. beforeInvocation ( " CTX-post " ) . seq ( 1 ) . arg ( tt , " afterGATE " , " ≺test::CTX≻ " ) ) ; ////////TICKET #1319 : really re-scheduler directly? may lead to duplicate invocations!
2023-08-22 18:57:15 +02:00
cout < < detector . showLog ( ) < < endl ;
2023-07-13 01:51:21 +02:00
}
/** @test TODO verify the Activity term builder
* @ todo WIP 7 / 23 ⟶ define ⟶ implement
*/
void
termBuilder ( )
{
}
/** @test TODO usage scenario: Activity graph for a render job
* @ todo WIP 7 / 23 ⟶ define ⟶ implement
*/
void
scenario_RenderJob ( )
{
}
/** @test TODO usage scenario: Activity graph for an async Job
* @ todo WIP 7 / 23 ⟶ define ⟶ implement
*/
void
scenario_IOJob ( )
{
}
/** @test TODO usage scenario: Activity graph for administrative job
* @ todo WIP 7 / 23 ⟶ define ⟶ implement
*/
void
scenario_MetaJob ( )
2023-07-03 18:40:37 +02:00
{
}
} ;
/** Register this test class... */
LAUNCHER ( SchedulerActivity_test , " unit engine " ) ;
2023-07-06 16:35:42 +02:00
} } } // namespace vault::gear::test