blob: c84eb07326528f01766d921abc573e008799ce4d [file] [log] [blame]
Jordan Baylesb0c191e2019-03-26 15:49:57 -07001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <thread> // NOLINT
6
7#include "api/impl/task_runner_impl.h"
Jordan Bayles5d72bc22019-04-09 13:33:52 -07008#include "api/impl/testing/fake_clock.h"
Jordan Baylesb0c191e2019-03-26 15:49:57 -07009#include "api/public/task_runner_factory.h"
10#include "platform/api/time.h"
11#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
12
13namespace {
14using openscreen::platform::Clock;
15using std::chrono::milliseconds;
16
17const auto kTaskRunnerSleepTime = milliseconds(1);
18
19void WaitUntilCondition(std::function<bool()> predicate) {
20 while (!predicate()) {
21 std::this_thread::sleep_for(kTaskRunnerSleepTime);
22 }
23}
24} // anonymous namespace
25
26namespace openscreen {
27namespace platform {
28
29TEST(TaskRunnerTest, TaskRunnerFromFactoryExecutesTask) {
Jordan Bayles5d72bc22019-04-09 13:33:52 -070030 FakeClock fake_clock{platform::Clock::time_point(milliseconds(1337))};
31 auto runner = TaskRunnerFactory::Create(fake_clock.now);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070032
33 std::thread t([&runner] {
34 static_cast<TaskRunnerImpl*>(runner.get())->RunUntilStopped();
35 });
36
37 std::string ran_tasks = "";
38 const auto task = [&ran_tasks] { ran_tasks += "1"; };
39 EXPECT_EQ(ran_tasks, "");
40
41 runner->PostTask(task);
42
43 WaitUntilCondition([&ran_tasks] { return ran_tasks == "1"; });
44 EXPECT_EQ(ran_tasks, "1");
45
46 static_cast<TaskRunnerImpl*>(runner.get())->RequestStopSoon();
47 t.join();
48}
49
50TEST(TaskRunnerTest, TaskRunnerRunsDelayedTasksInOrder) {
Jordan Bayles5d72bc22019-04-09 13:33:52 -070051 FakeClock fake_clock{platform::Clock::time_point(milliseconds(1337))};
52 auto runner = TaskRunnerFactory::Create(fake_clock.now);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070053
54 std::thread t([&runner] {
55 static_cast<TaskRunnerImpl*>(runner.get())->RunUntilStopped();
56 });
57
58 std::string ran_tasks = "";
59
Jordan Bayles5d72bc22019-04-09 13:33:52 -070060 const auto kDelayTime = milliseconds(5);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070061 const auto task_one = [&ran_tasks] { ran_tasks += "1"; };
Jordan Bayles5d72bc22019-04-09 13:33:52 -070062 runner->PostTaskWithDelay(task_one, kDelayTime);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070063
Jordan Baylesb0c191e2019-03-26 15:49:57 -070064 const auto task_two = [&ran_tasks] { ran_tasks += "2"; };
Jordan Bayles5d72bc22019-04-09 13:33:52 -070065 runner->PostTaskWithDelay(task_two, kDelayTime * 2);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070066
Jordan Bayles5d72bc22019-04-09 13:33:52 -070067 EXPECT_EQ(ran_tasks, "");
68 fake_clock.Advance(kDelayTime);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070069 WaitUntilCondition([&ran_tasks] { return ran_tasks == "1"; });
70 EXPECT_EQ(ran_tasks, "1");
71
Jordan Bayles5d72bc22019-04-09 13:33:52 -070072 fake_clock.Advance(kDelayTime);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070073 WaitUntilCondition([&ran_tasks] { return ran_tasks == "12"; });
74 EXPECT_EQ(ran_tasks, "12");
75
76 static_cast<TaskRunnerImpl*>(runner.get())->RequestStopSoon();
77 t.join();
78}
79
80TEST(TaskRunnerTest, SingleThreadedTaskRunnerRunsSequentially) {
Jordan Bayles5d72bc22019-04-09 13:33:52 -070081 FakeClock fake_clock{platform::Clock::time_point(milliseconds(1337))};
82 TaskRunnerImpl runner(fake_clock.now);
Jordan Baylesb0c191e2019-03-26 15:49:57 -070083
84 std::string ran_tasks;
85 const auto task_one = [&ran_tasks] { ran_tasks += "1"; };
86 const auto task_two = [&ran_tasks] { ran_tasks += "2"; };
87 const auto task_three = [&ran_tasks] { ran_tasks += "3"; };
88 const auto task_four = [&ran_tasks] { ran_tasks += "4"; };
89 const auto task_five = [&ran_tasks] { ran_tasks += "5"; };
90
91 runner.PostTask(task_one);
92 runner.PostTask(task_two);
93 runner.PostTask(task_three);
94 runner.PostTask(task_four);
95 runner.PostTask(task_five);
96 EXPECT_EQ(ran_tasks, "");
97
98 runner.RunUntilIdleForTesting();
99 EXPECT_EQ(ran_tasks, "12345");
100}
101
102TEST(TaskRunnerTest, TaskRunnerCanStopRunning) {
Jordan Bayles5d72bc22019-04-09 13:33:52 -0700103 FakeClock fake_clock{platform::Clock::time_point(milliseconds(1337))};
104 TaskRunnerImpl runner(fake_clock.now);
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700105
106 std::string ran_tasks;
107 const auto task_one = [&ran_tasks] { ran_tasks += "1"; };
108 const auto task_two = [&ran_tasks] { ran_tasks += "2"; };
109
110 runner.PostTask(task_one);
111 EXPECT_EQ(ran_tasks, "");
112
113 std::thread start_thread([&runner] { runner.RunUntilStopped(); });
114
115 WaitUntilCondition([&ran_tasks] { return !ran_tasks.empty(); });
116 EXPECT_EQ(ran_tasks, "1");
117
118 // Since Stop is called first, and the single threaded task
119 // runner should honor the queue, we know the task runner is not running
120 // since task two doesn't get ran.
121 runner.RequestStopSoon();
122 runner.PostTask(task_two);
123 EXPECT_EQ(ran_tasks, "1");
124
125 start_thread.join();
126}
127
128TEST(TaskRunnerTest, StoppingDoesNotDeleteTasks) {
Jordan Bayles5d72bc22019-04-09 13:33:52 -0700129 FakeClock fake_clock{platform::Clock::time_point(milliseconds(1337))};
130 TaskRunnerImpl runner(fake_clock.now);
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700131
132 std::string ran_tasks;
133 const auto task_one = [&ran_tasks] { ran_tasks += "1"; };
134
135 runner.PostTask(task_one);
136 runner.RequestStopSoon();
137
138 EXPECT_EQ(ran_tasks, "");
139 runner.RunUntilIdleForTesting();
140
141 EXPECT_EQ(ran_tasks, "1");
142}
143
144TEST(TaskRunnerTest, TaskRunnerIsStableWithLotsOfTasks) {
Jordan Bayles5d72bc22019-04-09 13:33:52 -0700145 FakeClock fake_clock{platform::Clock::time_point(milliseconds(1337))};
146 TaskRunnerImpl runner(fake_clock.now);
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700147
148 const int kNumberOfTasks = 500;
149 std::string expected_ran_tasks;
150 expected_ran_tasks.append(kNumberOfTasks, '1');
151
152 std::string ran_tasks;
153 for (int i = 0; i < kNumberOfTasks; ++i) {
154 const auto task = [&ran_tasks] { ran_tasks += "1"; };
155 runner.PostTask(task);
156 }
157
158 runner.RunUntilIdleForTesting();
159 EXPECT_EQ(ran_tasks, expected_ran_tasks);
160}
Jordan Baylesa8e96772019-04-08 10:53:54 -0700161
162TEST(TaskRunnerTest, TaskRunnerDelayedTasksDontBlockImmediateTasks) {
163 TaskRunnerImpl runner(platform::Clock::now);
164
165 std::string ran_tasks;
166 const auto task = [&ran_tasks] { ran_tasks += "1"; };
167 const auto delayed_task = [&ran_tasks] { ran_tasks += "A"; };
168
169 runner.PostTaskWithDelay(delayed_task, milliseconds(10000));
170 runner.PostTask(task);
171
172 runner.RunUntilIdleForTesting();
173 // The immediate task should have run, even though the delayed task
174 // was added first.
175
176 EXPECT_EQ(ran_tasks, "1");
177}
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700178} // namespace platform
179} // namespace openscreen