Lumiera  0.pre.03
»edityourfreedom«
dispatcher-looper-test.cpp
Go to the documentation of this file.
1 /*
2  DispatcherLooper(Test) - verify loop control and timing functionality of ProcDispatcher
3 
4  Copyright (C) Lumiera.org
5  2016, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
24 #include "lib/test/run.hpp"
25 #include "proc/control/looper.hpp"
26 
27 #include <chrono>
28 #include <thread>
29 
30 
31 namespace proc {
32 namespace control {
33 namespace test {
34 
35  using std::this_thread::sleep_for;
36  using namespace std::chrono_literals;
37 
38 
39  namespace { // test fixture...
40 
45  const uint EXPECTED_BUILDER_DELAY_ms = 50;
46 
47  bool
48  isFast (uint timeoutDelay_ms)
49  {
50  return timeoutDelay_ms < 1.2 * EXPECTED_BUILDER_DELAY_ms
51  and 0 < timeoutDelay_ms;
52  }
53 
54  bool
55  isSlow (uint timeoutDelay_ms)
56  {
57  return timeoutDelay_ms >= 1.2 * EXPECTED_BUILDER_DELAY_ms;
58  }
59 
60  bool
61  isDisabled (uint timeoutDelay_ms)
62  {
63  return 0 == timeoutDelay_ms;
64  }
65 
66 
73  struct Setup
74  {
75  bool has_commands_in_queue = false;
76 
77  Looper
78  install()
79  {
80  return Looper([&](){ return has_commands_in_queue; });
81  }
82  };
83 
84  }//(End) test fixture
85 
86 
87 
88 
89 
90 
91 
92  /******************************************************************************/
102  class DispatcherLooper_test : public Test
103  {
104 
105 
106  virtual void
108  {
109  verifyBasics();
110  verifyShutdown();
111  verifyWakeupActivity();
112  verifyShutdown_stops_processing();
113  verifyDisabling_stops_processing();
114  verifyBuilderStart();
115  }
116 
117 
118  void
120  {
121  Setup setup;
122  Looper looper = setup.install();
123 
124  CHECK (not looper.isDying());
125  CHECK (looper.shallLoop());
126  CHECK (not looper.runBuild());
127  CHECK (isDisabled (looper.getTimeout()));
128 
129  setup.has_commands_in_queue = true;
130  CHECK (looper.requireAction());
131 
132  uint timeout = looper.getTimeout();
133  CHECK (10 < timeout, "configured idle timeout %2u to short", timeout);
134  CHECK (timeout < 800, "configured idle timeout %3u to long", timeout);
135  }
136 
137 
138  void
140  {
141  Setup setup;
142  Looper looper = setup.install();
143 
144  CHECK (not looper.isDying());
145  CHECK (looper.shallLoop());
146 
147  looper.triggerShutdown();
148  CHECK (looper.isDying());
149  CHECK (not looper.shallLoop());
150  }
151 
152 
153  void
155  {
156  Setup setup;
157  Looper looper = setup.install();
158 
159  CHECK (not looper.isDying());
160  CHECK (looper.shallLoop());
161 
162  CHECK (not looper.requireAction());
163  CHECK (not looper.isWorking());
164  CHECK ( looper.isIdle());
165 
166  setup.has_commands_in_queue = true;
167 
168  CHECK ( looper.requireAction());
169  CHECK ( looper.isWorking());
170  CHECK (not looper.isIdle());
171  CHECK (looper.shallLoop());
172 
173  setup.has_commands_in_queue = false;
174  looper.markStateProcessed(); // after command processing
175  looper.markStateProcessed(); // after builder run
176 
177  CHECK (not looper.requireAction());
178  CHECK (not looper.isWorking());
179  CHECK ( looper.isIdle());
180  CHECK (looper.shallLoop());
181 
182  looper.triggerShutdown();
183 
184  CHECK (not looper.shallLoop());
185 
186  CHECK ( looper.requireAction());
187  CHECK (not looper.isWorking());
188  CHECK (not looper.isIdle());
189  }
190 
191 
192  void
194  {
195  Setup setup;
196  Looper looper = setup.install();
197 
198  CHECK (not looper.isDying());
199  CHECK (looper.shallLoop());
200 
201  CHECK (not looper.requireAction());
202  CHECK (not looper.isWorking());
203  CHECK ( looper.isIdle());
204 
205  setup.has_commands_in_queue = true;
206 
207  CHECK ( looper.requireAction());
208  CHECK ( looper.isWorking());
209  CHECK (not looper.isIdle());
210  CHECK ( looper.shallLoop());
211  CHECK (not looper.isDying());
212 
213  looper.triggerShutdown();
214 
215  CHECK ( looper.requireAction());
216  CHECK (not looper.isWorking());
217  CHECK (not looper.isIdle());
218  CHECK (not looper.shallLoop());
219  CHECK ( looper.isDying());
220 
221  setup.has_commands_in_queue = false;
222 
223  CHECK ( looper.requireAction());
224  CHECK (not looper.isWorking());
225  CHECK (not looper.isIdle());
226  CHECK (not looper.shallLoop());
227  CHECK ( looper.isDying());
228 
229  setup.has_commands_in_queue = true;
230 
231  CHECK ( looper.requireAction());
232  CHECK (not looper.isWorking());
233  CHECK (not looper.isIdle());
234  CHECK (not looper.shallLoop());
235  CHECK ( looper.isDying());
236  }
237 
238 
239  void
241  {
242  Setup setup;
243  Looper looper = setup.install();
244 
245  CHECK (not looper.requireAction());
246  CHECK (not looper.isDisabled());
247  CHECK (not looper.isWorking());
248  CHECK ( looper.isIdle());
249  CHECK ( looper.shallLoop());
250  CHECK (not looper.isDying());
251 
252  setup.has_commands_in_queue = true; // normal operation: pending commands will be processed
253 
254  CHECK ( looper.requireAction()); // ..causes wake-up
255  CHECK (not looper.isDisabled());
256  CHECK ( looper.isWorking());
257  CHECK (not looper.isIdle());
258  CHECK ( looper.shallLoop());
259  CHECK (not looper.isDying());
260 
261  looper.enableProcessing(false); // disable processing
262 
263  CHECK (not looper.requireAction());
264  CHECK ( looper.isDisabled());
265  CHECK (not looper.isWorking());
266  CHECK (not looper.isIdle());
267  CHECK ( looper.shallLoop());
268  CHECK (not looper.isDying());
269 
270  setup.has_commands_in_queue = false; // while disabled, state of the command queue has no effect
271 
272  CHECK (not looper.requireAction());
273  CHECK ( looper.isDisabled());
274  CHECK (not looper.isWorking());
275  CHECK (not looper.isIdle());
276  CHECK ( looper.shallLoop());
277  CHECK (not looper.isDying());
278 
279  setup.has_commands_in_queue = true;
280 
281  CHECK (not looper.requireAction());
282  CHECK ( looper.isDisabled());
283  CHECK (not looper.isWorking());
284  CHECK (not looper.isIdle());
285  CHECK ( looper.shallLoop());
286  CHECK (not looper.isDying());
287 
288  looper.enableProcessing(); // resume normal operation
289 
290  CHECK ( looper.requireAction());
291  CHECK (not looper.isDisabled());
292  CHECK ( looper.isWorking());
293  CHECK (not looper.isIdle());
294  CHECK ( looper.shallLoop());
295  CHECK (not looper.isDying());
296 
297  looper.enableProcessing(false); // disable again
298 
299  CHECK (not looper.requireAction());
300  CHECK ( looper.isDisabled());
301  CHECK (not looper.isWorking());
302  CHECK (not looper.isIdle());
303  CHECK ( looper.shallLoop());
304  CHECK (not looper.isDying());
305 
306  looper.triggerShutdown(); // wake-up for shutdown even from disabled state
307 
308  CHECK ( looper.requireAction());
309  CHECK ( looper.isDisabled());
310  CHECK (not looper.isWorking());
311  CHECK (not looper.isIdle());
312  CHECK (not looper.shallLoop());
313  CHECK ( looper.isDying());
314  }
315 
316 
326  void
328  {
329  Setup setup;
330  Looper looper = setup.install();
331 
332  CHECK (not looper.requireAction());
333  CHECK (not looper.isDisabled());
334  CHECK (not looper.isWorking());
335  CHECK (not looper.runBuild());
336  CHECK ( looper.isIdle());
337 
338  setup.has_commands_in_queue = true; // regular command processing
339 
340  CHECK ( looper.requireAction());
341  CHECK (not looper.isDisabled());
342  CHECK ( looper.isWorking());
343  CHECK (not looper.runBuild());
344  CHECK (not looper.isIdle());
345 
346  looper.markStateProcessed(); // at least one command has been handled
347 
348  CHECK ( looper.requireAction());
349  CHECK (not looper.isDisabled());
350  CHECK ( looper.isWorking());
351  CHECK (not looper.runBuild()); // ...note: build not yet triggered
352  CHECK (not looper.isIdle());
353 
354  CHECK (isSlow (looper.getTimeout()));
355 
356 
357  looper.markStateProcessed(); // next processing round: further command(s) processed,
358  // yet still more commands pending...
359  CHECK ( looper.requireAction());
360  CHECK (not looper.isDisabled());
361  CHECK ( looper.isWorking());
362  CHECK (not looper.runBuild()); // ...build still postponed
363  CHECK (not looper.isIdle());
364 
365  sleep_for (800ms);
366  looper.markStateProcessed(); // let's assume we did command processing for a long time...
367 
368  CHECK ( looper.requireAction());
369  CHECK (not looper.isDisabled());
370  CHECK ( looper.isWorking());
371  CHECK ( looper.runBuild()); // ...after some time of command processing, a build run is forced
372  CHECK (not looper.isIdle());
373 
374  looper.markStateProcessed(); // and when the builder run is confirmed...
375 
376  CHECK ( looper.requireAction());
377  CHECK (not looper.isDisabled());
378  CHECK ( looper.isWorking());
379  CHECK (not looper.runBuild()); // ...we are back to normal working state (build postponed)
380  CHECK (not looper.isIdle());
381 
382 
383  setup.has_commands_in_queue = false; // now emptied our queue
384  looper.markStateProcessed(); // at least one further command has been handled
385 
386  CHECK (not looper.requireAction());
387  CHECK (not looper.isDisabled());
388  CHECK (not looper.isWorking());
389  CHECK ( looper.runBuild()); // ...note: now build will be triggered
390  CHECK (not looper.isIdle());
391 
392  CHECK (isFast (looper.getTimeout())); // ...but only after a short wait period,
393  // since not looper.requireAction()
394 
395 
396  looper.markStateProcessed(); // next processing round: invoked builder,
397  // and no more commands commands pending...
398  CHECK (not looper.requireAction());
399  CHECK (not looper.isDisabled());
400  CHECK (not looper.isWorking());
401  CHECK (not looper.runBuild()); // ...note: now done with building
402  CHECK ( looper.isIdle());
403 
404  CHECK (isDisabled(looper.getTimeout())); // ...now Dispatcher is idle and goes to sleep
405 
406 
407  setup.has_commands_in_queue = true; // next command pending
408 
409  CHECK ( looper.requireAction()); // return to work mode
410  CHECK (not looper.isDisabled());
411  CHECK ( looper.isWorking());
412  CHECK (not looper.runBuild());
413  CHECK (not looper.isIdle());
414 
415  setup.has_commands_in_queue = false; // now let's assume command has been processed
416  looper.markStateProcessed(); // and queue is empty again
417 
418  CHECK (not looper.requireAction());
419  CHECK (not looper.isDisabled());
420  CHECK (not looper.isWorking());
421  CHECK ( looper.runBuild());
422  CHECK (not looper.isIdle());
423 
424  CHECK (isFast (looper.getTimeout())); // now build *would* be triggered after short timeout, but..
425 
426 
427  looper.enableProcessing(false); // disable processing
428 
429  CHECK (not looper.requireAction());
430  CHECK ( looper.isDisabled());
431  CHECK (not looper.isWorking());
432  CHECK (not looper.runBuild()); // ...note: dirty state hidden by disabled state
433  CHECK (not looper.isIdle());
434 
435  CHECK (isDisabled (looper.getTimeout()));
436 
437 
438  looper.enableProcessing(true); // enable back
439 
440  CHECK (not looper.requireAction());
441  CHECK (not looper.isDisabled());
442  CHECK (not looper.isWorking());
443  CHECK ( looper.runBuild()); // ...note: dirty state revealed again
444  CHECK (not looper.isIdle());
445 
446  CHECK (isFast (looper.getTimeout()));
447 
448  looper.enableProcessing(false); // disable processing
449  looper.markStateProcessed(); // let's assume builder was running and is now finished
450 
451  CHECK (not looper.requireAction());
452  CHECK ( looper.isDisabled());
453  CHECK (not looper.isWorking());
454  CHECK (not looper.runBuild()); // ...note: dirty state not obvious
455  CHECK (not looper.isIdle());
456 
457  CHECK (isDisabled (looper.getTimeout()));
458 
459 
460  looper.enableProcessing(true); // enable back
461 
462  CHECK (not looper.requireAction());
463  CHECK (not looper.isDisabled());
464  CHECK (not looper.isWorking());
465  CHECK (not looper.runBuild()); // ...note: but now it becomes clear builder is not dirty
466  CHECK ( looper.isIdle());
467 
468  CHECK (isDisabled (looper.getTimeout()));
469 
470 
471  setup.has_commands_in_queue = true; // more commands again
472  looper.markStateProcessed(); // ...and let's assume one command has already been processed
473 
474  CHECK ( looper.requireAction());
475  CHECK (not looper.isDisabled());
476  CHECK ( looper.isWorking());
477  CHECK (not looper.runBuild());
478  CHECK (not looper.isIdle());
479 
480  looper.triggerShutdown(); // request shutdown...
481 
482  CHECK ( looper.requireAction());
483  CHECK ( looper.isDisabled());
484  CHECK (not looper.isWorking());
485  CHECK (not looper.runBuild());
486  CHECK (not looper.isIdle());
487 
488  CHECK (isDisabled (looper.getTimeout()));
489 
490 
491  setup.has_commands_in_queue = false; // and even when done with all commands...
492  looper.markStateProcessed();
493 
494  CHECK ( looper.requireAction());
495  CHECK ( looper.isDisabled());
496  CHECK (not looper.isWorking());
497  CHECK (not looper.runBuild()); // ...note: still no need for builder run, since in shutdown
498  CHECK (not looper.isIdle());
499 
500  CHECK (isDisabled (looper.getTimeout()));
501  }
502  };
503 
504 
506  LAUNCHER (DispatcherLooper_test, "unit controller");
507 
508 
509 }}} // namespace proc::control::test
bool isWorking() const
Definition: looper.hpp:139
bool shallLoop() const
state fusion to control looping
Definition: looper.hpp:202
Definition: Setup.py:1
Definition: run.hpp:49
ulong getTimeout() const
Definition: looper.hpp:208
bool requireAction()
state fusion to control (timed) wait
Definition: looper.hpp:186
Implementation building block of ProcDispatcher to control waiting and timing.
void markStateProcessed()
invoking this function signals that all consequences of past state changes have been processed and ar...
Definition: looper.hpp:170
bool runBuild() const
Definition: looper.hpp:141
std::vector< string > & Arg
Definition: run.hpp:54
LAUNCHER(ArgumentTupleAccept_test, "unit controller")
Register this test class...
Encapsulated control logic for the session thread loop.
Definition: looper.hpp:112
Simple test class runner.
bool isDying() const
Definition: looper.hpp:137
bool isDisabled() const
Definition: looper.hpp:138
bool isIdle() const
Definition: looper.hpp:142
void enableProcessing(bool yes=true)
Definition: looper.hpp:154
Proc-Layer implementation namespace root.
Definition: id-scheme.hpp:63