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);
+}
