Index: webrtc/base/task_unittest.cc |
diff --git a/webrtc/base/task_unittest.cc b/webrtc/base/task_unittest.cc |
deleted file mode 100644 |
index 38ceb145fddb00550f1bbce2ce535a9f74a1d10a..0000000000000000000000000000000000000000 |
--- a/webrtc/base/task_unittest.cc |
+++ /dev/null |
@@ -1,542 +0,0 @@ |
-/* |
- * Copyright 2004 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. |
- */ |
- |
-#if defined(WEBRTC_POSIX) |
-#include <sys/time.h> |
-#endif // WEBRTC_POSIX |
- |
-// TODO: Remove this once the cause of sporadic failures in these |
-// tests is tracked down. |
-#include <iostream> |
- |
-#if defined(WEBRTC_WIN) |
-#include "webrtc/base/win32.h" |
-#endif // WEBRTC_WIN |
- |
-#include "webrtc/base/arraysize.h" |
-#include "webrtc/base/constructormagic.h" |
-#include "webrtc/base/gunit.h" |
-#include "webrtc/base/logging.h" |
-#include "webrtc/base/task.h" |
-#include "webrtc/base/taskrunner.h" |
-#include "webrtc/base/thread.h" |
-#include "webrtc/base/timeutils.h" |
- |
-namespace rtc { |
- |
-static int64_t GetCurrentTime() { |
- return TimeMillis() * 10000; |
-} |
- |
-// feel free to change these numbers. Note that '0' won't work, though |
-#define STUCK_TASK_COUNT 5 |
-#define HAPPY_TASK_COUNT 20 |
- |
-// this is a generic timeout task which, when it signals timeout, will |
-// include the unique ID of the task in the signal (we don't use this |
-// in production code because we haven't yet had occasion to generate |
-// an array of the same types of task) |
- |
-class IdTimeoutTask : public Task, public sigslot::has_slots<> { |
- public: |
- explicit IdTimeoutTask(TaskParent *parent) : Task(parent) { |
- SignalTimeout.connect(this, &IdTimeoutTask::OnLocalTimeout); |
- } |
- |
- sigslot::signal1<const int> SignalTimeoutId; |
- sigslot::signal1<const int> SignalDoneId; |
- |
- virtual int ProcessStart() { |
- return STATE_RESPONSE; |
- } |
- |
- void OnLocalTimeout() { |
- SignalTimeoutId(unique_id()); |
- } |
- |
- protected: |
- virtual void Stop() { |
- SignalDoneId(unique_id()); |
- Task::Stop(); |
- } |
-}; |
- |
-class StuckTask : public IdTimeoutTask { |
- public: |
- explicit StuckTask(TaskParent *parent) : IdTimeoutTask(parent) {} |
- virtual int ProcessStart() { |
- return STATE_BLOCKED; |
- } |
-}; |
- |
-class HappyTask : public IdTimeoutTask { |
- public: |
- explicit HappyTask(TaskParent *parent) : IdTimeoutTask(parent) { |
- time_to_perform_ = rand() % (STUCK_TASK_COUNT / 2); |
- } |
- virtual int ProcessStart() { |
- if (ElapsedTime() > (time_to_perform_ * 1000 * 10000)) |
- return STATE_RESPONSE; |
- else |
- return STATE_BLOCKED; |
- } |
- |
- private: |
- int time_to_perform_; |
-}; |
- |
-// simple implementation of a task runner which uses Windows' |
-// GetSystemTimeAsFileTime() to get the current clock ticks |
- |
-class MyTaskRunner : public TaskRunner { |
- public: |
- virtual void WakeTasks() { RunTasks(); } |
- virtual int64_t CurrentTime() { return GetCurrentTime(); } |
- |
- bool timeout_change() const { |
- return timeout_change_; |
- } |
- |
- void clear_timeout_change() { |
- timeout_change_ = false; |
- } |
- protected: |
- virtual void OnTimeoutChange() { |
- timeout_change_ = true; |
- } |
- bool timeout_change_; |
-}; |
- |
-// |
-// this unit test is primarily concerned (for now) with the timeout |
-// functionality in tasks. It works as follows: |
-// |
-// * Create a bunch of tasks, some "stuck" (ie., guaranteed to timeout) |
-// and some "happy" (will immediately finish). |
-// * Set the timeout on the "stuck" tasks to some number of seconds between |
-// 1 and the number of stuck tasks |
-// * Start all the stuck & happy tasks in random order |
-// * Wait "number of stuck tasks" seconds and make sure everything timed out |
- |
-class TaskTest : public sigslot::has_slots<> { |
- public: |
- TaskTest() {} |
- |
- // no need to delete any tasks; the task runner owns them |
- ~TaskTest() {} |
- |
- void Start() { |
- // create and configure tasks |
- for (int i = 0; i < STUCK_TASK_COUNT; ++i) { |
- stuck_[i].task_ = new StuckTask(&task_runner_); |
- stuck_[i].task_->SignalTimeoutId.connect(this, |
- &TaskTest::OnTimeoutStuck); |
- stuck_[i].timed_out_ = false; |
- stuck_[i].xlat_ = stuck_[i].task_->unique_id(); |
- stuck_[i].task_->set_timeout_seconds(i + 1); |
- LOG(LS_INFO) << "Task " << stuck_[i].xlat_ << " created with timeout " |
- << stuck_[i].task_->timeout_seconds(); |
- } |
- |
- for (int i = 0; i < HAPPY_TASK_COUNT; ++i) { |
- happy_[i].task_ = new HappyTask(&task_runner_); |
- happy_[i].task_->SignalTimeoutId.connect(this, |
- &TaskTest::OnTimeoutHappy); |
- happy_[i].task_->SignalDoneId.connect(this, |
- &TaskTest::OnDoneHappy); |
- happy_[i].timed_out_ = false; |
- happy_[i].xlat_ = happy_[i].task_->unique_id(); |
- } |
- |
- // start all the tasks in random order |
- int stuck_index = 0; |
- int happy_index = 0; |
- for (int i = 0; i < STUCK_TASK_COUNT + HAPPY_TASK_COUNT; ++i) { |
- if ((stuck_index < STUCK_TASK_COUNT) && |
- (happy_index < HAPPY_TASK_COUNT)) { |
- if (rand() % 2 == 1) { |
- stuck_[stuck_index++].task_->Start(); |
- } else { |
- happy_[happy_index++].task_->Start(); |
- } |
- } else if (stuck_index < STUCK_TASK_COUNT) { |
- stuck_[stuck_index++].task_->Start(); |
- } else { |
- happy_[happy_index++].task_->Start(); |
- } |
- } |
- |
- for (int i = 0; i < STUCK_TASK_COUNT; ++i) { |
- std::cout << "Stuck task #" << i << " timeout is " << |
- stuck_[i].task_->timeout_seconds() << " at " << |
- stuck_[i].task_->timeout_time() << std::endl; |
- } |
- |
- // just a little self-check to make sure we started all the tasks |
- ASSERT_EQ(STUCK_TASK_COUNT, stuck_index); |
- ASSERT_EQ(HAPPY_TASK_COUNT, happy_index); |
- |
- // run the unblocked tasks |
- LOG(LS_INFO) << "Running tasks"; |
- task_runner_.RunTasks(); |
- |
- std::cout << "Start time is " << GetCurrentTime() << std::endl; |
- |
- // give all the stuck tasks time to timeout |
- for (int i = 0; !task_runner_.AllChildrenDone() && i < STUCK_TASK_COUNT; |
- ++i) { |
- Thread::Current()->ProcessMessages(1000); |
- for (int j = 0; j < HAPPY_TASK_COUNT; ++j) { |
- if (happy_[j].task_) { |
- happy_[j].task_->Wake(); |
- } |
- } |
- LOG(LS_INFO) << "Polling tasks"; |
- task_runner_.PollTasks(); |
- } |
- |
- // We see occasional test failures here due to the stuck tasks not having |
- // timed-out yet, which seems like it should be impossible. To help track |
- // this down we have added logging of the timing information, which we send |
- // directly to stdout so that we get it in opt builds too. |
- std::cout << "End time is " << GetCurrentTime() << std::endl; |
- } |
- |
- void OnTimeoutStuck(const int id) { |
- LOG(LS_INFO) << "Timed out task " << id; |
- |
- int i; |
- for (i = 0; i < STUCK_TASK_COUNT; ++i) { |
- if (stuck_[i].xlat_ == id) { |
- stuck_[i].timed_out_ = true; |
- stuck_[i].task_ = NULL; |
- break; |
- } |
- } |
- |
- // getting a bad ID here is a failure, but let's continue |
- // running to see what else might go wrong |
- EXPECT_LT(i, STUCK_TASK_COUNT); |
- } |
- |
- void OnTimeoutHappy(const int id) { |
- int i; |
- for (i = 0; i < HAPPY_TASK_COUNT; ++i) { |
- if (happy_[i].xlat_ == id) { |
- happy_[i].timed_out_ = true; |
- happy_[i].task_ = NULL; |
- break; |
- } |
- } |
- |
- // getting a bad ID here is a failure, but let's continue |
- // running to see what else might go wrong |
- EXPECT_LT(i, HAPPY_TASK_COUNT); |
- } |
- |
- void OnDoneHappy(const int id) { |
- int i; |
- for (i = 0; i < HAPPY_TASK_COUNT; ++i) { |
- if (happy_[i].xlat_ == id) { |
- happy_[i].task_ = NULL; |
- break; |
- } |
- } |
- |
- // getting a bad ID here is a failure, but let's continue |
- // running to see what else might go wrong |
- EXPECT_LT(i, HAPPY_TASK_COUNT); |
- } |
- |
- void check_passed() { |
- EXPECT_TRUE(task_runner_.AllChildrenDone()); |
- |
- // make sure none of our happy tasks timed out |
- for (int i = 0; i < HAPPY_TASK_COUNT; ++i) { |
- EXPECT_FALSE(happy_[i].timed_out_); |
- } |
- |
- // make sure all of our stuck tasks timed out |
- for (int i = 0; i < STUCK_TASK_COUNT; ++i) { |
- EXPECT_TRUE(stuck_[i].timed_out_); |
- if (!stuck_[i].timed_out_) { |
- std::cout << "Stuck task #" << i << " timeout is at " |
- << stuck_[i].task_->timeout_time() << std::endl; |
- } |
- } |
- |
- std::cout.flush(); |
- } |
- |
- private: |
- struct TaskInfo { |
- IdTimeoutTask *task_; |
- bool timed_out_; |
- int xlat_; |
- }; |
- |
- MyTaskRunner task_runner_; |
- TaskInfo stuck_[STUCK_TASK_COUNT]; |
- TaskInfo happy_[HAPPY_TASK_COUNT]; |
-}; |
- |
-TEST(start_task_test, Timeout) { |
- TaskTest task_test; |
- task_test.Start(); |
- task_test.check_passed(); |
-} |
- |
-// Test for aborting the task while it is running |
- |
-class AbortTask : public Task { |
- public: |
- explicit AbortTask(TaskParent *parent) : Task(parent) { |
- set_timeout_seconds(1); |
- } |
- |
- virtual int ProcessStart() { |
- Abort(); |
- return STATE_NEXT; |
- } |
- private: |
- RTC_DISALLOW_COPY_AND_ASSIGN(AbortTask); |
-}; |
- |
-class TaskAbortTest : public sigslot::has_slots<> { |
- public: |
- TaskAbortTest() {} |
- |
- // no need to delete any tasks; the task runner owns them |
- ~TaskAbortTest() {} |
- |
- void Start() { |
- Task *abort_task = new AbortTask(&task_runner_); |
- abort_task->SignalTimeout.connect(this, &TaskAbortTest::OnTimeout); |
- abort_task->Start(); |
- |
- // run the task |
- task_runner_.RunTasks(); |
- } |
- |
- private: |
- void OnTimeout() { |
- FAIL() << "Task timed out instead of aborting."; |
- } |
- |
- MyTaskRunner task_runner_; |
- RTC_DISALLOW_COPY_AND_ASSIGN(TaskAbortTest); |
-}; |
- |
-TEST(start_task_test, Abort) { |
- TaskAbortTest abort_test; |
- abort_test.Start(); |
-} |
- |
-// Test for aborting a task to verify that it does the Wake operation |
-// which gets it deleted. |
- |
-class SetBoolOnDeleteTask : public Task { |
- public: |
- SetBoolOnDeleteTask(TaskParent *parent, bool *set_when_deleted) |
- : Task(parent), |
- set_when_deleted_(set_when_deleted) { |
- EXPECT_TRUE(NULL != set_when_deleted); |
- EXPECT_FALSE(*set_when_deleted); |
- } |
- |
- virtual ~SetBoolOnDeleteTask() { |
- *set_when_deleted_ = true; |
- } |
- |
- virtual int ProcessStart() { |
- return STATE_BLOCKED; |
- } |
- |
- private: |
- bool* set_when_deleted_; |
- RTC_DISALLOW_COPY_AND_ASSIGN(SetBoolOnDeleteTask); |
-}; |
- |
-class AbortShouldWakeTest : public sigslot::has_slots<> { |
- public: |
- AbortShouldWakeTest() {} |
- |
- // no need to delete any tasks; the task runner owns them |
- ~AbortShouldWakeTest() {} |
- |
- void Start() { |
- bool task_deleted = false; |
- Task *task_to_abort = new SetBoolOnDeleteTask(&task_runner_, &task_deleted); |
- task_to_abort->Start(); |
- |
- // Task::Abort() should call TaskRunner::WakeTasks(). WakeTasks calls |
- // TaskRunner::RunTasks() immediately which should delete the task. |
- task_to_abort->Abort(); |
- EXPECT_TRUE(task_deleted); |
- |
- if (!task_deleted) { |
- // avoid a crash (due to referencing a local variable) |
- // if the test fails. |
- task_runner_.RunTasks(); |
- } |
- } |
- |
- private: |
- void OnTimeout() { |
- FAIL() << "Task timed out instead of aborting."; |
- } |
- |
- MyTaskRunner task_runner_; |
- RTC_DISALLOW_COPY_AND_ASSIGN(AbortShouldWakeTest); |
-}; |
- |
-TEST(start_task_test, AbortShouldWake) { |
- AbortShouldWakeTest abort_should_wake_test; |
- abort_should_wake_test.Start(); |
-} |
- |
-// Validate that TaskRunner's OnTimeoutChange gets called appropriately |
-// * When a task calls UpdateTaskTimeout |
-// * When the next timeout task time, times out |
-class TimeoutChangeTest : public sigslot::has_slots<> { |
- public: |
- TimeoutChangeTest() |
- : task_count_(arraysize(stuck_tasks_)) {} |
- |
- // no need to delete any tasks; the task runner owns them |
- ~TimeoutChangeTest() {} |
- |
- void Start() { |
- for (int i = 0; i < task_count_; ++i) { |
- stuck_tasks_[i] = new StuckTask(&task_runner_); |
- stuck_tasks_[i]->set_timeout_seconds(i + 2); |
- stuck_tasks_[i]->SignalTimeoutId.connect(this, |
- &TimeoutChangeTest::OnTimeoutId); |
- } |
- |
- for (int i = task_count_ - 1; i >= 0; --i) { |
- stuck_tasks_[i]->Start(); |
- } |
- task_runner_.clear_timeout_change(); |
- |
- // At this point, our timeouts are set as follows |
- // task[0] is 2 seconds, task[1] at 3 seconds, etc. |
- |
- stuck_tasks_[0]->set_timeout_seconds(2); |
- // Now, task[0] is 2 seconds, task[1] at 3 seconds... |
- // so timeout change shouldn't be called. |
- EXPECT_FALSE(task_runner_.timeout_change()); |
- task_runner_.clear_timeout_change(); |
- |
- stuck_tasks_[0]->set_timeout_seconds(1); |
- // task[0] is 1 seconds, task[1] at 3 seconds... |
- // The smallest timeout got smaller so timeout change be called. |
- EXPECT_TRUE(task_runner_.timeout_change()); |
- task_runner_.clear_timeout_change(); |
- |
- stuck_tasks_[1]->set_timeout_seconds(2); |
- // task[0] is 1 seconds, task[1] at 2 seconds... |
- // The smallest timeout is still 1 second so no timeout change. |
- EXPECT_FALSE(task_runner_.timeout_change()); |
- task_runner_.clear_timeout_change(); |
- |
- while (task_count_ > 0) { |
- int previous_count = task_count_; |
- task_runner_.PollTasks(); |
- if (previous_count != task_count_) { |
- // We only get here when a task times out. When that |
- // happens, the timeout change should get called because |
- // the smallest timeout is now in the past. |
- EXPECT_TRUE(task_runner_.timeout_change()); |
- task_runner_.clear_timeout_change(); |
- } |
- Thread::Current()->socketserver()->Wait(500, false); |
- } |
- } |
- |
- private: |
- void OnTimeoutId(const int id) { |
- for (size_t i = 0; i < arraysize(stuck_tasks_); ++i) { |
- if (stuck_tasks_[i] && stuck_tasks_[i]->unique_id() == id) { |
- task_count_--; |
- stuck_tasks_[i] = NULL; |
- break; |
- } |
- } |
- } |
- |
- MyTaskRunner task_runner_; |
- StuckTask* (stuck_tasks_[3]); |
- int task_count_; |
- RTC_DISALLOW_COPY_AND_ASSIGN(TimeoutChangeTest); |
-}; |
- |
-TEST(start_task_test, TimeoutChange) { |
- TimeoutChangeTest timeout_change_test; |
- timeout_change_test.Start(); |
-} |
- |
-class DeleteTestTaskRunner : public TaskRunner { |
- public: |
- DeleteTestTaskRunner() { |
- } |
- virtual void WakeTasks() { } |
- virtual int64_t CurrentTime() { return GetCurrentTime(); } |
- private: |
- RTC_DISALLOW_COPY_AND_ASSIGN(DeleteTestTaskRunner); |
-}; |
- |
-TEST(unstarted_task_test, DeleteTask) { |
- // This test ensures that we don't |
- // crash if a task is deleted without running it. |
- DeleteTestTaskRunner task_runner; |
- HappyTask* happy_task = new HappyTask(&task_runner); |
- happy_task->Start(); |
- |
- // try deleting the task directly |
- HappyTask* child_happy_task = new HappyTask(happy_task); |
- delete child_happy_task; |
- |
- // run the unblocked tasks |
- task_runner.RunTasks(); |
-} |
- |
-TEST(unstarted_task_test, DoNotDeleteTask1) { |
- // This test ensures that we don't |
- // crash if a task runner is deleted without |
- // running a certain task. |
- DeleteTestTaskRunner task_runner; |
- HappyTask* happy_task = new HappyTask(&task_runner); |
- happy_task->Start(); |
- |
- HappyTask* child_happy_task = new HappyTask(happy_task); |
- child_happy_task->Start(); |
- |
- // Never run the tasks |
-} |
- |
-TEST(unstarted_task_test, DoNotDeleteTask2) { |
- // This test ensures that we don't |
- // crash if a taskrunner is delete with a |
- // task that has never been started. |
- DeleteTestTaskRunner task_runner; |
- HappyTask* happy_task = new HappyTask(&task_runner); |
- happy_task->Start(); |
- |
- // Do not start the task. |
- // Note: this leaks memory, so don't do this. |
- // Instead, always run your tasks or delete them. |
- new HappyTask(happy_task); |
- |
- // run the unblocked tasks |
- task_runner.RunTasks(); |
-} |
- |
-} // namespace rtc |