testEventLoop.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
10#include "AsyncEngine.h"
11#include "EventLoop.h"
12#include "tests/testEventLoop.h"
13#include "time/Engine.h"
14#include "unitTestMain.h"
15
16#include <cppunit/TestAssert.h>
17
19
20void
22{
23 EventLoop();
24}
25
27{
28public:
29 RecordingEngine(int aTimeout = 0) : return_timeout(aTimeout) {}
30
31 virtual int checkEvents(int timeout) {
32 ++calls;
33 lasttimeout = timeout;
34 return return_timeout;
35 }
36
37 int calls = 0;
38 int lasttimeout = 0;
40};
41
42/* test that a registered async engine is invoked on each loop run
43 * we do this with an instrumented async engine.
44 */
45void
47{
48 {
49 /* trivial case - no engine, should quit immediately */
50 EventLoop theLoop;
51 CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
52 }
53
54 {
55 /* An event loop with all idle engines, and nothing dispatched in a run should
56 * automatically quit. The runOnce call should return True when the loop is
57 * entirely idle to make it easy for people running the loop by hand.
58 */
59 EventLoop theLoop;
61 theLoop.registerEngine(&engine);
62 CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
63 CPPUNIT_ASSERT_EQUAL(1, engine.calls);
64 theLoop.run();
65 CPPUNIT_ASSERT_EQUAL(2, engine.calls);
66 }
67
68 {
69 /* an engine that asks for a timeout should not be detected as idle:
70 * use runOnce which should return false
71 */
72 EventLoop theLoop;
73 RecordingEngine engine;
74 theLoop.registerEngine(&engine);
75 CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
76 CPPUNIT_ASSERT_EQUAL(1, engine.calls);
77 CPPUNIT_ASSERT_EQUAL(EVENT_LOOP_TIMEOUT, engine.lasttimeout);
78 }
79}
80
81/* each AsyncEngine needs to be given a timeout. We want one engine in each
82 * loop to be given the timeout value - and the rest to have a timeout of 0.
83 * The last registered engine should be given this timeout, which will mean
84 * that we do not block in the loop until the last engine. This will allow for
85 * dynamic introduction and removal of engines, as long as the last engine
86 * is one which can do a os call rather than busy waiting.
87 *
88 * So - we want the timeout hints returned from the earlier engines to be
89 * tracked, and the lowest non-negative value given to the last engine.
90 */
91void
93{
94 EventLoop theLoop;
95 RecordingEngine engineOne(5);
96 RecordingEngine engineTwo;
97 theLoop.registerEngine(&engineOne);
98 theLoop.registerEngine(&engineTwo);
99 theLoop.runOnce();
100 CPPUNIT_ASSERT_EQUAL(1, engineOne.calls);
101 CPPUNIT_ASSERT_EQUAL(0, engineOne.lasttimeout);
102 CPPUNIT_ASSERT_EQUAL(1, engineTwo.calls);
103 CPPUNIT_ASSERT_EQUAL(5, engineTwo.lasttimeout);
104}
105
106/* An engine which is suffering errors. This should result in 10
107 * loops until the loop stops - because that's the error retry amount
108 * hard-coded into EventLoop::runOnce()
109 */
110void
112{
113 EventLoop theLoop;
115 theLoop.registerEngine(&failing_engine);
116 CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
117 CPPUNIT_ASSERT_EQUAL(1, failing_engine.calls);
118 CPPUNIT_ASSERT_EQUAL(1, theLoop.errcount);
119 theLoop.run();
120 /* run resets the error count ... */
121 CPPUNIT_ASSERT_EQUAL(10, theLoop.errcount);
122 CPPUNIT_ASSERT_EQUAL(11, failing_engine.calls);
123}
124
125/* An event loop has a time service which is like an async engine but never
126 * generates events and there can only be one such service.
127 */
128class StubTime : public Time::Engine
129{
130public:
131 StubTime() : calls(0) {}
132
133 int calls;
134 void tick() {
135 ++calls;
136 }
137};
138
139void
141{
142 EventLoop theLoop;
143 StubTime myTime;
144 /* the loop will not error without a time service */
145 theLoop.runOnce();
146 /* we can set the time service */
147 theLoop.setTimeService(&myTime);
148 /* it invokes our tick() call */
149 theLoop.runOnce();
150 CPPUNIT_ASSERT_EQUAL(1, myTime.calls);
151 /* it invokes our tick() call again */
152 theLoop.runOnce();
153 CPPUNIT_ASSERT_EQUAL(2, myTime.calls);
154}
155
156/* one async engine is the primary engine - the engine that is allowed to block.
157 * this defaults to the last added one, but can be explicitly nominated
158 */
159void
161{
162 EventLoop theLoop;
163 RecordingEngine first_engine(10);
164 RecordingEngine second_engine(10);
165 /* one engine - gets a timeout */
166 theLoop.registerEngine(&first_engine);
167 theLoop.runOnce();
168 CPPUNIT_ASSERT_EQUAL(EVENT_LOOP_TIMEOUT, first_engine.lasttimeout);
169 /* two engines - the second gets the timeout */
170 theLoop.registerEngine(&second_engine);
171 theLoop.runOnce();
172 CPPUNIT_ASSERT_EQUAL(0, first_engine.lasttimeout);
173 CPPUNIT_ASSERT_EQUAL(10, second_engine.lasttimeout);
174 /* set the first engine to be primary explicitly and now gets the timeout */
175 theLoop.setPrimaryEngine(&first_engine);
176 theLoop.runOnce();
177 CPPUNIT_ASSERT_EQUAL(10, first_engine.lasttimeout);
178 CPPUNIT_ASSERT_EQUAL(0, second_engine.lasttimeout);
179}
180
#define EVENT_LOOP_TIMEOUT
Definition: EventLoop.h:16
int errcount
Definition: EventLoop.h:69
void run()
Definition: EventLoop.cc:76
void setTimeService(Time::Engine *)
Definition: EventLoop.cc:162
void registerEngine(AsyncEngine *engine)
Definition: EventLoop.cc:70
void setPrimaryEngine(AsyncEngine *engine)
Definition: EventLoop.cc:149
bool runOnce()
Definition: EventLoop.cc:89
virtual int checkEvents(int timeout)
RecordingEngine(int aTimeout=0)
void tick()
event class for doing synthetic time etc
Definition: Engine.h:16
void testSetPrimaryEngine()
void testEngineTimeout()
void testRunOnce()
void testEngineErrors()
void testSetTimeService()
CPPUNIT_TEST_SUITE_REGISTRATION(testEventLoop)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors