The problem with passing the deadline was just a blatant symptom that something with the overall design was not quite right, leading to mix-up of interfaces and implementation functions, and more and more detail parameters spreading throughout the call chains. The turning point was to realise the two conceptual levels crossing and interconnected within the »Scheduler-Service« - the Activity-Language describes the patterns of processing - the Scheduler components handle time-bound events So by turning the (previously private) queue entry into an ActivationEvent, the design could be balanced. This record becomes the common agens within the Scheduler, and builds upon / layers on top of the common agens of the Language, which is the Activity record.
293 lines
10 KiB
C++
293 lines
10 KiB
C++
/*
|
|
SchedulerInvocation(Test) - verify queue processing 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 02139, USA.
|
|
|
|
* *****************************************************/
|
|
|
|
/** @file scheduler-invocation-test.cpp
|
|
** unit test \ref SchedulerInvocation_test
|
|
*/
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
#include "vault/gear/scheduler-invocation.hpp"
|
|
#include "lib/util.hpp"
|
|
|
|
using test::Test;
|
|
using util::isSameObject;
|
|
|
|
|
|
namespace vault{
|
|
namespace gear {
|
|
namespace test {
|
|
|
|
|
|
|
|
|
|
/********************************************************************//**
|
|
* @test Scheduler Layer-1: queue processing and invocation by priority.
|
|
* @see SchedulerCommutator_test
|
|
* @see SchedulerUsage_test
|
|
*/
|
|
class SchedulerInvocation_test : public Test
|
|
{
|
|
|
|
virtual void
|
|
run (Arg)
|
|
{
|
|
simpleUsage();
|
|
verify_Queuing();
|
|
verify_WaterLevel();
|
|
verify_Significance();
|
|
verify_stability();
|
|
verify_isDue();
|
|
}
|
|
|
|
|
|
/** @test demonstrate a simple usage scenario of data passing
|
|
*/
|
|
void
|
|
simpleUsage()
|
|
{
|
|
SchedulerInvocation sched;
|
|
Activity activity;
|
|
Time when{1,2,3};
|
|
Time dead{2,3,4};
|
|
|
|
CHECK (not sched.peekHead());
|
|
|
|
sched.instruct ({activity, when, dead});
|
|
sched.feedPrioritisation();
|
|
CHECK (sched.peekHead());
|
|
|
|
Activity* head = sched.pullHead();
|
|
CHECK (not sched.peekHead());
|
|
CHECK (isSameObject (*head, activity));
|
|
}
|
|
|
|
|
|
|
|
/** @test verify records are passed properly through the queues
|
|
* - add multiple elements to the instruct queue
|
|
* - after `feedPrioritisation` these appear as output
|
|
*/
|
|
void
|
|
verify_Queuing()
|
|
{
|
|
SchedulerInvocation sched;
|
|
Activity one{1u,1u};
|
|
Activity two{2u,2u};
|
|
Activity wee{3u,3u};
|
|
Time t{5,5};
|
|
|
|
sched.instruct ({one, t});
|
|
sched.instruct ({two, t});
|
|
sched.instruct ({wee, t});
|
|
CHECK (not sched.peekHead());
|
|
|
|
sched.feedPrioritisation();
|
|
CHECK (isSameObject (*sched.pullHead(), one));
|
|
CHECK (isSameObject (*sched.pullHead(), two));
|
|
CHECK (isSameObject (*sched.pullHead(), wee));
|
|
CHECK (not sched.peekHead());
|
|
CHECK (sched.empty());
|
|
}
|
|
|
|
|
|
|
|
/** @test verify the given time point is utilised for prioritisation
|
|
* - order at output is determined by the time spec
|
|
* - even later added elements can push back
|
|
* previously visible elements at head
|
|
*/
|
|
void
|
|
verify_WaterLevel()
|
|
{
|
|
SchedulerInvocation sched;
|
|
Activity a1{1u,1u};
|
|
Activity a2{2u,2u};
|
|
Activity a3{3u,3u};
|
|
Activity a4{4u,4u};
|
|
|
|
sched.instruct ({a2, Time{2,0}});
|
|
sched.instruct ({a4, Time{4,0}});
|
|
sched.feedPrioritisation();
|
|
CHECK (isSameObject (*sched.peekHead(), a2));
|
|
|
|
sched.instruct ({a3, Time{3,0}});
|
|
sched.instruct ({a1, Time{1,0}});
|
|
CHECK (isSameObject (*sched.peekHead(), a2));
|
|
|
|
sched.feedPrioritisation();
|
|
CHECK (isSameObject (*sched.pullHead(), a1));
|
|
CHECK (isSameObject (*sched.pullHead(), a2));
|
|
CHECK (isSameObject (*sched.pullHead(), a3));
|
|
CHECK (isSameObject (*sched.pullHead(), a4));
|
|
}
|
|
|
|
|
|
|
|
/** @test sort order is not necessarily stable
|
|
* if using identical time specs on entrance
|
|
*/
|
|
void
|
|
verify_stability()
|
|
{
|
|
SchedulerInvocation sched;
|
|
Activity a1{1u,1u};
|
|
Activity a2{2u,2u};
|
|
Activity a3{3u,3u};
|
|
Activity a4{4u,4u};
|
|
|
|
sched.feedPrioritisation ({a1, Time{0,5}});
|
|
sched.feedPrioritisation ({a2, Time{0,5}});
|
|
sched.feedPrioritisation ({a3, Time{0,5}});
|
|
sched.feedPrioritisation ({a4, Time{0,4}});
|
|
CHECK (isSameObject (*sched.pullHead(), a4));
|
|
CHECK (isSameObject (*sched.pullHead(), a3));
|
|
CHECK (isSameObject (*sched.pullHead(), a1));
|
|
CHECK (isSameObject (*sched.pullHead(), a2));
|
|
CHECK (not sched.pullHead());
|
|
}
|
|
|
|
|
|
|
|
/** @test the entry appearing at head _is due_
|
|
* when its time is at or before current time.
|
|
*/
|
|
void
|
|
verify_isDue()
|
|
{
|
|
SchedulerInvocation sched;
|
|
Activity a1{1u,1u};
|
|
|
|
sched.feedPrioritisation ({a1, Time{0,5}});
|
|
CHECK (isSameObject (*sched.peekHead(), a1));
|
|
CHECK ( sched.isDue (Time{0,10}));
|
|
CHECK ( sched.isDue (Time{0,5}));
|
|
CHECK (not sched.isDue (Time{0,1}));
|
|
|
|
sched.pullHead();
|
|
CHECK (not sched.peekHead());
|
|
CHECK (not sched.isDue (Time{0,1}));
|
|
CHECK (not sched.isDue (Time{0,10}));
|
|
}
|
|
|
|
|
|
|
|
/** @test verify extended classification data and information functions at scheduler head
|
|
* - add entries providing extra information regarding significance
|
|
* - verify that missing the deadline is detected
|
|
* - entries past deadline are marked _outdated_ (will be dropped by Layer-2)
|
|
* - entries can be tagged with an ManifestationID, allowing to enable
|
|
* or disable visibility for a »family« of schedule entries
|
|
* - use the flag for _compulsory_ entries, allowing to detect
|
|
* a fatal _jammed_ situation where the head entry is
|
|
* out of time, while marked mandatory to process.
|
|
*/
|
|
void
|
|
verify_Significance()
|
|
{
|
|
SchedulerInvocation sched;
|
|
Activity act;
|
|
|
|
sched.feedPrioritisation ({act, Time{2,0}, Time{3,0}});
|
|
CHECK (Time(2,0) == sched.headTime());
|
|
CHECK ( sched.isDue (Time{2,0}));
|
|
CHECK (not sched.isMissed (Time{2,0}));
|
|
CHECK (not sched.isMissed (Time{3,0}));
|
|
CHECK ( sched.isMissed (Time{4,0}));
|
|
|
|
CHECK (not sched.isOutdated (Time{2,0}));
|
|
CHECK (not sched.isOutdated (Time{3,0}));
|
|
CHECK ( sched.isOutdated (Time{4,0}));
|
|
|
|
sched.feedPrioritisation ({act, Time{1,0}, Time{3,0}, ManifestationID{5}});
|
|
CHECK (Time(1,0) == sched.headTime());
|
|
CHECK ( sched.isOutdated (Time{1,0}));
|
|
CHECK (not sched.isMissed (Time{1,0}));
|
|
|
|
sched.activate (ManifestationID{5});
|
|
CHECK (Time(1,0) == sched.headTime());
|
|
CHECK ( sched.isDue (Time{1,0}));
|
|
CHECK (not sched.isOutdated (Time{1,0}));
|
|
CHECK (not sched.isOutdated (Time{3,0}));
|
|
CHECK ( sched.isOutdated (Time{4,0}));
|
|
CHECK ( sched.isMissed (Time{4,0}));
|
|
CHECK ( sched.isDue (Time{4,0}));
|
|
|
|
sched.activate (ManifestationID{23});
|
|
CHECK (not sched.isOutdated (Time{1,0}));
|
|
|
|
sched.drop (ManifestationID{5});
|
|
CHECK (Time(1,0) == sched.headTime());
|
|
CHECK ( sched.isOutdated (Time{1,0}));
|
|
CHECK ( sched.isOutdated (Time{4,0}));
|
|
CHECK ( sched.isMissed (Time{4,0}));
|
|
CHECK (not sched.isMissed (Time{1,0}));
|
|
CHECK ( sched.isDue (Time{1,0}));
|
|
|
|
sched.feedPrioritisation ({act, Time{0,0}, Time{2,0}, ManifestationID{23}, true});
|
|
CHECK (Time(0,0) == sched.headTime()); // ^^^^ marked as compulsory
|
|
CHECK (not sched.isMissed (Time{1,0}));
|
|
CHECK (not sched.isOutdated (Time{1,0}));
|
|
CHECK (not sched.isOutOfTime(Time{2,0})); // still OK /at/ deadline
|
|
CHECK ( sched.isOutOfTime(Time{3,0})); // ↯ past deadline yet marked as compulsory
|
|
CHECK ( sched.isOutdated (Time{3,0}));
|
|
CHECK ( sched.isMissed (Time{3,0}));
|
|
|
|
sched.drop (ManifestationID{5});
|
|
CHECK ( sched.isOutOfTime(Time{3,0})); // Manifestation-5 is altogether irrelevant for this case
|
|
|
|
sched.drop (ManifestationID{23});
|
|
CHECK (Time(0,0) == sched.headTime());
|
|
CHECK ( sched.isOutdated (Time{1,0}));
|
|
CHECK (not sched.isOutOfTime(Time{2,0}));
|
|
CHECK (not sched.isOutOfTime(Time{3,0})); // the disabled manifestation-23 masks the fatal out-of-time state
|
|
CHECK ( sched.isOutdated (Time{3,0}));
|
|
CHECK ( sched.isMissed (Time{3,0}));
|
|
|
|
sched.pullHead();
|
|
CHECK (Time(1,0) == sched.headTime());
|
|
CHECK ( sched.isOutdated (Time{1,0}));
|
|
CHECK ( sched.isDue (Time{1,0}));
|
|
|
|
sched.pullHead();
|
|
CHECK (Time(2,0) == sched.headTime());
|
|
CHECK (not sched.isOutdated (Time{2,0}));
|
|
CHECK ( sched.isOutdated (Time{4,0}));
|
|
CHECK ( sched.isMissed (Time{4,0}));
|
|
CHECK ( sched.isDue (Time{4,0}));
|
|
|
|
sched.pullHead();
|
|
CHECK (Time::NEVER == sched.headTime());
|
|
CHECK (not sched.isMissed (Time{4,0}));
|
|
CHECK (not sched.isOutdated (Time{4,0}));
|
|
CHECK (not sched.isDue (Time{4,0}));
|
|
CHECK (sched.empty());
|
|
}
|
|
};
|
|
|
|
|
|
/** Register this test class... */
|
|
LAUNCHER (SchedulerInvocation_test, "unit engine");
|
|
|
|
|
|
|
|
}}} // namespace vault::gear::test
|