/* MOCK-DISPATCHER.hpp - test scaffolding to verify render job planning and dispatch Copyright (C) Lumiera.org 2023, 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 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 ** - 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. ** @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 */ #ifndef STEAM_ENGINE_TEST_MOCK_DISPATCHER_H #define STEAM_ENGINE_TEST_MOCK_DISPATCHER_H #include "lib/test/test-helper.hpp" #include "steam/play/dummy-play-connection.hpp" #include "steam/fixture/node-graph-attachment.hpp" #include "steam/fixture/segmentation.hpp" #include "steam/mobject/model-port.hpp" #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/time/timevalue.hpp" #include "lib/diff/gen-node.hpp" #include "lib/linked-elements.hpp" #include "lib/itertools.hpp" #include "lib/depend.hpp" #include #include namespace steam { namespace engine { namespace test { using std::make_tuple; using lib::diff::GenNode; using lib::diff::MakeRec; using lib::time::TimeValue; using lib::time::Time; using lib::HashVal; ///////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1294 : organisation of namespaces / includes?? using fixture::Segmentation; 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 =0) { return ExitNode{seed ,ExitNodes{} ,& DummyJob::getFunctor()}; } }//(End)internal test helpers.... /** * Mock setup for a JobTicket to generate DummyJob 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 * the test specification setup. * @see JobPlanningSetup_test * @see DispatcherInterface_test */ class MockJobTicket : public JobTicket { public: MockJobTicket() : JobTicket{defineSimpleSpec()} { } MockJobTicket (HashVal seed) : JobTicket{defineSimpleSpec (seed)} { } // template // MockJobTicket (HashVal seed, IT&& prereq) // : JobTicket{defineSpec (seed, std::forward (prereq))} // { } /* ===== Diagnostics ===== */ bool verify_associated (Job const&) const; static bool isAssociated (Job const&, JobTicket const&); }; /** * Mock setup for a complete Segmentation to emulate the structure * of the actual fixture, without the need of building a low-level Model. * MockSegmentation instances can be instantiated directly within the * 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. * - 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) * - 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 * @see MockSetup_test::verify_MockSegmentation */ class MockSegmentation : public Segmentation { // simulated allocator; // must be able to handle re-entrant allocations std::list tickets_; public: MockSegmentation() : Segmentation{} , tickets_{} { } MockSegmentation (std::initializer_list specs) : MockSegmentation{} { for (auto& spec : specs) { auto start = spec.retrieveAttribute