Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
mock-dispatcher.hpp
Go to the documentation of this file.
1/*
2 MOCK-DISPATCHER.hpp - test scaffolding to verify render job planning and dispatch
3
4 Copyright (C)
5 2023, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
41#ifndef STEAM_ENGINE_TEST_MOCK_DISPATCHER_H
42#define STEAM_ENGINE_TEST_MOCK_DISPATCHER_H
43
44
52#include "vault/gear/job.h"
53#include "vault/real-clock.hpp"
56#include "lib/diff/gen-node.hpp"
58#include "lib/itertools.hpp"
59#include "lib/depend.hpp"
60#include "lib/util.hpp"
61
62#include <tuple>
63#include <map>
64
65
66namespace steam {
67namespace engine {
68namespace test {
69
70 using std::make_tuple;
74 using lib::time::Time;
75 using lib::HashVal;
76 using lib::ranHash;
77 using lib::rani;
78 using util::isnil;
80 using fixture::Segmentation;
81 using vault::RealClock;
82 using vault::gear::Job;
84
85
86
87
88
94 class MockJob
95 : public Job
96 {
97 static Job build();
98 static Job build (Time nominalTime, int additionalKey);
99
100 public:
102 : Job{build()}
103 { }
104
105 MockJob (Time nominalTime, int additionalKey)
106 : Job{build (nominalTime,additionalKey)}
107 { }
108
109
110 static bool was_invoked (Job const& job);
111 static Time invocationTime (Job const& job);
112 static Time invocationNominalTime (Job const& job);
113 static int invocationAdditionalKey (Job const& job);
114
115 static bool isNopJob (Job const&);
116 static JobClosure& getFunctor();
117 };
118
119
120
121
122
123
137 : private lib::AllocatorHandle<JobTicket>
138 , public JobTicket
139 {
140 auto&
142 {
143 return static_cast<lib::AllocatorHandle<JobTicket>&> (*this);
144 }
145
147 static ExitNode
148 defineSimpleSpec (HashVal seed =ranHash())
149 {
150 return ExitNode{seed, DUMMY_JOB_RUNTIME
151 ,ExitNodes{}
153 }
154
155 public:
159
160 MockJobTicket (HashVal seed)
162 { }
163
164
165 /* ===== Diagnostics ===== */
166
167 bool verify_associated (Job const&) const;
168 static bool isAssociated (Job const&, JobTicket const&);
169 };
170
171
172
194 : public Segmentation
195 {
196
197 public:
201
202 MockSegmentation (std::initializer_list<GenNode> specs)
204 {
205 for (auto& spec : specs)
206 {
207 auto start = spec.retrieveAttribute<Time> ("start");
208 auto after = spec.retrieveAttribute<Time> ("after");
209 Segmentation::splitSplice (start, after
211 );
212 }
213 }
214
215
218 {
219 return ExitNode{buildSeed (spec)
220 ,buildRuntime (spec)
221 ,buildPrerequisites (spec)
223 }
224
226 void duplicateExitNodeSpec (uint times);
227
228
229 private: /* ======== Implementation: build fake ExitNodes from test specification ==== */
230
231 HashVal
232 buildSeed (GenNode const& spec)
233 {
234 auto seed = spec.retrieveAttribute<int> ("mark");
235 return seed? HashVal(*seed) : HashVal(1 +rani(1000));
236 }
237
239 buildRuntime (GenNode const& spec)
240 {
241 auto runtime = spec.retrieveAttribute<Duration> ("runtime");
242 return runtime? *runtime : DUMMY_JOB_RUNTIME;
243 }
244
247 {
248 ExitNodes prerequisites;
249 for (auto& child : spec.getChildren())
250 prerequisites.emplace_back (
251 buildExitNodeFromSpec (child));
252 return prerequisites;
253 }
254 };
255
256
257
258
266 inline void
268 {
269 using Spec = fixture::NodeGraphAttachment;
270
271 Segmentation::adaptSpecification ([times](Spec const& spec)
272 {
273 return Spec{ExitNodes(times, spec[0])};
274 }); // vector with <times> copies of spec[0]
275 } // (Warning: use parens, not braces for this ctor...)
276
277
283 inline bool
285 {
286 JobFunctor& functor = dynamic_cast<JobFunctor&> (static_cast<JobClosure&> (*job.jobClosure));
287 Time nominalTime {TimeValue{job.parameter.nominalTime}};
288 InvocationInstanceID const& invoKey = job.parameter.invoKey;
289 return this->isValid()
290 and this->verifyInstance(functor, invoKey, nominalTime);
291 }
292
299 inline bool
300 MockJobTicket::isAssociated (Job const& job, JobTicket const& ticket)
301 { // should work always, since storage is the same
302 MockJobTicket const& backdoor = static_cast<MockJobTicket const&> (ticket);
303 return backdoor.verify_associated (job);
304 }
305
306
307
308 namespace { // used internally by MockDispatcher....
311
313 }
314
315
316
331 : public Dispatcher
332 {
333
334 DummyPlaybackSetup dummySetup_;
336
337 using PortIdxMap = std::map<ModelPort, size_t>;
338
340
341 public:
342 /* == mock implementation of the Dispatcher interface == */
343
344 size_t
345 resolveModelPort (ModelPort modelPort) override
346 {
347 auto entry = portIdx_.find(modelPort);
348 if (entry == portIdx_.end())
349 throw error::Logic{"Invalid ModelPort for this Dispatcher"};
350 else
351 return entry->second;
352 }
353
354
355 JobTicket&
356 getJobTicketFor (size_t portIDX, TimeValue nominalTime) override
357 {
358 auto& seg = mockSeg_[nominalTime];
359 return seg.jobTicket(portIDX);
360 }
361
362
363 public:
365 : dummySetup_{}
366 , mockSeg_{MakeRec().genNode()} // Node: generate a single active Segment to cover all
368 {
370 }
371
372 MockDispatcher (std::initializer_list<GenNode> specs)
373 : dummySetup_{}
374 , mockSeg_(specs)
376 {
378 }
379
380
383 {
384 ModelPorts mockModelPorts = dummySetup_.getAllModelPorts();
385 return *mockModelPorts; // using just the first dummy port
386 }
387
399 {
400 return dummySetup_.getModelPort (index);
401 }
402
406 bool verify(Job const& job, ModelPort const& port, play::DataSink const& sink)
407 {
408 if (not dummySetup_.isSupported (port, sink)) return false;
409
410 TimeValue nominalTime{job.parameter.nominalTime};
411 size_t portIDX = resolveModelPort (port);
412 JobTicket& ticket = getJobTicketFor (portIDX, nominalTime);
413 return isnil (ticket)? MockJob::isNopJob (job)
414 : MockJobTicket::isAssociated (job, ticket);
415 }
416
417 private:
420 {
421 PortIdxMap newIndex;
422 uint i{0};
423 for (auto it=dummySetup_.getAllModelPorts()
424 ; bool{it}
425 ; ++it, ++i
426 )
427 newIndex[*it] = i;
428
429 return newIndex;
430 }
431 };
432
433
434}}} // namespace steam::engine::test
435#endif /*STEAM_ENGINE_TEST_MOCK_DISPATCHER_H*/
A front-end/concept to allow access to custom memory management.
Placeholder implementation for a custom allocator.
Duration is the internal Lumiera time metric.
basic constant internal time value.
Lumiera's internal time value datatype.
Internal abstraction: a service within the engine for translating a logical calculation stream (corre...
A top-level point in the render node network where data generation can be driven.
Definition exit-node.hpp:65
execution plan for pulling a specific exit node.
bool verifyInstance(JobFunctor &, InvocationInstanceID const &, Time) const
Helper for tests: verify the given invocation parameters match this JobTicket.
A mocked frame Dispatcher setup without any backing model.
bool verify(Job const &job, ModelPort const &port, play::DataSink const &sink)
Test support: verify the given Job is consistent with this Dispatcher.
size_t resolveModelPort(ModelPort modelPort) override
translate a generic ModelPort spec into the specific index number applicable at the Timeline referred...
play::test::DummyOutputLink getDummyConnection(uint index)
The faked builder/playback setup provides some preconfigured ModelPort and corresponding DataSink han...
MockDispatcher(std::initializer_list< GenNode > specs)
JobTicket & getJobTicketFor(size_t portIDX, TimeValue nominalTime) override
Core Dispatcher operation: locate the appropriate Segment and retrieve/derive a »blueprint« for rende...
std::map< ModelPort, size_t > PortIdxMap
Mock setup for a JobTicket to generate dummy render Job invocations.
bool verify_associated(Job const &) const
verify the given job instance was actually generated from this JobTicket.
static ExitNode defineSimpleSpec(HashVal seed=ranHash())
provide a test specification wired to MockJob
static bool isAssociated(Job const &, JobTicket const &)
convenience shortcut to perform this test on arbitrary JobTicket and Job instances.
Mock setup for a render Job with NO action but built-in diagnostics.
static bool was_invoked(Job const &job)
static Time invocationNominalTime(Job const &job)
static int invocationAdditionalKey(Job const &job)
static Job build()
uses random job definition values
static Time invocationTime(Job const &job)
static JobClosure & getFunctor()
MockJob(Time nominalTime, int additionalKey)
static bool isNopJob(Job const &)
Mock setup for a complete Segmentation to emulate the structure of the actual fixture,...
HashVal buildSeed(GenNode const &spec)
Duration buildRuntime(GenNode const &spec)
void duplicateExitNodeSpec(uint times)
This is some trickery to allow handling of multiple ModelPort(s) in MockDispatcher; actually the code...
MockSegmentation(std::initializer_list< GenNode > specs)
ExitNode buildExitNodeFromSpec(GenNode const &spec)
ExitNodes buildPrerequisites(GenNode const &spec)
Binding and access point from a given Segment to access the actual render nodes.
For the purpose of building and rendering, the fixture (for each timeline) is partitioned such that e...
Segment const & splitSplice(OptTime start, OptTime after, engine::ExitNodes &&modelLink=ExitNodes{})
rework the existing Segmentation to include a new Segment as specified
void adaptSpecification(std::function< NodeGraphAttachment(NodeGraphAttachment const &)> rewrite)
Handle designating a point within the model, where actually output data can be pulled.
denotes an opened connection ready to receive media data for output.
Framework for dummy playback and rendering.
Convenience frontend to access the current raw system time.
Interface of the closure for frame rendering jobs.
Definition job.h:244
Individual frame rendering task, forwarding to a closure.
Definition job.h:276
Singleton services and Dependency Injection.
Service abstraction within the render engine for generating render jobs.
Dummy and test setup of playback and rendering, omitting most of the Lumiera engine.
Generic building block for tree shaped (meta)data structures.
unsigned int uint
Definition integral.hpp:29
Helpers for working with iterators based on the pipeline model.
Execution plan to generate render jobs within a specific render process.
Definition of a render job.
opaque ID attached to each individual job invocation.
Definition job.h:105
Intrusive single linked list with optional ownership.
Organising the output data calculation possibilities.
lib::HashVal ranHash()
Definition random.hpp:155
int rani(uint bound=_iBOUND())
Definition random.hpp:135
size_t HashVal
a STL compatible hash value
Definition hash-value.h:52
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
std::deque< engine::ExitNode > ExitNodes
Definition exit-node.hpp:43
std::pair< mobject::ModelPort, play::DataSink > DummyOutputLink
Steam-Layer implementation namespace root.
Test runner and basic definitions for tests.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
Definition util.hpp:421
bool isnil(lib::time::Duration const &dur)
Link from the Fixture datastructure into the render node network.
Front-end for simplified access to the current wall clock time.
Part of the Fixture datastructure to manage time segments of constant structure.
generic data element node within a tree
Definition gen-node.hpp:224
Rec::scopeIter getChildren() const
Definition gen-node.hpp:825
std::optional< X > retrieveAttribute(string key) const
mismatch tolerant convenience shortcut to peek into the attributes of a nested Record
Definition gen-node.hpp:801
A collection of frequently used helper functions to support unit testing.
a family of time value like entities and their relationships.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...