From 542017aa65dc1095c43d1ffa1e7e1910bdfe6fcc Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 13 Jun 2023 20:23:33 +0200 Subject: [PATCH] Dispatcher-Pipeline: mocked Dispatcher implementation complete (closes: #1294) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `steam/engine/mock-dispatcher.hpp |cpp` now integrates this ''complete mock setup for render jobs and frame dispatching.'' The exising `DummyJob` has been slightly adapted and renamed to `MockJob` and is tightly integrated with the other mocks. The implementation of a `MockDispatcher` necessitated to change the use of `MockJobTicket`. The initial attempts used a complete mock implementation, but this approach turned out not to be viable. Instead — based on the ideas developed for the mock setup — now the prospective real implementation of `JobTicket` is available and will be used by the mock setup too. Instead of a synthetic spec, now a setup of recursively connected `ExitNode`(s) is used; the latter seems to develop into some kind of Facade for the render node network. Based on this mock setup, we can now demonstrate the (mostly) complete Job-Planning pipeline, starting from a segmentation up to render jobs, and verify proper connectivity and job invocation. ✔ --- src/lib/iter-adapter-ptr-deref.hpp | 62 +++---- src/steam/engine/frame-coord.hpp | 1 - src/steam/engine/job-ticket.hpp | 11 +- src/steam/fixture/segment.hpp | 1 - src/steam/fixture/segmentation.hpp | 17 +- .../{vault => steam}/engine/job-hash-test.cpp | 24 +-- .../steam/engine/job-planning-setup-test.cpp | 31 ++-- .../engine/mock-dispatcher.cpp} | 49 +++--- tests/core/steam/engine/mock-dispatcher.hpp | 151 ++++++++++++------ tests/core/steam/engine/mock-support-test.cpp | 51 +++--- .../engine/scheduler-interface-test.cpp | 12 +- tests/core/vault/engine/dummy-job.hpp | 75 --------- wiki/thinkPad.ichthyo.mm | 22 +-- 13 files changed, 231 insertions(+), 276 deletions(-) rename tests/core/{vault => steam}/engine/job-hash-test.cpp (89%) rename tests/core/{vault/engine/dummy-job.cpp => steam/engine/mock-dispatcher.cpp} (87%) rename tests/core/{vault => steam}/engine/scheduler-interface-test.cpp (96%) delete mode 100644 tests/core/vault/engine/dummy-job.hpp diff --git a/src/lib/iter-adapter-ptr-deref.hpp b/src/lib/iter-adapter-ptr-deref.hpp index f42a46284..1081b8e3c 100644 --- a/src/lib/iter-adapter-ptr-deref.hpp +++ b/src/lib/iter-adapter-ptr-deref.hpp @@ -48,41 +48,11 @@ #include "lib/iter-adapter.hpp" -#include +#include -namespace std { - template - class unique_ptr; -} - namespace lib { - namespace { - - /** helper to remove pointer, - * while retaining const */ - template - struct RemovePtr { typedef T Type; }; - - template - struct RemovePtr { typedef T Type; }; - - template - struct RemovePtr { typedef const T Type; }; - - template - struct RemovePtr { typedef const T Type; }; - - template - struct RemovePtr { typedef const T Type; }; - - /** allow automatic dereferencing of std::unique_ptr */ - template - struct RemovePtr> { typedef T Type; }; - } - - /** * wrapper for an existing Iterator type, @@ -98,26 +68,30 @@ namespace lib { public: - typedef typename IT::value_type pointer; - typedef typename RemovePtr::Type value_type; - typedef value_type& reference; + /** this iterator adapter is meant to wrap an iterator yielding pointer values */ + using pointer = typename meta::ValueTypeBinding::value_type; + static_assert(std::is_pointer_v); + + using value_type = typename std::remove_pointer_t; + using reference = value_type&; + ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (PtrDerefIter); - // the purpose of the following typedefs is to ease building a correct "const iterator" + // the purpose of the following typedefs is to support building a correct "const iterator" - typedef typename boost::remove_const::type ValueTypeBase; // value_type without const + using ValueTypeBase = typename std::remove_const_t; // value_type without const - typedef typename IterType::template SimilarIter< ValueTypeBase* * >::Type WrappedIterType; - typedef typename IterType::template SimilarIter::Type WrappedConstIterType; + using WrappedIterType = typename IterType::template SimilarIter< ValueTypeBase* * >::Type; + using WrappedConstIterType = typename IterType::template SimilarIter::Type; - typedef PtrDerefIter IterType; - typedef PtrDerefIter ConstIterType; + using IterType = PtrDerefIter; + using ConstIterType = PtrDerefIter; - /** PtrDerefIter is always created + /** PtrDerefIter is always created * by wrapping an existing iterator. */ explicit @@ -244,7 +218,7 @@ namespace lib { - /** + /** * wrapper for an existing Iterator type to expose the address of each value yielded. * Typically this can be used to build visitation sequences based on values living * within a stable data structure (e.g. unmodifiable STL vector) @@ -280,7 +254,7 @@ namespace lib { ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (AddressExposingIter); - /** AddressExposingIter is always created + /** AddressExposingIter is always created * by wrapping an existing iterator. */ explicit @@ -304,7 +278,7 @@ namespace lib { /** @return address of the source iteraor's current result * @warning exposing a reference to an internal pointer for sake of compatibility. * Clients must not store that reference, but rather use it to initialise - * a copy. The internal pointer exposed here will be changed on increment. + * a copy. The internal pointer exposed here will be changed on increment. */ reference operator*() const diff --git a/src/steam/engine/frame-coord.hpp b/src/steam/engine/frame-coord.hpp index 59285720e..d33d34108 100644 --- a/src/steam/engine/frame-coord.hpp +++ b/src/steam/engine/frame-coord.hpp @@ -32,7 +32,6 @@ #include "steam/common.hpp" #include "steam/mobject/model-port.hpp" #include "lib/time/timevalue.hpp" -#include "lib/time/timequant.hpp" #include diff --git a/src/steam/engine/job-ticket.hpp b/src/steam/engine/job-ticket.hpp index 45b3b4c91..14218032f 100644 --- a/src/steam/engine/job-ticket.hpp +++ b/src/steam/engine/job-ticket.hpp @@ -36,19 +36,14 @@ #define STEAM_ENGINE_JOB_TICKET_H #include "steam/common.hpp" -//#include "steam/state.hpp" #include "vault/engine/job.h" #include "steam/engine/frame-coord.hpp" #include "steam/engine/exit-node.hpp" -//#include "lib/time/timevalue.hpp" -//#include "lib/time/timequant.hpp" #include "lib/hierarchy-orientation-indicator.hpp" #include "lib/linked-elements.hpp" +#include "lib/util-foreach.hpp" #include "lib/iter-adapter.hpp" #include "lib/itertools.hpp" -#include "lib/util-foreach.hpp" -#include "lib/meta/tuple-helper.hpp" -#include "lib/meta/trait.hpp" #include "lib/util.hpp" #include @@ -58,10 +53,6 @@ namespace steam { namespace engine { -//using lib::time::TimeSpan; -//using lib::time::Duration; -//using lib::time::FSecs; -//using lib::time::Time; using vault::engine::Job; using vault::engine::JobFunctor; using vault::engine::JobClosure; /////////////////////////////////////////////////////////////////////TICKET #1287 : fix actual interface down to JobFunctor (after removing C structs) diff --git a/src/steam/fixture/segment.hpp b/src/steam/fixture/segment.hpp index ee10bfc76..469bb54ae 100644 --- a/src/steam/fixture/segment.hpp +++ b/src/steam/fixture/segment.hpp @@ -39,7 +39,6 @@ #include "steam/engine/job-ticket.hpp" #include "lib/allocator-handle.hpp" #include "lib/time/timevalue.hpp" -#include "lib/itertools.hpp" #include "lib/util.hpp" #include diff --git a/src/steam/fixture/segmentation.hpp b/src/steam/fixture/segmentation.hpp index d7ee42c52..4f38551de 100644 --- a/src/steam/fixture/segmentation.hpp +++ b/src/steam/fixture/segmentation.hpp @@ -54,6 +54,7 @@ #include #include +#include namespace steam { @@ -83,19 +84,17 @@ namespace fixture { class Segmentation : util::NonCopyable { - protected: /** segments of the engine in ordered sequence. */ list segments_; - public: - virtual ~Segmentation(); ///< this is an interface - protected: Segmentation() ///< there is always a single cover-all Segment initially : segments_{1} { } public: + virtual ~Segmentation(); ///< this is an interface + size_t size() const { @@ -121,6 +120,16 @@ namespace fixture { /** rework the existing Segmentation to include a new Segment as specified */ Segment const& splitSplice (OptTime start, OptTime after, engine::ExitNodes&& modelLink =ExitNodes{}); + + + protected: + /** @internal rewrite the NodeGraphAttachment in each Segment */ + void + adaptSpecification (std::function rewrite) + { + for (fixture::Segment& seg : segments_) + seg.exitNode = move(rewrite (seg.exitNode)); + } }; diff --git a/tests/core/vault/engine/job-hash-test.cpp b/tests/core/steam/engine/job-hash-test.cpp similarity index 89% rename from tests/core/vault/engine/job-hash-test.cpp rename to tests/core/steam/engine/job-hash-test.cpp index 26b75a637..ff091b912 100644 --- a/tests/core/vault/engine/job-hash-test.cpp +++ b/tests/core/steam/engine/job-hash-test.cpp @@ -29,16 +29,18 @@ #include "lib/util.hpp" #include "vault/real-clock.hpp" -#include "vault/engine/dummy-job.hpp" +#include "steam/engine/mock-dispatcher.hpp" #include -namespace vault { -namespace engine { -namespace test { +namespace steam { +namespace engine{ +namespace test { using util::isSameObject; + using vault::engine::Job; + using vault::engine::JobParameter; @@ -67,23 +69,23 @@ namespace test { void verify_simple_job_properties() { - Job job = DummyJob::build(); + MockJob job; CHECK (job.isValid()); Time beforeInvocation = RealClock::now(); job.triggerJob(); - CHECK (DummyJob::was_invoked (job)); - CHECK (RealClock::now() > DummyJob::invocationTime (job)); - CHECK (beforeInvocation < DummyJob::invocationTime (job)); + CHECK (MockJob::was_invoked (job)); + CHECK (RealClock::now() > MockJob::invocationTime (job)); + CHECK (beforeInvocation < MockJob::invocationTime (job)); } void verify_job_identity() { - Job job1 = DummyJob::build(); - Job job2 = DummyJob::build(); + MockJob job1; + MockJob job2; CHECK (job1 != job2, "random test data clash"); @@ -130,4 +132,4 @@ namespace test { /** Register this test class... */ LAUNCHER(JobHash_test, "unit engine"); -}}} // namespace vault::engine::test +}}} // namespace steam::engine::test diff --git a/tests/core/steam/engine/job-planning-setup-test.cpp b/tests/core/steam/engine/job-planning-setup-test.cpp index 29668e72f..7765e8bb9 100644 --- a/tests/core/steam/engine/job-planning-setup-test.cpp +++ b/tests/core/steam/engine/job-planning-setup-test.cpp @@ -28,19 +28,14 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "steam/engine/mock-dispatcher.hpp" -#include "vault/engine/dummy-job.hpp" #include "lib/format-cout.hpp"///////////////////////TODO #include "lib/iter-tree-explorer.hpp" #include "lib/format-util.hpp" #include "lib/util.hpp" -//#include "steam/engine/job-planning.hpp" - -//#include using test::Test; -//using std::rand; using lib::eachNum; using lib::treeExplore; using lib::time::PQuant; @@ -52,7 +47,6 @@ namespace steam { namespace engine{ namespace test { - using vault::engine::DummyJob; using lib::time::FixedFrameQuantiser; namespace { // test fixture... @@ -83,7 +77,7 @@ namespace test { * - integration: generate a complete sequence of (dummy)Jobs * - scaffolding and mocking used for this test * - * @todo WIP-WIP-WIP 4/2023 + * @todo WIP-WIP 4/2023 * * @see DispatcherInterface_test * @see MockSupport_test @@ -112,12 +106,12 @@ namespace test { Time nominalTime = lib::test::randTime(); int additionalKey = rand() % 5000; - Job mockJob = DummyJob::build (nominalTime, additionalKey); + MockJob mockJob{nominalTime, additionalKey}; mockJob.triggerJob(); - CHECK (DummyJob::was_invoked (mockJob)); - CHECK (RealClock::wasRecently (DummyJob::invocationTime (mockJob))); - CHECK (nominalTime == DummyJob::invocationNominalTime (mockJob) ); - CHECK (additionalKey == DummyJob::invocationAdditionalKey(mockJob)); + CHECK (MockJob::was_invoked (mockJob)); + CHECK (RealClock::wasRecently (MockJob::invocationTime (mockJob))); + CHECK (nominalTime == MockJob::invocationNominalTime (mockJob) ); + CHECK (additionalKey == MockJob::invocationAdditionalKey(mockJob)); // Build a simple Segment at [10s ... 20s[ MockSegmentation mockSegs{MakeRec() @@ -143,10 +137,15 @@ namespace test { jobP.triggerJob(); jobM.triggerJob(); - CHECK (123 == DummyJob::invocationAdditionalKey (jobM)); // verify each job was invoked and linked to the correct spec, - CHECK (555 == DummyJob::invocationAdditionalKey (jobP)); // indicating that in practice it will activate the proper render node - // - ////////////////////////////////////////////////////////////////////TODO: extract Dispatcher-Mock from DispatcherInterface_test + CHECK (123 == MockJob::invocationAdditionalKey (jobM)); // verify each job was invoked and linked to the correct spec, + CHECK (555 == MockJob::invocationAdditionalKey (jobP)); // indicating that in practice it will activate the proper render node + + coord.modelPortIDX = 1; + coord.absoluteNominalTime = Time{0,30}; + MockDispatcher dispatcher; // a complete dispatcher backed by a mock Segment for the whole timeline + auto [port1,sink1] = dispatcher.getDummyConnection(1); // also some fake ModelPort and DataSink entries are registered + Job jobD = dispatcher.getJobTicketFor(coord).createJobFor(coord); + CHECK (dispatcher.verify(jobD, port1, sink1)); // the generated job uses the associated ModelPort and DataSink and JobTicket } diff --git a/tests/core/vault/engine/dummy-job.cpp b/tests/core/steam/engine/mock-dispatcher.cpp similarity index 87% rename from tests/core/vault/engine/dummy-job.cpp rename to tests/core/steam/engine/mock-dispatcher.cpp index 0bc6bff62..a0fa87dfb 100644 --- a/tests/core/vault/engine/dummy-job.cpp +++ b/tests/core/steam/engine/mock-dispatcher.cpp @@ -1,5 +1,5 @@ /* - DummyJob - diagnostic job for unit tests + MockDispatcher - diagnostic render job and frame dispatcher Copyright (C) Lumiera.org 2013, Hermann Vosseler @@ -20,7 +20,7 @@ * *****************************************************/ -/** @file dummy-job.cpp +/** @file mock-dispatcher.cpp ** Implementation of a dummy render job for unit tests. ** Based on using a specifically rigged DummyClosure as JobFunctor, ** where the actual Job invocation does nothing other than storing @@ -32,14 +32,14 @@ ** ** # Usage front-end ** - ** The static functions in vault::engine::DummyJob allow to - ** - build such a mock job, possibly with random (or well defined) parameters - ** - when passing back this job instance, verify invocation and extract data + ** A MockJob can directly created, and then sliced down to the Job baseclass, + ** since it has no additional data fields. The static functions in MockJob allow + ** to verify that a given job instance was created from this setup, that it was + ** invoked, and verify invocation time and extract data */ -#include "vault/engine/dummy-job.hpp" - +#include "steam/engine/mock-dispatcher.hpp" #include "vault/engine/nop-job-functor.hpp" #include "lib/test/test-helper.hpp" #include "lib/time/timevalue.hpp" @@ -50,14 +50,15 @@ #include "lib/util.hpp" #include -#include #include +#include -namespace vault{ -namespace engine { +namespace steam { +namespace engine{ +namespace test { - namespace { // DummyJob implementation details... + namespace { // MockJob and DummyClosure implementation details... using lib::HashVal; using lib::NullValue; @@ -65,14 +66,16 @@ namespace engine { using std::unordered_map; using util::access_or_default; + using vault::engine::JobParameter; + const int MAX_PARAM_A(1000); ///< random test values 0...1000 const int MAX_PARAM_B(10); ///< random test values -10...+10 /** - * test dummy jobs are backed by this closure. - * DummyJob invocations are recorded in a hashtable + * MockJob objects are backed by this closure. + * Invocations of this job functor are recorded in a hashtable * @note as of 5/2023, we use a simplistic map-based implementation, * causing a consecutive invocation of the same job instance * with identical JobParameter to overwrite the previous log entry. @@ -158,7 +161,7 @@ namespace engine { { } }; - /** recording DummyJob invocations */ + /** recording MockJob invocations */ unordered_map invocationLog_; @@ -195,7 +198,7 @@ namespace engine { Job - DummyJob::build() + MockJob::build() { InvocationInstanceID invoKey; invoKey.part.a = rand() % MAX_PARAM_A; @@ -208,7 +211,7 @@ namespace engine { Job - DummyJob::build (Time nominalTime, int additionalKey) + MockJob::build (Time nominalTime, int additionalKey) { InvocationInstanceID invoKey; invoKey.part.a = additionalKey; @@ -219,7 +222,7 @@ namespace engine { bool - DummyJob::was_invoked (Job const& job) + MockJob::was_invoked (Job const& job) { REQUIRE (job.usesClosure (dummyClosure)); @@ -228,7 +231,7 @@ namespace engine { Time - DummyJob::invocationTime (Job const& job) + MockJob::invocationTime (Job const& job) { REQUIRE (job.usesClosure (dummyClosure)); @@ -237,7 +240,7 @@ namespace engine { Time - DummyJob::invocationNominalTime (Job const& job) + MockJob::invocationNominalTime (Job const& job) { REQUIRE (job.usesClosure (dummyClosure)); @@ -246,7 +249,7 @@ namespace engine { int - DummyJob::invocationAdditionalKey (Job const& job) + MockJob::invocationAdditionalKey (Job const& job) { REQUIRE (job.usesClosure (dummyClosure)); @@ -256,7 +259,7 @@ namespace engine { /** @internal for collaboration with other Mock/Dummy facilities */ JobClosure& - DummyJob::getFunctor() + MockJob::getFunctor() { return dummyClosure; } @@ -268,7 +271,7 @@ namespace engine { * @see JobTicket::JobTicket::createJobFor(FrameCoord) */ bool - DummyJob::isNopJob (Job const& job) + MockJob::isNopJob (Job const& job) { InvocationInstanceID empty; ///////////////////////////////////////////////////////////////////////TICKET #1287 : temporary workaround until we get rid of the C base structs JobClosure& jobFunctor = static_cast (*job.jobClosure); //////////////////////////TICKET #1287 : fix actual interface down to JobFunctor (after removing C structs) @@ -278,4 +281,4 @@ namespace engine { -}} // namespace vault::engine +}}} // namespace steam::engine::test diff --git a/tests/core/steam/engine/mock-dispatcher.hpp b/tests/core/steam/engine/mock-dispatcher.hpp index a0093d298..18996fcb8 100644 --- a/tests/core/steam/engine/mock-dispatcher.hpp +++ b/tests/core/steam/engine/mock-dispatcher.hpp @@ -22,19 +22,25 @@ /** @file mock-dispatcher.hpp ** Mock data structures to support implementation testing of render job - ** planning and frame dispatch. Together with dummy-job.hpp, this provides - ** a specifically rigged test setup, allowing to investigate and verify - ** designated functionality in isolation, without backing by the actual - ** render engine implementation. - ** - the MockDispatcherTable emulates the frame dispatch from the Fixture + ** planning and frame dispatch. This specifically rigged test setup allows to + ** investigate and verify designated functionality in isolation, without backing + ** by the actual render engine and low-level-Model implementation. + ** - a MockJob is a render Job, wired to a DummyFunctor, which does nothing, + ** but records any invocation into an internal diagnostics Map. + ** - MockJobTicket is a builder / adapter on top of the actual steam::engine::JobTicket, + ** allowing to generate simple JobTicket instances with an embedded ExitNode and + ** a (configurable) pipelineID. From this setup, »mock jobs« can be generated, + ** which use the MockJob functor and thus record any invocation without performing + ** actual work. The internal connection to the MockJobTicket can then be verified. ** - MockSegmentation is a mocked variant of the »Segmentation« datastructure, ** which forms the backbone of the Fixture and is the top-level attachment - ** point for the »low-level-Model« (the render nodes network) - ** - MockJobTicket is a builder / adapter on top of the actual steam::engine::JobTicket, - ** allowing to generate a complete rigged MockSegmentation setup from a generic - ** test specification written as nested lib::diff::GenNode elements. From this - ** setup, »mock jobs« can be generated, which use the DummyJob functor and - ** just record any invocation without performing actual work. + ** point for the »low-level-Model« (the render nodes network). It can be + ** configured with a test specification of ExitNode(s) defined by a + ** GenNode tree, and defining Segments of the timeline and prerequisites. + ** - finally, the MockDispatcher combines all these facilities to emulate + ** frame dispatch from the Fixture without actually using any data model. + ** Similar to MockSegmentation, a GenNode-based specification is used. + ** ** @remark in spring 2023, this setup was created as a means to define and ** then build the actual implementation of frame dispatch and scheduling. ** @see MockSupport_test @@ -53,7 +59,6 @@ #include "steam/engine/dispatcher.hpp" #include "steam/engine/job-ticket.hpp" #include "vault/engine/job.h" -#include "vault/engine/dummy-job.hpp" #include "vault/real-clock.hpp" #include "lib/allocator-handle.hpp" #include "lib/time/timevalue.hpp" @@ -79,45 +84,57 @@ namespace test { using lib::HashVal; using util::isnil; using util::isSameObject; - ///////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1294 : organisation of namespaces / includes?? using fixture::Segmentation; + using vault::engine::Job; + using vault::engine::JobClosure; - namespace { // used internally - - using play::test::ModelPorts; - using play::test::PlayTestFrames_Strategy; - using vault::engine::JobClosure; - using vault::engine::JobParameter; - using vault::engine::DummyJob; - - using DummyPlaybackSetup = play::test::DummyPlayConnection; - - - - - /* ===== specify a mock JobTicket setup for tests ===== */ - - inline ExitNode - defineSimpleSpec (HashVal seed = 1+rand()) - { - return ExitNode{seed - ,ExitNodes{} - ,& DummyJob::getFunctor()}; - } - - }//(End)internal test helpers.... /** - * Mock setup for a JobTicket to generate DummyJob invocations. + * Mock setup for a render Job with NO action but built-in diagnostics. + * Each invocation of such a MockJob will be logged internally + * and can be investigated and verified afterwards. + */ + class MockJob + : public Job + { + static Job build(); ///< uses random job definition values + static Job build (Time nominalTime, int additionalKey); + + public: + MockJob() + : Job{build()} + { } + + MockJob (Time nominalTime, int additionalKey) + : Job{build (nominalTime,additionalKey)} + { } + + + static bool was_invoked (Job const& job); + static Time invocationTime (Job const& job); + static Time invocationNominalTime (Job const& job); + static int invocationAdditionalKey (Job const& job); + + static bool isNopJob (Job const&); + static JobClosure& getFunctor(); + }; + + + + + + + /** + * Mock setup for a JobTicket to generate dummy render Job invocations. * Implemented as subclass, it provides a specification DSL for tests, * and is able to probe some otherwise opaque internals of JobTicket. * Beyond that, MockJobTicket has the same storage size; and behaves * like the regular JobTicket after construction -- but any Job * created by JobTicket::createJobFor(FrameCoord) will be wired - * with the DummyJob functor and can thus be related back to + * with the MockJob functor and can thus be related back to * the test specification setup. * @see JobPlanningSetup_test * @see DispatcherInterface_test @@ -132,6 +149,15 @@ namespace test { return static_cast&> (*this); } + /** provide a test specification wired to MockJob */ + static ExitNode + defineSimpleSpec (HashVal seed = 1+rand()) + { + return ExitNode{seed + ,ExitNodes{} + ,& MockJob::getFunctor()}; + } + public: MockJobTicket() : JobTicket{defineSimpleSpec(), allocator()} @@ -157,14 +183,14 @@ namespace test { * test, by passing a test specification in »GenNode« notation to the * constructor. This specification defines the segments to create * and allows to associate a marker number, which can later be - * verified from the actual DummyJob invocation. + * verified from the actual DummyClosure invocation. * - the ctor accepts a sequence of GenNode elements, * each corresponding to a segment to created * - optionally, attributes "start" and "after" can be defined * to provide the lib::time::Time values of segment start/end * - in addition, optionally a "mark" attribute can be defined; * the given integer number will be "hidden" in the job instance - * hash, and can be [verified](\ref DummyJob::invocationAdditionalKey) + * hash, and can be [verified](\ref MockJob::invocationAdditionalKey) * - the _scope_ of each top-level GenNode may hold a sequence of * nested nodes corresponding to _prerequisite_ JobTicket instances * - these can in turn hold further nested prerequisites, and so on @@ -198,7 +224,7 @@ namespace test { { return ExitNode{buildSeed (spec) ,buildPrerequisites (spec) - ,& DummyJob::getFunctor()}; + ,& MockJob::getFunctor()}; } /** @internal helper for MockDispatcher */ @@ -238,8 +264,12 @@ namespace test { inline void MockSegmentation::duplicateExitNodeSpec (uint times) { - for (fixture::Segment& seg : segments_) - seg.exitNode = move(fixture::NodeGraphAttachment{ExitNodes{times, seg.exitNode[0]}}); + using Spec = fixture::NodeGraphAttachment; + + Segmentation::adaptSpecification ([times](Spec const& spec) + { + return Spec{ExitNodes{times, spec[0]}}; + }); } @@ -273,6 +303,28 @@ namespace test { + namespace { // used internally by MockDispatcher.... + using play::test::ModelPorts; + using play::test::PlayTestFrames_Strategy; + + using DummyPlaybackSetup = play::test::DummyPlayConnection; + } + + + + /** + * A mocked frame Dispatcher setup without any backing model. + * Instantiating such a MockDispatcher will automatically create some fake + * model structures and some ModelPort and DisplaySink handles (and thereby + * push aside and shadow any existing ModelPort registry). + * + * The configuration is similar to MockSegmentation, using a test spec + * given as GenNode-tree to define Segments of the timeline and possibly + * pipeline-IDs and prerequisites. One notable difference is that here + * the default ctor always creates a single Segment covering the whole + * time axis, and that the ExitNode specification is automatically + * duplicated for all faked ModelPort(s). + */ class MockDispatcher : public Dispatcher { @@ -285,8 +337,9 @@ namespace test { const PortIdxMap portIdx_; public: - /* == mock Dispatcher implementation == */ + /* == mock implementation of the Dispatcher interface == */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1276 : likely to become obsolete FrameCoord locateRelative (FrameCoord const&, FrameCnt frameOffset) override { @@ -298,7 +351,7 @@ namespace test { { UNIMPLEMENTED ("determine when to finish a planning chunk"); } - +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1276 : likely to become obsolete size_t resolveModelPort (ModelPort modelPort) override @@ -319,6 +372,7 @@ namespace test { } + public: MockDispatcher() : dummySetup_{} , mockSeg_{MakeRec().genNode()} // Node: generate a single active Segment to cover all @@ -368,7 +422,7 @@ namespace test { TimeValue nominalTime{job.parameter.nominalTime}; size_t portIDX = resolveModelPort (port); JobTicket& ticket = accessJobTicket (portIDX, nominalTime); - return isnil (ticket)? DummyJob::isNopJob (job) + return isnil (ticket)? MockJob::isNopJob (job) : MockJobTicket::isAssociated (job, ticket); } @@ -388,9 +442,6 @@ namespace test { } }; -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221 -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221 - }}} // namespace steam::engine::test #endif /*STEAM_ENGINE_TEST_MOCK_DISPATCHER_H*/ diff --git a/tests/core/steam/engine/mock-support-test.cpp b/tests/core/steam/engine/mock-support-test.cpp index 6c513f9f1..ae6f21b93 100644 --- a/tests/core/steam/engine/mock-support-test.cpp +++ b/tests/core/steam/engine/mock-support-test.cpp @@ -29,7 +29,6 @@ #include "lib/test/test-helper.hpp" #include "steam/engine/mock-dispatcher.hpp" #include "vault/engine/nop-job-functor.hpp" -#include "vault/engine/dummy-job.hpp" #include "lib/iter-tree-explorer.hpp" #include "lib/util-tuple.hpp" #include "lib/util.hpp" @@ -43,7 +42,6 @@ namespace engine{ namespace test { using steam::fixture::Segment; - using vault::engine::DummyJob; using lib::singleValIterator; using util::isSameObject; using util::seqTuple; @@ -55,6 +53,7 @@ namespace test { * - creating and invoking mock render jobs * - a mocked JobTicket, generating mock render jobs * - configurable test setup for a mocked Segmentation datastructure + * - configurable setup of a complete frame Dispatcher * @see JobPlanningSetup_test * @see Dispatcher * @see vault::engine::Job @@ -95,7 +94,7 @@ namespace test { CHECK (MockJobTicket::isAssociated (job, ticket)); job.triggerJob(); - CHECK (DummyJob::was_invoked (job)); + CHECK (MockJob::was_invoked (job)); } @@ -107,21 +106,21 @@ namespace test { { Time nominalTime = lib::test::randTime(); int additionalKey = rand() % 5000; - Job mockJob = DummyJob::build (nominalTime, additionalKey); + MockJob mockJob{nominalTime, additionalKey}; CHECK (mockJob.getNominalTime() == nominalTime); - CHECK (not DummyJob::was_invoked (mockJob)); + CHECK (not MockJob::was_invoked (mockJob)); mockJob.triggerJob(); - CHECK (DummyJob::was_invoked (mockJob)); - CHECK (RealClock::wasRecently (DummyJob::invocationTime (mockJob))); - CHECK (nominalTime == DummyJob::invocationNominalTime (mockJob) ); - CHECK (additionalKey == DummyJob::invocationAdditionalKey(mockJob)); + CHECK (MockJob::was_invoked (mockJob)); + CHECK (RealClock::wasRecently (MockJob::invocationTime (mockJob))); + CHECK (nominalTime == MockJob::invocationNominalTime (mockJob) ); + CHECK (additionalKey == MockJob::invocationAdditionalKey(mockJob)); - Time prevInvocation = DummyJob::invocationTime (mockJob); + Time prevInvocation = MockJob::invocationTime (mockJob); mockJob.triggerJob(); - CHECK (prevInvocation < DummyJob::invocationTime (mockJob)); // invoked again, recorded new invocation time - CHECK (nominalTime == DummyJob::invocationNominalTime (mockJob) ); // all other Job parameter recorded again unaltered - CHECK (additionalKey == DummyJob::invocationAdditionalKey(mockJob)); + CHECK (prevInvocation < MockJob::invocationTime (mockJob)); // invoked again, recorded new invocation time + CHECK (nominalTime == MockJob::invocationNominalTime (mockJob) ); // all other Job parameter recorded again unaltered + CHECK (additionalKey == MockJob::invocationAdditionalKey(mockJob)); } @@ -182,12 +181,12 @@ namespace test { Job someJob = ticket.createJobFor(coord); // JobTicket uses, but does not check the time given in FrameCoord CHECK (someJob.parameter.nominalTime == _raw(coord.absoluteNominalTime)); CHECK (MockJobTicket::isAssociated (someJob, ticket)); // but the generated Job is linked to the Closure backed by the JobTicket - CHECK (not DummyJob::was_invoked (someJob)); + CHECK (not MockJob::was_invoked (someJob)); someJob.triggerJob(); - CHECK (DummyJob::was_invoked (someJob)); - CHECK (RealClock::wasRecently (DummyJob::invocationTime (someJob))); - CHECK (someTime == DummyJob::invocationNominalTime (someJob)); + CHECK (MockJob::was_invoked (someJob)); + CHECK (RealClock::wasRecently (MockJob::invocationTime (someJob))); + CHECK (someTime == MockJob::invocationNominalTime (someJob)); } //-----------------------------------------------------------------/// Segmentation with a segment spanning part of the timeline > 10s { @@ -214,9 +213,9 @@ namespace test { CHECK (marker == job.parameter.invoKey.part.a); job.triggerJob(); - CHECK (DummyJob::was_invoked (job)); - CHECK (RealClock::wasRecently (DummyJob::invocationTime (job))); - CHECK (marker == DummyJob::invocationAdditionalKey (job)); // DummyClosure is rigged such as to feed back the seed in `part.a` + CHECK (MockJob::was_invoked (job)); + CHECK (RealClock::wasRecently (MockJob::invocationTime (job))); + CHECK (marker == MockJob::invocationAdditionalKey (job)); // DummyClosure is rigged such as to feed back the seed in `part.a` // and thus we can prove this job really belongs to the marked segment // create another job from the (empty) seg1 job = seg1.jobTicket(0).createJobFor (coord); @@ -250,7 +249,7 @@ namespace test { Job job = s2.jobTicket(0).createJobFor(coord); job.triggerJob(); - CHECK (marker == DummyJob::invocationAdditionalKey (job)); + CHECK (marker == MockJob::invocationAdditionalKey (job)); } //-----------------------------------------------------------------/// Segmentation with several segments built in specific order { @@ -293,10 +292,10 @@ namespace test { Job job = segment.jobTicket(0).createJobFor(coord); job.triggerJob(); - CHECK (DummyJob::was_invoked (job)); - CHECK (RealClock::wasRecently (DummyJob::invocationTime (job))); + CHECK (MockJob::was_invoked (job)); + CHECK (RealClock::wasRecently (MockJob::invocationTime (job))); - return DummyJob::invocationAdditionalKey (job); + return MockJob::invocationAdditionalKey (job); }; CHECK (2 == probeKey(s1)); // verify all generated jobs are wired back to the correct segment CHECK (3 == probeKey(s2)); @@ -339,8 +338,8 @@ namespace test { job1.triggerJob(); job2.triggerJob(); - CHECK (23 == DummyJob::invocationAdditionalKey (job1)); - CHECK (11 == DummyJob::invocationAdditionalKey (job2)); + CHECK (23 == MockJob::invocationAdditionalKey (job1)); + CHECK (11 == MockJob::invocationAdditionalKey (job2)); } //-----------------------------------------------------------------/// a tree of deep nested prerequisites { diff --git a/tests/core/vault/engine/scheduler-interface-test.cpp b/tests/core/steam/engine/scheduler-interface-test.cpp similarity index 96% rename from tests/core/vault/engine/scheduler-interface-test.cpp rename to tests/core/steam/engine/scheduler-interface-test.cpp index 3b3f16f31..c940a4fde 100644 --- a/tests/core/vault/engine/scheduler-interface-test.cpp +++ b/tests/core/steam/engine/scheduler-interface-test.cpp @@ -31,7 +31,7 @@ #include "vault/real-clock.hpp" #include "vault/engine/scheduler-frontend.hpp" #include "vault/engine/scheduler-diagnostics.hpp" -#include "vault/engine/dummy-job.hpp" +#include "steam/engine/mock-dispatcher.hpp" namespace vault { @@ -44,6 +44,8 @@ namespace test { using lib::time::Offset; using lib::time::FSecs; + using steam::engine::test::MockJob; + namespace { // test fixture: scheduling a dummy job operation... @@ -92,7 +94,7 @@ namespace test { { SchedulerDiagnostics monitor(scheduler); - Job job = DummyJob::build(); + MockJob job; Time deadline(TEST_START_TIME); scheduler.startJobTransaction() @@ -112,8 +114,8 @@ namespace test { JobTransaction tx = scheduler.startJobTransaction(); - Job job1 = DummyJob::build(); - Job job2 = DummyJob::build(); + MockJob job1; + MockJob job2; tx.addFreewheeling(job1); tx.addBackground (job2); @@ -178,7 +180,7 @@ namespace test { Time nominalTime(dummyFrameStart(frameNr)); Time deadline(TEST_START_TIME + nominalTime); - Job job = DummyJob::build(nominalTime, frameNr); + MockJob job{nominalTime, frameNr}; currentTx.addJob (deadline, job); diff --git a/tests/core/vault/engine/dummy-job.hpp b/tests/core/vault/engine/dummy-job.hpp deleted file mode 100644 index d2828b151..000000000 --- a/tests/core/vault/engine/dummy-job.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - DUMMY-JOB.hpp - diagnostic job for unit tests - - Copyright (C) Lumiera.org - 2013, Hermann Vosseler - - 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 dummy-job.hpp - ** Unit test helper to generate dummy render jobs. - ** Render Jobs generated from this setup will not actually perform - ** any action, other than recording this invocation and the used - ** parameters into a map table managed behind the scenes. Using - ** the provided query function, it is possible to probe for such - ** an invocation and to extract the recorded parameter data. - ** - ** This setup is used both for stand-alone tests, which just require - ** "some job", but also as part of a complete hierarchy of mocked - ** data structures related to frame job dispatch and invocation - ** @see mock-dispatcher.hpp - ** @see MockSupport_test - ** - */ - - -#ifndef VAULT_ENGINE_DUMMY_JOB_H -#define VAULT_ENGINE_DUMMY_JOB_H - - - -#include "vault/engine/job.h" -#include "lib/time/timevalue.hpp" - - -namespace vault{ -namespace engine { - - using lib::time::Time; - - - /** - * Test helper: generate test dummy jobs with built-in diagnostics. - * Each invocation of such a dummy job will be logged internally - * and can be investigated and verified afterwards. - */ - struct DummyJob - { - static Job build(); ///< uses random job definition values - static Job build (Time nominalTime, int additionalKey); - - static bool was_invoked (Job const& job); - static Time invocationTime (Job const& job); - static Time invocationNominalTime (Job const& job); - static int invocationAdditionalKey (Job const& job); - - static JobClosure& getFunctor(); - static bool isNopJob (Job const&); - }; - -}} // namespace vault::engine -#endif diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index ee8d470e9..8c950d1bb 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -70119,7 +70119,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -70128,9 +70128,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + @@ -70277,7 +70278,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -70316,7 +70318,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -70327,17 +70329,18 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

- + - - + + - + + @@ -70379,7 +70382,6 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
-