webrtc/api/task_queue/task_queue_test.cc
Danil Chapovalov 95e0a607f6 Increase TaskQueueTest.PostALot timeouts
recent changed decreased timeout from forever to 1s which is not enough on some platforms
Increase timeout to forever for posting 65k tasks.
Also increase timeout for eventual destruction of the tasks to reduce change it would flake.

Bug: chromium:972917
Change-Id: I4948d49c1514833ab190856fdd25a47a5bad91eb
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/141410
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28235}
2019-06-11 14:42:18 +00:00

273 lines
9.1 KiB
C++

/*
* 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/ref_counter.h"
#include "rtc_base/task_utils/to_queued_task.h"
#include "rtc_base/time_utils.h"
namespace webrtc {
namespace {
std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
const std::unique_ptr<webrtc::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) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
auto queue = CreateTaskQueue(factory, "Construct");
EXPECT_FALSE(queue->IsCurrent());
}
TEST_P(TaskQueueTest, PostAndCheckCurrent) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
rtc::Event event;
auto queue = CreateTaskQueue(factory, "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(ToQueuedTask([&event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event.Set();
}));
EXPECT_TRUE(event.Wait(1000));
}
TEST_P(TaskQueueTest, PostCustomTask) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
rtc::Event ran;
auto queue = CreateTaskQueue(factory, "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) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
rtc::Event event;
auto queue = CreateTaskQueue(factory, "PostDelayedZero");
queue->PostDelayedTask(ToQueuedTask([&event] { event.Set(); }), 0);
EXPECT_TRUE(event.Wait(1000));
}
TEST_P(TaskQueueTest, PostFromQueue) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
rtc::Event event;
auto queue = CreateTaskQueue(factory, "PostFromQueue");
queue->PostTask(ToQueuedTask([&event, &queue] {
queue->PostTask(ToQueuedTask([&event] { event.Set(); }));
}));
EXPECT_TRUE(event.Wait(1000));
}
TEST_P(TaskQueueTest, PostDelayed) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
rtc::Event event;
auto queue =
CreateTaskQueue(factory, "PostDelayed", TaskQueueFactory::Priority::HIGH);
int64_t start = rtc::TimeMillis();
queue->PostDelayedTask(ToQueuedTask([&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) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
auto queue = CreateTaskQueue(factory, "PostMultipleDelayed");
std::vector<rtc::Event> events(100);
for (int i = 0; i < 100; ++i) {
rtc::Event* event = &events[i];
queue->PostDelayedTask(ToQueuedTask([event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event->Set();
}),
i);
}
for (rtc::Event& e : events)
EXPECT_TRUE(e.Wait(1000));
}
TEST_P(TaskQueueTest, PostDelayedAfterDestruct) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
rtc::Event run;
rtc::Event deleted;
auto queue = CreateTaskQueue(factory, "PostDelayedAfterDestruct");
queue->PostDelayedTask(
ToQueuedTask([&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) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
rtc::Event event;
auto post_queue = CreateTaskQueue(factory, "PostQueue");
auto reply_queue = CreateTaskQueue(factory, "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));
}
TEST_P(TaskQueueTest, PostALot) {
// Waits until DecrementCount called |count| times. Thread safe.
class BlockingCounter {
public:
explicit BlockingCounter(int initial_count) : count_(initial_count) {}
void DecrementCount() {
if (count_.DecRef() == rtc::RefCountReleaseStatus::kDroppedLastRef) {
event_.Set();
}
}
bool Wait(int give_up_after_ms) { return event_.Wait(give_up_after_ms); }
private:
webrtc_impl::RefCounter count_;
rtc::Event event_;
};
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
static constexpr int kTaskCount = 0xffff;
rtc::Event posting_done;
BlockingCounter all_destroyed(kTaskCount);
int tasks_executed = 0;
auto task_queue = CreateTaskQueue(factory, "PostALot");
task_queue->PostTask(ToQueuedTask([&] {
// Post tasks from the queue to guarantee that the 1st task won't be
// executed before the last one is posted.
for (int i = 0; i < kTaskCount; ++i) {
task_queue->PostTask(ToQueuedTask(
[&] { ++tasks_executed; }, [&] { all_destroyed.DecrementCount(); }));
}
posting_done.Set();
}));
// Before destroying the task queue wait until all child tasks are posted.
posting_done.Wait(rtc::Event::kForever);
// Destroy the task queue.
task_queue = nullptr;
// Expect all tasks are destroyed eventually. In some task queue
// implementations that might happen on a different thread after task queue is
// destroyed.
EXPECT_TRUE(all_destroyed.Wait(60000));
EXPECT_LE(tasks_executed, kTaskCount);
}
// Test posting two tasks that have shared state not protected by a
// lock. The TaskQueue should guarantee memory read-write order and
// FIFO task execution order, so the second task should always see the
// changes that were made by the first task.
//
// If the TaskQueue doesn't properly synchronize the execution of
// tasks, there will be a data race, which is undefined behavior. The
// EXPECT calls may randomly catch this, but to make the most of this
// unit test, run it under TSan or some other tool that is able to
// directly detect data races.
TEST_P(TaskQueueTest, PostTwoWithSharedUnprotectedState) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
struct SharedState {
// First task will set this value to 1 and second will assert it.
int state = 0;
} state;
auto queue = CreateTaskQueue(factory, "PostTwoWithSharedUnprotectedState");
rtc::Event done;
queue->PostTask(ToQueuedTask([&state, &queue, &done] {
// Post tasks from queue to guarantee, that 1st task won't be
// executed before the second one will be posted.
queue->PostTask(ToQueuedTask([&state] { state.state = 1; }));
queue->PostTask(ToQueuedTask([&state, &done] {
EXPECT_EQ(state.state, 1);
done.Set();
}));
// Check, that state changing tasks didn't start yet.
EXPECT_EQ(state.state, 0);
}));
EXPECT_TRUE(done.Wait(1000));
}
} // namespace
} // namespace webrtc