Publish task queue test suite.

The set of tests is a copy of rtc_base/task_queue_unittests excluding tests
that verify rtc::NewClosure rather than task queue implementation itself.

Bug: webrtc:10191
Change-Id: I94e962ad63ff6510c43a97ef0cd4da7d08f25538
Reviewed-on: https://webrtc-review.googlesource.com/c/118445
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26369}
diff --git a/api/task_queue/BUILD.gn b/api/task_queue/BUILD.gn
index 11550e8..69f2133 100644
--- a/api/task_queue/BUILD.gn
+++ b/api/task_queue/BUILD.gn
@@ -39,6 +39,25 @@
   ]
 }
 
+rtc_source_set("task_queue_test") {
+  visibility = [ "*" ]
+  testonly = true
+  sources = [
+    "task_queue_test.cc",
+    "task_queue_test.h",
+  ]
+  deps = [
+    ":task_queue",
+    ":task_queue_factory",
+    "../../rtc_base:rtc_event",
+    "../../rtc_base:rtc_task_queue_api",
+    "../../rtc_base:timeutils",
+    "../../test:test_support",
+    "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/strings",
+  ]
+}
+
 rtc_source_set("default_task_queue_factory") {
   # TODO(bugs.webrtc.org/10191): Make public when implemented for all
   # supported platforms.
diff --git a/api/task_queue/DEPS b/api/task_queue/DEPS
index e480aa9..26f86a2 100644
--- a/api/task_queue/DEPS
+++ b/api/task_queue/DEPS
@@ -4,4 +4,7 @@
   "task_queue_impl\.h": [
     "+rtc_base/task_queue.h",
   ],
+  "task_queue_test\.h": [
+    "+test/gtest.h",
+  ],
 }
diff --git a/api/task_queue/task_queue_test.cc b/api/task_queue/task_queue_test.cc
new file mode 100644
index 0000000..cf9c814
--- /dev/null
+++ b/api/task_queue/task_queue_test.cc
@@ -0,0 +1,212 @@
+/*
+ *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/task_queue/task_queue_test.h"
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "rtc_base/event.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/timeutils.h"
+
+namespace webrtc {
+namespace {
+
+std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+    TaskQueueFactory* factory,
+    absl::string_view task_queue_name,
+    TaskQueueFactory::Priority priority = TaskQueueFactory::Priority::NORMAL) {
+  return factory->CreateTaskQueue(task_queue_name, priority);
+}
+
+TEST_P(TaskQueueTest, Construct) {
+  auto queue = CreateTaskQueue(GetParam(), "Construct");
+  EXPECT_FALSE(queue->IsCurrent());
+}
+
+TEST_P(TaskQueueTest, PostAndCheckCurrent) {
+  rtc::Event event;
+  auto queue = CreateTaskQueue(GetParam(), "PostAndCheckCurrent");
+
+  // We're not running a task, so there shouldn't be a current queue.
+  EXPECT_FALSE(queue->IsCurrent());
+  EXPECT_FALSE(TaskQueueBase::Current());
+
+  queue->PostTask(rtc::NewClosure([&event, &queue] {
+    EXPECT_TRUE(queue->IsCurrent());
+    event.Set();
+  }));
+  EXPECT_TRUE(event.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostCustomTask) {
+  rtc::Event ran;
+  auto queue = CreateTaskQueue(GetParam(), "PostCustomImplementation");
+
+  class CustomTask : public QueuedTask {
+   public:
+    explicit CustomTask(rtc::Event* ran) : ran_(ran) {}
+
+   private:
+    bool Run() override {
+      ran_->Set();
+      return false;  // Do not allow the task to be deleted by the queue.
+    }
+
+    rtc::Event* const ran_;
+  } my_task(&ran);
+
+  queue->PostTask(absl::WrapUnique(&my_task));
+  EXPECT_TRUE(ran.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostDelayedZero) {
+  rtc::Event event;
+  auto queue = CreateTaskQueue(GetParam(), "PostDelayedZero");
+
+  queue->PostDelayedTask(rtc::NewClosure([&event] { event.Set(); }), 0);
+  EXPECT_TRUE(event.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostFromQueue) {
+  rtc::Event event;
+  auto queue = CreateTaskQueue(GetParam(), "PostFromQueue");
+
+  queue->PostTask(rtc::NewClosure([&event, &queue] {
+    queue->PostTask(rtc::NewClosure([&event] { event.Set(); }));
+  }));
+  EXPECT_TRUE(event.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostDelayed) {
+  rtc::Event event;
+  auto queue = CreateTaskQueue(GetParam(), "PostDelayed",
+                               TaskQueueFactory::Priority::HIGH);
+
+  int64_t start = rtc::TimeMillis();
+  queue->PostDelayedTask(rtc::NewClosure([&event, &queue] {
+                           EXPECT_TRUE(queue->IsCurrent());
+                           event.Set();
+                         }),
+                         100);
+  EXPECT_TRUE(event.Wait(1000));
+  int64_t end = rtc::TimeMillis();
+  // These tests are a little relaxed due to how "powerful" our test bots can
+  // be.  Most recently we've seen windows bots fire the callback after 94-99ms,
+  // which is why we have a little bit of leeway backwards as well.
+  EXPECT_GE(end - start, 90u);
+  EXPECT_NEAR(end - start, 190u, 100u);  // Accept 90-290.
+}
+
+TEST_P(TaskQueueTest, PostMultipleDelayed) {
+  auto queue = CreateTaskQueue(GetParam(), "PostMultipleDelayed");
+
+  std::vector<rtc::Event> events(100);
+  for (int i = 0; i < 100; ++i) {
+    rtc::Event* event = &events[i];
+    queue->PostDelayedTask(rtc::NewClosure([event, &queue] {
+                             EXPECT_TRUE(queue->IsCurrent());
+                             event->Set();
+                           }),
+                           i);
+  }
+
+  for (rtc::Event& e : events)
+    EXPECT_TRUE(e.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostDelayedAfterDestruct) {
+  rtc::Event run;
+  rtc::Event deleted;
+  auto queue = CreateTaskQueue(GetParam(), "PostDelayedAfterDestruct");
+  queue->PostDelayedTask(
+      rtc::NewClosure([&run] { run.Set(); }, [&deleted] { deleted.Set(); }),
+      100);
+  // Destroy the queue.
+  queue = nullptr;
+  // Task might outlive the TaskQueue, but still should be deleted.
+  EXPECT_TRUE(deleted.Wait(200));
+  EXPECT_FALSE(run.Wait(0));  // and should not run.
+}
+
+TEST_P(TaskQueueTest, PostAndReuse) {
+  rtc::Event event;
+  auto post_queue = CreateTaskQueue(GetParam(), "PostQueue");
+  auto reply_queue = CreateTaskQueue(GetParam(), "ReplyQueue");
+
+  int call_count = 0;
+
+  class ReusedTask : public QueuedTask {
+   public:
+    ReusedTask(int* counter, TaskQueueBase* reply_queue, rtc::Event* event)
+        : counter_(*counter), reply_queue_(reply_queue), event_(*event) {
+      EXPECT_EQ(counter_, 0);
+    }
+
+   private:
+    bool Run() override {
+      if (++counter_ == 1) {
+        reply_queue_->PostTask(absl::WrapUnique(this));
+        // At this point, the object is owned by reply_queue_ and it's
+        // theoratically possible that the object has been deleted (e.g. if
+        // posting wasn't possible).  So, don't touch any member variables here.
+
+        // Indicate to the current queue that ownership has been transferred.
+        return false;
+      } else {
+        EXPECT_EQ(counter_, 2);
+        EXPECT_TRUE(reply_queue_->IsCurrent());
+        event_.Set();
+        return true;  // Indicate that the object should be deleted.
+      }
+    }
+
+    int& counter_;
+    TaskQueueBase* const reply_queue_;
+    rtc::Event& event_;
+  };
+
+  auto task =
+      absl::make_unique<ReusedTask>(&call_count, reply_queue.get(), &event);
+  post_queue->PostTask(std::move(task));
+  EXPECT_TRUE(event.Wait(1000));
+}
+
+// Tests posting more messages than a queue can queue up.
+// In situations like that, tasks will get dropped.
+TEST_P(TaskQueueTest, PostALot) {
+  // To destruct the event after the queue has gone out of scope.
+  rtc::Event event;
+
+  int tasks_executed = 0;
+  int tasks_cleaned_up = 0;
+  static const int kTaskCount = 0xffff;
+
+  {
+    auto queue = CreateTaskQueue(GetParam(), "PostALot");
+
+    // On linux, the limit of pending bytes in the pipe buffer is 0xffff.
+    // So here we post a total of 0xffff+1 messages, which triggers a failure
+    // case inside of the libevent queue implementation.
+
+    queue->PostTask(
+        rtc::NewClosure([&event] { event.Wait(rtc::Event::kForever); }));
+    for (int i = 0; i < kTaskCount; ++i)
+      queue->PostTask(
+          rtc::NewClosure([&tasks_executed] { ++tasks_executed; },
+                          [&tasks_cleaned_up] { ++tasks_cleaned_up; }));
+    event.Set();  // Unblock the first task.
+  }
+
+  EXPECT_GE(tasks_cleaned_up, tasks_executed);
+  EXPECT_EQ(tasks_cleaned_up, kTaskCount);
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/api/task_queue/task_queue_test.h b/api/task_queue/task_queue_test.h
new file mode 100644
index 0000000..300d6f3
--- /dev/null
+++ b/api/task_queue/task_queue_test.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_TASK_QUEUE_TASK_QUEUE_TEST_H_
+#define API_TASK_QUEUE_TASK_QUEUE_TEST_H_
+
+#include "api/task_queue/task_queue_factory.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+// Suite of tests to verify TaskQueue implementation with.
+// Example usage:
+//
+// namespace {
+//
+// using ::webrtc::TaskQueueTest;
+// webrtc::TaskQueueFactory* MyFactory();
+// INSTANTIATE_TEST_SUITE_P(My, TaskQueueTest, ::testing::Values(MyFactory()));
+//
+// }  // namespace
+class TaskQueueTest : public ::testing::TestWithParam<TaskQueueFactory*> {};
+
+}  // namespace webrtc
+
+#endif  // API_TASK_QUEUE_TASK_QUEUE_TEST_H_