testEventLoop.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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 "compat/cppunit.h"
12#include "EventLoop.h"
13#include "time/Engine.h"
14#include "unitTestMain.h"
15
16#include <cppunit/TestAssert.h>
17
18/*
19 * test the EventLoop implementation
20 */
21
22class TestEventLoop : public CPPUNIT_NS::TestFixture
23{
32
33protected:
34 void testCreate();
35 void testRunOnce();
36 void testEngineTimeout();
37 void testEngineErrors();
38 void testSetTimeService();
40 /* TODO:
41 * test that engine which errors a couple of times, then returns 0, then
42 * errors 10 times in a row triggers a fail on the 10th time around
43 */
44};
45
47
48void
50{
51 EventLoop();
52}
53
55{
56public:
57 RecordingEngine(int aTimeout = 0) : return_timeout(aTimeout) {}
58
59 int checkEvents(int timeout) override {
60 ++calls;
61 lasttimeout = timeout;
62 return return_timeout;
63 }
64
65 int calls = 0;
66 int lasttimeout = 0;
68};
69
70/* test that a registered async engine is invoked on each loop run
71 * we do this with an instrumented async engine.
72 */
73void
75{
76 {
77 /* trivial case - no engine, should quit immediately */
78 EventLoop theLoop;
79 CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
80 }
81
82 {
83 /* An event loop with all idle engines, and nothing dispatched in a run should
84 * automatically quit. The runOnce call should return True when the loop is
85 * entirely idle to make it easy for people running the loop by hand.
86 */
87 EventLoop theLoop;
89 theLoop.registerEngine(&engine);
90 CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
91 CPPUNIT_ASSERT_EQUAL(1, engine.calls);
92 theLoop.run();
93 CPPUNIT_ASSERT_EQUAL(2, engine.calls);
94 }
95
96 {
97 /* an engine that asks for a timeout should not be detected as idle:
98 * use runOnce which should return false
99 */
100 EventLoop theLoop;
101 RecordingEngine engine;
102 theLoop.registerEngine(&engine);
103 CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
104 CPPUNIT_ASSERT_EQUAL(1, engine.calls);
105 CPPUNIT_ASSERT_EQUAL(EVENT_LOOP_TIMEOUT, engine.lasttimeout);
106 }
107}
108
109/* each AsyncEngine needs to be given a timeout. We want one engine in each
110 * loop to be given the timeout value - and the rest to have a timeout of 0.
111 * The last registered engine should be given this timeout, which will mean
112 * that we do not block in the loop until the last engine. This will allow for
113 * dynamic introduction and removal of engines, as long as the last engine
114 * is one which can do a os call rather than busy waiting.
115 *
116 * So - we want the timeout hints returned from the earlier engines to be
117 * tracked, and the lowest non-negative value given to the last engine.
118 */
119void
121{
122 EventLoop theLoop;
123 RecordingEngine engineOne(5);
124 RecordingEngine engineTwo;
125 theLoop.registerEngine(&engineOne);
126 theLoop.registerEngine(&engineTwo);
127 theLoop.runOnce();
128 CPPUNIT_ASSERT_EQUAL(1, engineOne.calls);
129 CPPUNIT_ASSERT_EQUAL(0, engineOne.lasttimeout);
130 CPPUNIT_ASSERT_EQUAL(1, engineTwo.calls);
131 CPPUNIT_ASSERT_EQUAL(5, engineTwo.lasttimeout);
132}
133
134/* An engine which is suffering errors. This should result in 10
135 * loops until the loop stops - because that's the error retry amount
136 * hard-coded into EventLoop::runOnce()
137 */
138void
140{
141 EventLoop theLoop;
143 theLoop.registerEngine(&failing_engine);
144 CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
145 CPPUNIT_ASSERT_EQUAL(1, failing_engine.calls);
146 CPPUNIT_ASSERT_EQUAL(1, theLoop.errcount);
147 theLoop.run();
148 /* run resets the error count ... */
149 CPPUNIT_ASSERT_EQUAL(10, theLoop.errcount);
150 CPPUNIT_ASSERT_EQUAL(11, failing_engine.calls);
151}
152
153/* An event loop has a time service which is like an async engine but never
154 * generates events and there can only be one such service.
155 */
156class StubTime : public Time::Engine
157{
158public:
159 StubTime() : calls(0) {}
160
161 int calls;
162 void tick() override {
163 ++calls;
164 }
165};
166
167void
169{
170 EventLoop theLoop;
171 StubTime myTime;
172 /* the loop will not error without a time service */
173 theLoop.runOnce();
174 /* we can set the time service */
175 theLoop.setTimeService(&myTime);
176 /* it invokes our tick() call */
177 theLoop.runOnce();
178 CPPUNIT_ASSERT_EQUAL(1, myTime.calls);
179 /* it invokes our tick() call again */
180 theLoop.runOnce();
181 CPPUNIT_ASSERT_EQUAL(2, myTime.calls);
182}
183
184/* one async engine is the primary engine - the engine that is allowed to block.
185 * this defaults to the last added one, but can be explicitly nominated
186 */
187void
189{
190 EventLoop theLoop;
191 RecordingEngine first_engine(10);
192 RecordingEngine second_engine(10);
193 /* one engine - gets a timeout */
194 theLoop.registerEngine(&first_engine);
195 theLoop.runOnce();
196 CPPUNIT_ASSERT_EQUAL(EVENT_LOOP_TIMEOUT, first_engine.lasttimeout);
197 /* two engines - the second gets the timeout */
198 theLoop.registerEngine(&second_engine);
199 theLoop.runOnce();
200 CPPUNIT_ASSERT_EQUAL(0, first_engine.lasttimeout);
201 CPPUNIT_ASSERT_EQUAL(10, second_engine.lasttimeout);
202 /* set the first engine to be primary explicitly and now gets the timeout */
203 theLoop.setPrimaryEngine(&first_engine);
204 theLoop.runOnce();
205 CPPUNIT_ASSERT_EQUAL(10, first_engine.lasttimeout);
206 CPPUNIT_ASSERT_EQUAL(0, second_engine.lasttimeout);
207}
208
209int
210main(int argc, char *argv[])
211{
212 return TestProgram().run(argc, argv);
213}
214
#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
int checkEvents(int timeout) override
RecordingEngine(int aTimeout=0)
void tick() override
CPPUNIT_TEST(testSetPrimaryEngine)
void testSetTimeService()
void testEngineErrors()
void testSetPrimaryEngine()
CPPUNIT_TEST(testSetTimeService)
CPPUNIT_TEST(testEngineTimeout)
CPPUNIT_TEST(testEngineErrors)
CPPUNIT_TEST_SUITE(TestEventLoop)
void testEngineTimeout()
CPPUNIT_TEST(testCreate)
CPPUNIT_TEST(testRunOnce)
void testRunOnce()
implements test program's main() function while enabling customization
Definition: unitTestMain.h:26
int run(int argc, char *argv[])
Definition: unitTestMain.h:44
event class for doing synthetic time etc
Definition: Engine.h:16
int main(int argc, char *argv[])
CPPUNIT_TEST_SUITE_REGISTRATION(TestEventLoop)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors