]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tests/testEventLoop.cc
SourceLayout: src/base, take 1 -- moved remaining Async* files to src/base/
[thirdparty/squid.git] / src / tests / testEventLoop.cc
CommitLineData
f5bffbd5 1#include "config.h"
e1f7507e 2
a553a5a3 3#include <cppunit/TestAssert.h>
4
a553a5a3 5#include "testEventLoop.h"
6#include "EventLoop.h"
e1f7507e 7#include "Mem.h"
a553a5a3 8
e1f7507e
AJ
9#if 0
10#include "AsyncEngine.h"
882255af 11#include "base/AsyncCallQueue.h"
e1f7507e
AJ
12#include "event.h"
13#endif
a553a5a3 14
15CPPUNIT_TEST_SUITE_REGISTRATION( testEventLoop );
16
17/* stub functions to link successfully */
18void
19shut_down(int)
20{}
21
757a2291
GS
22void
23reconfigure(int)
24{}
25
a553a5a3 26/* end stubs */
27
28/* init legacy static-initialized modules */
29
16555581 30void
31testEventLoop::setUp()
a553a5a3 32{
16555581 33 Mem::Init();
34 statInit();
35}
a553a5a3 36
37/*
38 * Test creating a EventLoop
39 */
40void
41testEventLoop::testCreate()
42{
43 EventLoop();
44}
45
cb9b9424 46#if POLISHED_MAIN_LOOP
a553a5a3 47
48/*
26ac0430 49 * Running the loop once is useful for integration with other loops, such as
a553a5a3 50 * migrating to it in incrementally.
51 *
8ff3fa2e 52 * This test works by having a custom dispatcher and engine which record how
53 * many times they are called.
a553a5a3 54 */
55
56class RecordDispatcher : public CompletionDispatcher
57{
58
59public:
60 int calls;
26ac0430 61 RecordDispatcher(): calls(0) {}
a553a5a3 62
26ac0430 63 bool dispatch() {
8ff3fa2e 64 ++calls;
65 /* claim we dispatched calls to be useful for the testStopOnIdle test.
66 */
67 return true;
68 }
a553a5a3 69};
70
cb9b9424 71#endif /* POLISHED_MAIN_LOOP */
72
8ff3fa2e 73class RecordingEngine : public AsyncEngine
74{
75
76public:
77 int calls;
78 int lasttimeout;
79 int return_timeout;
80 RecordingEngine(int return_timeout=0): calls(0), lasttimeout(0),
26ac0430 81 return_timeout(return_timeout) {}
8ff3fa2e 82
26ac0430
AJ
83 virtual int checkEvents(int timeout) {
84 ++calls;
85 lasttimeout = timeout;
86 return return_timeout;
87 }
88};
8ff3fa2e 89
cb9b9424 90#if POLISHED_MAIN_LOOP
91
a553a5a3 92void
93testEventLoop::testRunOnce()
94{
95 EventLoop theLoop;
96 RecordDispatcher dispatcher;
97 theLoop.registerDispatcher(&dispatcher);
8ff3fa2e 98 RecordingEngine engine;
99 theLoop.registerEngine(&engine);
a553a5a3 100 theLoop.runOnce();
101 CPPUNIT_ASSERT_EQUAL(1, dispatcher.calls);
8ff3fa2e 102 CPPUNIT_ASSERT_EQUAL(1, engine.calls);
a553a5a3 103}
104
105/*
8ff3fa2e 106 * completion dispatchers registered with the event loop are invoked by the
107 * event loop.
a553a5a3 108 *
8ff3fa2e 109 * This test works by having a customer dispatcher which shuts the loop down
110 * once its been invoked twice.
a553a5a3 111 *
8ff3fa2e 112 * It also tests that loop.run() and loop.stop() work, because if they dont
113 * work, this test will either hang, or fail.
a553a5a3 114 */
115
116class ShutdownDispatcher : public CompletionDispatcher
117{
118
119public:
120 EventLoop &theLoop;
121 int calls;
26ac0430 122 ShutdownDispatcher(EventLoop & theLoop):theLoop(theLoop), calls(0) {}
a553a5a3 123
26ac0430 124 bool dispatch() {
8ff3fa2e 125 if (++calls == 2)
126 theLoop.stop();
127
128 return true;
129 }
a553a5a3 130};
131
132void
133testEventLoop::testRegisterDispatcher()
134{
135 EventLoop theLoop;
136 ShutdownDispatcher testDispatcher(theLoop);
137 theLoop.registerDispatcher(&testDispatcher);
138 theLoop.run();
8ff3fa2e 139 /* we should get two calls because the test dispatched returns true from
140 * dispatch(), and calls stop on the second call.
141 */
a553a5a3 142 CPPUNIT_ASSERT_EQUAL(2, testDispatcher.calls);
143}
8ff3fa2e 144
145/* test that a registered async engine is invoked on each loop run
146 * we do this with an intstrumented async engine.
147 */
148void
149testEventLoop::testRegisterEngine()
150{
151 EventLoop theLoop;
152 ShutdownDispatcher testDispatcher(theLoop);
153 theLoop.registerDispatcher(&testDispatcher);
154 RecordingEngine testEngine;
155 theLoop.registerEngine(&testEngine);
156 theLoop.run();
157 CPPUNIT_ASSERT_EQUAL(2, testEngine.calls);
158}
159
160/* each AsyncEngine needs to be given a timeout. We want one engine in each
161 * loop to be given the timeout value - and the rest to have a timeout of 0.
162 * The last registered engine should be given this timeout, which will mean
163 * that we dont block in the loop until the last engine. This will allow for
164 * dynamic introduction and removal of engines, as long as the last engine
165 * is one which can do a os call rather than busy waiting.
166 *
167 * So - we want the timeout hints returned from the earlier engines to be
168 * tracked, and the lowest non-negative value given to the last engine.
169 */
170void
171testEventLoop::testEngineTimeout()
172{
173 EventLoop theLoop;
174 RecordingEngine engineOne(5);
175 RecordingEngine engineTwo;
176 theLoop.registerEngine(&engineOne);
177 theLoop.registerEngine(&engineTwo);
178 theLoop.runOnce();
179 CPPUNIT_ASSERT_EQUAL(0, engineOne.lasttimeout);
180 CPPUNIT_ASSERT_EQUAL(5, engineTwo.lasttimeout);
181}
182
183/* An event loop with all idle engines, and nothing dispatched in a run should
184 * automatically quit. The runOnce call should return True when the loop is
185 * entirely idle to make it easy for people running the loop by hand.
186 */
187void
188testEventLoop::testStopOnIdle()
189{
190 EventLoop theLoop;
191 /* trivial case - no dispatchers or engines, should quit immediately */
192 CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
193 theLoop.run();
194 /* add a dispatcher with nothing to dispatch - use an EventDispatcher as its
195 * sufficient and handy
196 */
197 EventDispatcher dispatcher;
198 theLoop.registerDispatcher(&dispatcher);
199 CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
200 theLoop.run();
201 /* add an engine which is idle.
202 */
203 RecordingEngine engine(AsyncEngine::EVENT_IDLE);
204 theLoop.registerEngine(&engine);
205 CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
206 CPPUNIT_ASSERT_EQUAL(1, engine.calls);
207 theLoop.run();
208 CPPUNIT_ASSERT_EQUAL(2, engine.calls);
209 /* add an engine which is suffering errors. This should result in 10
210 * loops until the loop stops - because thats the error retry amount
211 */
212 RecordingEngine failing_engine(AsyncEngine::EVENT_ERROR);
213 theLoop.registerEngine(&failing_engine);
214 CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
215 CPPUNIT_ASSERT_EQUAL(1, failing_engine.calls);
216 theLoop.run();
217 /* run resets the error count ... */
218 CPPUNIT_ASSERT_EQUAL(11, failing_engine.calls);
bef81ea5 219
220 /* an engine that asks for a timeout should not be detected as idle:
221 * use runOnce which should return false
222 */
223 theLoop = EventLoop();
224 RecordingEngine non_idle_engine(1000);
225 theLoop.registerEngine(&non_idle_engine);
226 CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
8ff3fa2e 227}
228
cb9b9424 229#endif /* POLISHED_MAIN_LOOP */
230
8ff3fa2e 231/* An event loop has a time service which is like an async engine but never
232 * generates events and there can only be one such service.
233 */
234
235class StubTime : public TimeEngine
236{
237
238public:
43d8f31d 239 StubTime() : calls(0) {}
8ff3fa2e 240
241 int calls;
26ac0430 242 void tick() {
8ff3fa2e 243 ++calls;
244 }
245};
246
247void
248testEventLoop::testSetTimeService()
249{
250 EventLoop theLoop;
251 StubTime myTime;
252 /* the loop will not error without a time service */
253 theLoop.runOnce();
254 /* we can set the time service */
255 theLoop.setTimeService(&myTime);
256 /* it invokes our tick() call */
257 theLoop.runOnce();
258 CPPUNIT_ASSERT_EQUAL(1, myTime.calls);
259 /* it invokes our tick() call again */
260 theLoop.runOnce();
261 CPPUNIT_ASSERT_EQUAL(2, myTime.calls);
262}
bef81ea5 263
264/* one async engine is the primary engine - the engine that is allowed to block.
265 * this defaults to the last added one, but can be explicitly nominated
266 */
267void
268testEventLoop::testSetPrimaryEngine()
269{
270 EventLoop theLoop;
271 RecordingEngine first_engine(10);
272 RecordingEngine second_engine(10);
273 /* one engine - gets a timeout */
274 theLoop.registerEngine(&first_engine);
275 theLoop.runOnce();
6289f91f 276 CPPUNIT_ASSERT_EQUAL(EVENT_LOOP_TIMEOUT, first_engine.lasttimeout);
bef81ea5 277 /* two engines - the second gets the timeout */
278 theLoop.registerEngine(&second_engine);
279 theLoop.runOnce();
280 CPPUNIT_ASSERT_EQUAL(0, first_engine.lasttimeout);
281 CPPUNIT_ASSERT_EQUAL(10, second_engine.lasttimeout);
282 /* set the first engine to be primary explicitly and now gets the timeout */
283 theLoop.setPrimaryEngine(&first_engine);
284 theLoop.runOnce();
285 CPPUNIT_ASSERT_EQUAL(10, first_engine.lasttimeout);
286 CPPUNIT_ASSERT_EQUAL(0, second_engine.lasttimeout);
bef81ea5 287}