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

Unified Diff: test/plugin/ActiveQueueTest.cpp

Issue 29323611: Issue #1234, #2058 - Rewrite log facility, improving thread implementation
Patch Set: Created Aug. 19, 2015, 5:42 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
Index: test/plugin/ActiveQueueTest.cpp
===================================================================
new file mode 100644
--- /dev/null
+++ b/test/plugin/ActiveQueueTest.cpp
@@ -0,0 +1,183 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2015 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 <gtest/gtest.h>
+#include "../../src/plugin/ActiveQueue.h"
+#include <ostream>
+#include <memory>
+
+class TrivialIntMessageQueue
+ : public MessageQueue<int>
+{
+public:
+ TrivialIntMessageQueue()
+ : MessageQueue()
+ {}
+};
+
+TEST(MessageQueue, Instance)
+{
+ TrivialIntMessageQueue mq;
+}
+
+TEST(MessageQueue, Insert)
+{
+ TrivialIntMessageQueue mq;
+ mq.Insert(5);
+}
+
+TEST(MessageQueue, RvalueInsertRemove)
+{
+ TrivialIntMessageQueue mq;
+ mq.Insert(2+3); // int&&
+ int result;
+ auto haveResult = mq.Remove([&](int x) { result = x; });
+ ASSERT_TRUE(haveResult);
+ ASSERT_EQ(5, result);
+}
+
+TEST(MessageQueue, ConstInsertRemove)
+{
+ TrivialIntMessageQueue mq;
+ const int value = 4;
+ mq.Insert(value); // const int&
+ int result;
+ auto haveResult = mq.Remove([&](int x) { result = x; });
+ ASSERT_TRUE(haveResult);
+ ASSERT_EQ(4, result);
+}
+
+TEST(MessageQueue, Thread)
+{
+ bool threadTimeout = false;
+ std::string threadFailMessage;
+ MessageQueue<unsigned int> mq;
+ static const unsigned int numberOfElements = 1000;
+ unsigned int counter = 1;
+
+ std::thread th([&]() -> void {
+ // Begin body of notice thread
+ try
+ {
+ /*
+ * We use a nested loop with the same predicate because notice and wait are not related one-to-one.
+ * Multiple calls to notify_one() may happen before the wait_for() statement is active.
+ * Thus the outer loop manages the condition variable.
+ * The inner loop removes all available queue elements, since there may be more than one per notice.
+ */
+ while (counter < numberOfElements)
+ {
+ if (mq.WaitFor(std::chrono::seconds(10)) == std::cv_status::timeout)
+ {
+ threadFailMessage = "Thread timed out.";
+ return;
+ }
+ bool noticeIsFresh = true;
+ while (counter < numberOfElements)
+ {
+ unsigned int element;
+ auto f = [&](unsigned int x) -> void { element = x; };
+ if (mq.Remove(f))
+ {
+ if (element != counter)
+ {
+ std::ostringstream ss;
+ ss << "Counter mismatch. expected = " << counter << ". actual = " << element;
+ threadFailMessage = ss.str();
+ return;
+ }
+ noticeIsFresh = false;
+ ++counter; // counter represents the number of elements removed, so only increment when remove() returns true
+ }
+ else if (noticeIsFresh)
+ {
+ threadFailMessage = "Notice received, but no element to remove from queue.";
+ return;
+ }
+ }
+ }
+ }
+ catch (std::exception &e)
+ {
+ threadFailMessage = std::string("Exception: ") + e.what();
+ }
+ // End body of notice thread
+ });
+
+ // Body of test thread
+ for (unsigned int j = 1; j <= numberOfElements ; ++j)
+ {
+ mq.Insert(j);
+ };
+ th.join();
+ if (!threadFailMessage.empty())
+ {
+ FAIL() << threadFailMessage;
+ }
+ ASSERT_EQ(numberOfElements, counter);
+}
+
+/*
+ * All the ActiveQueue tests instantiante the ActiveQueue in a separate block.
+ * This ensures its internal thread has terminated before the end of the test,
+ * and that the test will hang if it has not.
+ */
+
+TEST(ActiveQueue, Instance)
+{
+ bool seen = false;
+ auto process = [&](unsigned int) { seen = true; };
+ {
+ ActiveQueue<unsigned int, decltype(process)> aq(process);
+ }
+ ASSERT_FALSE(seen);
+}
+
+TEST(ActiveQueue, Single)
+{
+ bool seen = false;
+ auto process = [&](unsigned int) { seen = true; };
+ {
+ ActiveQueue<unsigned int, decltype(process)> aq(process);
+ aq.Insert(0);
+ }
+ ASSERT_TRUE(seen);
+}
+
+TEST(ActiveQueue, Multiple)
+{
+ static const unsigned int numberOfElements = 1000;
+ unsigned int counter = 0;
+ std::string threadFailMessage;
+ auto process = [&](unsigned int x) -> void {
+ ++counter;
+ if (x != counter)
+ {
+ std::ostringstream os;
+ os << "Mismatch: expected counter=" << counter << ", received queue element=" << x << ".";
+ threadFailMessage = os.str();
+ }
+ };
+ {
+ ActiveQueue<unsigned int, decltype(process)> aq(process);
+ for (unsigned int j = 1; j <= numberOfElements; ++j)
+ {
+ aq.Insert(j);
+ ASSERT_EQ("", threadFailMessage);
+ };
+ }
+ ASSERT_EQ(numberOfElements, counter);
+}

Powered by Google App Engine
This is Rietveld