-#define SQUID_UNIT_TEST 1
+/*
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
#include "squid.h"
+#include "AsyncEngine.h"
+#include "EventLoop.h"
+#include "SquidTime.h"
+#include "tests/testEventLoop.h"
+#include "unitTestMain.h"
#include <cppunit/TestAssert.h>
-#include "testEventLoop.h"
-#include "EventLoop.h"
-#include "Mem.h"
-#include "protos.h"
-#include "stat.h"
-
CPPUNIT_TEST_SUITE_REGISTRATION( testEventLoop );
-/* init legacy static-initialized modules */
-
-void
-testEventLoop::setUp()
-{
- Mem::Init();
- statInit();
-}
-
-/*
- * Test creating a EventLoop
- */
void
testEventLoop::testCreate()
{
EventLoop();
}
-#if POLISHED_MAIN_LOOP
-
-/*
- * Running the loop once is useful for integration with other loops, such as
- * migrating to it in incrementally.
- *
- * This test works by having a custom dispatcher and engine which record how
- * many times they are called.
- */
-
-class RecordDispatcher : public CompletionDispatcher
-{
-
-public:
- int calls;
- RecordDispatcher(): calls(0) {}
-
- bool dispatch() {
- ++calls;
- /* claim we dispatched calls to be useful for the testStopOnIdle test.
- */
- return true;
- }
-};
-
-#endif /* POLISHED_MAIN_LOOP */
-
class RecordingEngine : public AsyncEngine
{
-
public:
- int calls;
- int lasttimeout;
- int return_timeout;
- RecordingEngine(int return_timeout=0): calls(0), lasttimeout(0),
- return_timeout(return_timeout) {}
+ RecordingEngine(int aTimeout = 0) : return_timeout(aTimeout) {}
virtual int checkEvents(int timeout) {
++calls;
lasttimeout = timeout;
return return_timeout;
}
-};
-#if POLISHED_MAIN_LOOP
+ int calls = 0;
+ int lasttimeout = 0;
+ int return_timeout = 0;
+};
+/* test that a registered async engine is invoked on each loop run
+ * we do this with an instrumented async engine.
+ */
void
testEventLoop::testRunOnce()
{
- EventLoop theLoop;
- RecordDispatcher dispatcher;
- theLoop.registerDispatcher(&dispatcher);
- RecordingEngine engine;
- theLoop.registerEngine(&engine);
- theLoop.runOnce();
- CPPUNIT_ASSERT_EQUAL(1, dispatcher.calls);
- CPPUNIT_ASSERT_EQUAL(1, engine.calls);
-}
-
-/*
- * completion dispatchers registered with the event loop are invoked by the
- * event loop.
- *
- * This test works by having a customer dispatcher which shuts the loop down
- * once its been invoked twice.
- *
- * It also tests that loop.run() and loop.stop() work, because if they dont
- * work, this test will either hang, or fail.
- */
-
-class ShutdownDispatcher : public CompletionDispatcher
-{
-
-public:
- EventLoop &theLoop;
- int calls;
- ShutdownDispatcher(EventLoop & theLoop):theLoop(theLoop), calls(0) {}
-
- bool dispatch() {
- if (++calls == 2)
- theLoop.stop();
-
- return true;
+ {
+ /* trivial case - no engine, should quit immediately */
+ EventLoop theLoop;
+ CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
}
-};
-void
-testEventLoop::testRegisterDispatcher()
-{
- EventLoop theLoop;
- ShutdownDispatcher testDispatcher(theLoop);
- theLoop.registerDispatcher(&testDispatcher);
- theLoop.run();
- /* we should get two calls because the test dispatched returns true from
- * dispatch(), and calls stop on the second call.
- */
- CPPUNIT_ASSERT_EQUAL(2, testDispatcher.calls);
-}
+ {
+ /* An event loop with all idle engines, and nothing dispatched in a run should
+ * automatically quit. The runOnce call should return True when the loop is
+ * entirely idle to make it easy for people running the loop by hand.
+ */
+ EventLoop theLoop;
+ RecordingEngine engine(AsyncEngine::EVENT_IDLE);
+ theLoop.registerEngine(&engine);
+ CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
+ CPPUNIT_ASSERT_EQUAL(1, engine.calls);
+ theLoop.run();
+ CPPUNIT_ASSERT_EQUAL(2, engine.calls);
+ }
-/* test that a registered async engine is invoked on each loop run
- * we do this with an intstrumented async engine.
- */
-void
-testEventLoop::testRegisterEngine()
-{
- EventLoop theLoop;
- ShutdownDispatcher testDispatcher(theLoop);
- theLoop.registerDispatcher(&testDispatcher);
- RecordingEngine testEngine;
- theLoop.registerEngine(&testEngine);
- theLoop.run();
- CPPUNIT_ASSERT_EQUAL(2, testEngine.calls);
+ {
+ /* an engine that asks for a timeout should not be detected as idle:
+ * use runOnce which should return false
+ */
+ EventLoop theLoop;
+ RecordingEngine engine;
+ theLoop.registerEngine(&engine);
+ CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
+ CPPUNIT_ASSERT_EQUAL(1, engine.calls);
+ CPPUNIT_ASSERT_EQUAL(EVENT_LOOP_TIMEOUT, engine.lasttimeout);
+ }
}
/* each AsyncEngine needs to be given a timeout. We want one engine in each
* loop to be given the timeout value - and the rest to have a timeout of 0.
* The last registered engine should be given this timeout, which will mean
- * that we dont block in the loop until the last engine. This will allow for
+ * that we do not block in the loop until the last engine. This will allow for
* dynamic introduction and removal of engines, as long as the last engine
* is one which can do a os call rather than busy waiting.
*
theLoop.registerEngine(&engineOne);
theLoop.registerEngine(&engineTwo);
theLoop.runOnce();
+ CPPUNIT_ASSERT_EQUAL(1, engineOne.calls);
CPPUNIT_ASSERT_EQUAL(0, engineOne.lasttimeout);
+ CPPUNIT_ASSERT_EQUAL(1, engineTwo.calls);
CPPUNIT_ASSERT_EQUAL(5, engineTwo.lasttimeout);
}
-/* An event loop with all idle engines, and nothing dispatched in a run should
- * automatically quit. The runOnce call should return True when the loop is
- * entirely idle to make it easy for people running the loop by hand.
+/* An engine which is suffering errors. This should result in 10
+ * loops until the loop stops - because that's the error retry amount
+ * hard-coded into EventLoop::runOnce()
*/
void
-testEventLoop::testStopOnIdle()
+testEventLoop::testEngineErrors()
{
EventLoop theLoop;
- /* trivial case - no dispatchers or engines, should quit immediately */
- CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
- theLoop.run();
- /* add a dispatcher with nothing to dispatch - use an EventDispatcher as its
- * sufficient and handy
- */
- EventDispatcher dispatcher;
- theLoop.registerDispatcher(&dispatcher);
- CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
- theLoop.run();
- /* add an engine which is idle.
- */
- RecordingEngine engine(AsyncEngine::EVENT_IDLE);
- theLoop.registerEngine(&engine);
- CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
- CPPUNIT_ASSERT_EQUAL(1, engine.calls);
- theLoop.run();
- CPPUNIT_ASSERT_EQUAL(2, engine.calls);
- /* add an engine which is suffering errors. This should result in 10
- * loops until the loop stops - because thats the error retry amount
- */
RecordingEngine failing_engine(AsyncEngine::EVENT_ERROR);
theLoop.registerEngine(&failing_engine);
CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
CPPUNIT_ASSERT_EQUAL(1, failing_engine.calls);
+ CPPUNIT_ASSERT_EQUAL(1, theLoop.errcount);
theLoop.run();
/* run resets the error count ... */
+ CPPUNIT_ASSERT_EQUAL(10, theLoop.errcount);
CPPUNIT_ASSERT_EQUAL(11, failing_engine.calls);
-
- /* an engine that asks for a timeout should not be detected as idle:
- * use runOnce which should return false
- */
- theLoop = EventLoop();
- RecordingEngine non_idle_engine(1000);
- theLoop.registerEngine(&non_idle_engine);
- CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
}
-#endif /* POLISHED_MAIN_LOOP */
-
/* An event loop has a time service which is like an async engine but never
* generates events and there can only be one such service.
*/
CPPUNIT_ASSERT_EQUAL(10, first_engine.lasttimeout);
CPPUNIT_ASSERT_EQUAL(0, second_engine.lasttimeout);
}
+