Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: test/TimeoutTest.cpp

Issue 29370876: Issue #4692, #3595 - Stop sleeping in the implementation of `SetTimeout`
Patch Set: Created Jan. 9, 2017, 1:22 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/SchedulerTest.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/TimeoutTest.cpp
===================================================================
new file mode 100644
--- /dev/null
+++ b/test/TimeoutTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2017 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../src/Timeout.h"
+#include "BaseJsTest.h"
+#include "PausePoint.h"
+#include <thread>
+
+TEST(Timeout, Instance)
+{
+ DelayedExecutor x([]() {});
+}
+
+TEST(Timeout, ConstructorBodyMayNotBeNull)
+{
+ auto nullBody = std::function<void()>();
+ ASSERT_ANY_THROW({ DelayedExecutor x(nullBody); });
+}
+
+TEST(Timeout, ImmediateRunSimple)
+{
+ int count = 0;
+ DelayedExecutor x([&]() { ++count; });
+ x.RunImmediately();
+ EXPECT_EQ(1, count);
+}
+
+TEST(Timeout, DelayedRunSimple)
+{
+ int count = 0;
+ DelayedExecutor x([&]() { ++count; });
+ x.RunWithDelay(std::chrono::milliseconds(1));
+ EXPECT_EQ(1, count);
+}
+
+/**
+ * Test class exposes each aspect point in the constructor.
+ */
+class DelayedExecutorTestAspect
+ : public AspectBase<DelayedExecutorTestAspect>
+{
+ std::function<void()> runnableToSleeping;
+ std::function<void()> runFinish;
+
+public:
+ template<class LockType>
+ void RunnableToSleeping(LockType& lock)
+ {
+ AntiLock<LockType> x(lock);
+ runnableToSleeping();
+ };
+
+ void RunFinish()
+ {
+ runFinish();
+ }
+
+ DelayedExecutorTestAspect(std::function<void()> runnableToSleeping,
+ std::function<void()> runFinish)
+ : runnableToSleeping(runnableToSleeping),
+ runFinish(runFinish)
+ {}
+};
+
+class DelayedExecutorForTesting
+ : public DelayedExecutorAspected<DelayedExecutorTestAspect>
+{
+public:
+ typedef DelayedExecutorAspected<DelayedExecutorTestAspect> Base;
+ DelayedExecutorForTesting(std::function<void()> body,
+ std::function<void()> runnableToSleeping,
+ std::function<void()> runFinish)
+ : Base(DelayedExecutorTestAspect(runnableToSleeping, runFinish), body)
+ {}
+};
+
+/**
+ * Exercises an ordinary sequence for RunWithDelay().
+ * This version tracks the sequence through test aspect points.
+ */
+TEST(Timeout, DelayedRunAspected)
+{
+ int sequence = 0;
+ auto body = [&]()
+ {
+ ASSERT_EQ(1, sequence);
+ sequence = 2;
+ };
+ auto runnableToSleeping = [&]()
+ {
+ ASSERT_EQ(0, sequence);
+ sequence = 1;
+ };
+ auto runFinish = [&]()
+ {
+ ASSERT_EQ(2, sequence);
+ sequence = 3;
+ };
+
+ DelayedExecutorForTesting x(body, runnableToSleeping, runFinish);
+ ASSERT_EQ(0, sequence);
+ x.RunWithDelay(std::chrono::milliseconds(1));
+ ASSERT_EQ(3, sequence);
+}
+
+/**
+ * Exercises an ordinary sequence for RunWithDelay().
+ * This version is in a separate thread.
+ */
+TEST(Timeout, DelayedRunAspectedThreaded)
+{
+ PausePoint pp;
+ int sequence = 0;
+ auto body = [&]()
+ {
+ sequence = 3;
+ pp.Pause();
+ };
+ auto runnableToSleeping = [&]()
+ {
+ sequence = 2;
+ pp.Pause();
+ };
+ auto runFinish = [&]()
+ {
+ sequence = 4;
+ pp.Pause();
+ };
+
+ std::thread th([&]()
+ {
+ DelayedExecutorForTesting x(body, runnableToSleeping, runFinish);
+ sequence = 1;
+ pp.Pause();
+ x.RunWithDelay(std::chrono::milliseconds(1));
+ sequence = 5;
+ pp.Pause();
+ sequence = 6;
+ });
+ for (int j = 1; j <= 5; ++j) {
+ pp.WaitUntilPaused();
+ ASSERT_EQ(j, sequence);
+ pp.Resume();
+ }
+ th.join();
+ ASSERT_EQ(6, sequence);
+}
+
+TEST(Timeout, DelayedRunInterrupted)
+{
+ PausePoint pp;
+ int sequence = 0;
+ auto body = [&]()
+ {
+ sequence = 3;
+ pp.Pause();
+ };
+ auto runnableToSleeping = [&]()
+ {
+ sequence = 2;
+ pp.Pause();
+ };
+ auto runFinish = [&]()
+ {
+ sequence = 4;
+ pp.Pause();
+ };
+
+ DelayedExecutorForTesting x(body, runnableToSleeping, runFinish);
+ ASSERT_EQ(0, sequence);
+ std::thread th([&]()
+ {
+ sequence = 1;
+ pp.Pause();
+ x.RunWithDelay(std::chrono::minutes(2)); // long delay to interrupt
+ sequence = 5;
+ pp.Pause();
+ sequence = 6;
+ });
+ pp.WaitUntilPaused();
+ ASSERT_EQ(1, sequence);
+ pp.Resume();
+ pp.WaitUntilPaused();
+ ASSERT_EQ(2, sequence);
+ /*
+ * We are at an aspect point where we're about to wait.
+ * We don't have the capability of interrupting the wait itself,
+ * so we rely on a heuristic.
+ * We resume and sleep for a bit to give the scheduler a chance to wake up
+ * the thread and for the condition variable to begin waiting.
+ * It's possible to get occasional failures with this algorithm.
+ */
+ pp.ResumeAndSleep(2);
+ // Assume the condition variable is waiting.
+ x.ForestallExecution();
+ // We skip sequence 3, where the body executes.
+ // We skip sequence 4, where DelayedExecutor changes state after execution
+ pp.WaitUntilPaused();
+ ASSERT_EQ(5, sequence);
+ pp.Resume();
+ th.join();
+ ASSERT_EQ(6, sequence);
+}
+
+
+
« no previous file with comments | « test/SchedulerTest.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld