blob: 24d829acf9b7372b47f594fa9ab69a3bae8c4f88 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Mark Slee9f0c6512007-02-28 23:58:26 +000019
Roger Meier49ff8b12012-04-13 09:12:31 +000020#include <thrift/concurrency/TimerManager.h>
cyyca8af9b2019-01-11 22:13:12 +080021#include <thrift/concurrency/ThreadFactory.h>
Roger Meier49ff8b12012-04-13 09:12:31 +000022#include <thrift/concurrency/Monitor.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000023
24#include <assert.h>
25#include <iostream>
26
Konrad Grochowski16a23a62014-11-13 15:33:38 +010027namespace apache {
28namespace thrift {
29namespace concurrency {
30namespace test {
Marc Slemko8a40a762006-07-19 17:46:50 +000031
T Jake Lucianib5e62212009-01-31 22:36:20 +000032using namespace apache::thrift::concurrency;
Marc Slemko8a40a762006-07-19 17:46:50 +000033
Marc Slemko8a40a762006-07-19 17:46:50 +000034class TimerManagerTests {
35
Konrad Grochowski16a23a62014-11-13 15:33:38 +010036public:
37 class Task : public Runnable {
38 public:
39 Task(Monitor& monitor, int64_t timeout)
40 : _timeout(timeout),
cyybfdbd032019-01-12 14:38:28 +080041 _startTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count()),
James E. King, III36200902016-10-05 14:47:18 -040042 _endTime(0),
Konrad Grochowski16a23a62014-11-13 15:33:38 +010043 _monitor(monitor),
44 _success(false),
45 _done(false) {}
Marc Slemko8a40a762006-07-19 17:46:50 +000046
Mark Sleef5f2be42006-09-05 21:05:31 +000047 ~Task() { std::cerr << this << std::endl; }
Marc Slemko6f038a72006-08-03 18:58:09 +000048
Marc Slemko8a40a762006-07-19 17:46:50 +000049 void run() {
50
cyybfdbd032019-01-12 14:38:28 +080051 _endTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
James E. King, IIIdf899132016-11-12 15:16:30 -050052 _success = (_endTime - _startTime) >= _timeout;
Marc Slemko6f038a72006-08-03 18:58:09 +000053
Konrad Grochowski16a23a62014-11-13 15:33:38 +010054 {
55 Synchronized s(_monitor);
James E. King, IIIdf899132016-11-12 15:16:30 -050056 _done = true;
David Reiss96d23882007-07-26 21:10:32 +000057 _monitor.notifyAll();
Marc Slemko8a40a762006-07-19 17:46:50 +000058 }
David Reiss0c90f6f2008-02-06 22:18:40 +000059 }
Marc Slemko9f27a4e2006-07-19 20:02:22 +000060
Mark Slee9b82d272007-05-23 05:16:07 +000061 int64_t _timeout;
62 int64_t _startTime;
63 int64_t _endTime;
Marc Slemko8a40a762006-07-19 17:46:50 +000064 Monitor& _monitor;
Marc Slemko9f27a4e2006-07-19 20:02:22 +000065 bool _success;
Marc Slemko8a40a762006-07-19 17:46:50 +000066 bool _done;
67 };
68
Mark Sleef5f2be42006-09-05 21:05:31 +000069 /**
70 * This test creates two tasks and waits for the first to expire within 10%
71 * of the expected expiration time. It then verifies that the timer manager
72 * properly clean up itself and the remaining orphaned timeout task when the
73 * manager goes out of scope and its destructor is called.
74 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +010075 bool test00(int64_t timeout = 1000LL) {
Marc Slemko8a40a762006-07-19 17:46:50 +000076
Konrad Grochowski16a23a62014-11-13 15:33:38 +010077 shared_ptr<TimerManagerTests::Task> orphanTask
78 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, 10 * timeout));
Marc Slemko8a40a762006-07-19 17:46:50 +000079
Marc Slemko9f27a4e2006-07-19 20:02:22 +000080 {
Marc Slemko9f27a4e2006-07-19 20:02:22 +000081 TimerManager timerManager;
cyyca8af9b2019-01-11 22:13:12 +080082 timerManager.threadFactory(shared_ptr<ThreadFactory>(new ThreadFactory()));
Marc Slemko9f27a4e2006-07-19 20:02:22 +000083 timerManager.start();
James E. King III9bea32f2018-03-16 16:07:42 -040084 if (timerManager.state() != TimerManager::STARTED) {
85 std::cerr << "timerManager is not in the STARTED state, but should be" << std::endl;
86 return false;
87 }
Marc Slemko8a40a762006-07-19 17:46:50 +000088
David Reiss52687eb2009-06-04 00:32:57 +000089 // Don't create task yet, because its constructor sets the expected completion time, and we
90 // need to delay between inserting the two tasks into the run queue.
91 shared_ptr<TimerManagerTests::Task> task;
Marc Slemko8a40a762006-07-19 17:46:50 +000092
Mark Sleef5f2be42006-09-05 21:05:31 +000093 {
94 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +000095 timerManager.add(orphanTask, 10 * timeout);
Marc Slemko8a40a762006-07-19 17:46:50 +000096
James E. King III9bea32f2018-03-16 16:07:42 -040097 THRIFT_SLEEP_USEC(timeout * 1000);
David Reiss52687eb2009-06-04 00:32:57 +000098
Konrad Grochowski16a23a62014-11-13 15:33:38 +010099 task.reset(new TimerManagerTests::Task(_monitor, timeout));
David Reiss96d23882007-07-26 21:10:32 +0000100 timerManager.add(task, timeout);
David Reiss96d23882007-07-26 21:10:32 +0000101 _monitor.wait();
Marc Slemko9f27a4e2006-07-19 20:02:22 +0000102 }
103
James E. King III9bea32f2018-03-16 16:07:42 -0400104 if (!task->_done) {
105 std::cerr << "task is not done, but it should have executed" << std::endl;
106 return false;
107 }
Marc Slemko9f27a4e2006-07-19 20:02:22 +0000108
Marc Slemko9f27a4e2006-07-19 20:02:22 +0000109 std::cout << "\t\t\t" << (task->_success ? "Success" : "Failure") << "!" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000110 }
111
James E. King III9bea32f2018-03-16 16:07:42 -0400112 if (orphanTask->_done) {
113 std::cerr << "orphan task is done, but it should not have executed" << std::endl;
114 return false;
115 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000116
Marc Slemko8a40a762006-07-19 17:46:50 +0000117 return true;
118 }
119
Francois Ferrandcc2d5582017-08-25 09:01:26 +0200120 /**
121 * This test creates two tasks, removes the first one then waits for the second one. It then
122 * verifies that the timer manager properly clean up itself and the remaining orphaned timeout
123 * task when the manager goes out of scope and its destructor is called.
124 */
125 bool test01(int64_t timeout = 1000LL) {
126 TimerManager timerManager;
cyyca8af9b2019-01-11 22:13:12 +0800127 timerManager.threadFactory(shared_ptr<ThreadFactory>(new ThreadFactory()));
Francois Ferrandcc2d5582017-08-25 09:01:26 +0200128 timerManager.start();
129 assert(timerManager.state() == TimerManager::STARTED);
130
131 Synchronized s(_monitor);
132
133 // Setup the two tasks
134 shared_ptr<TimerManagerTests::Task> taskToRemove
135 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 2));
136 timerManager.add(taskToRemove, taskToRemove->_timeout);
137
138 shared_ptr<TimerManagerTests::Task> task
139 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout));
140 timerManager.add(task, task->_timeout);
141
142 // Remove one task and wait until the other has completed
143 timerManager.remove(taskToRemove);
144 _monitor.wait(timeout * 2);
145
146 assert(!taskToRemove->_done);
147 assert(task->_done);
148
149 return true;
150 }
151
152 /**
153 * This test creates two tasks with the same callback and another one, then removes the two
154 * duplicated then waits for the last one. It then verifies that the timer manager properly
155 * clean up itself and the remaining orphaned timeout task when the manager goes out of scope
156 * and its destructor is called.
157 */
158 bool test02(int64_t timeout = 1000LL) {
159 TimerManager timerManager;
cyyca8af9b2019-01-11 22:13:12 +0800160 timerManager.threadFactory(shared_ptr<ThreadFactory>(new ThreadFactory()));
Francois Ferrandcc2d5582017-08-25 09:01:26 +0200161 timerManager.start();
162 assert(timerManager.state() == TimerManager::STARTED);
163
164 Synchronized s(_monitor);
165
166 // Setup the one tasks and add it twice
167 shared_ptr<TimerManagerTests::Task> taskToRemove
168 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 3));
169 timerManager.add(taskToRemove, taskToRemove->_timeout);
170 timerManager.add(taskToRemove, taskToRemove->_timeout * 2);
171
172 shared_ptr<TimerManagerTests::Task> task
173 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout));
174 timerManager.add(task, task->_timeout);
175
176 // Remove the first task (e.g. two timers) and wait until the other has completed
177 timerManager.remove(taskToRemove);
178 _monitor.wait(timeout * 2);
179
180 assert(!taskToRemove->_done);
181 assert(task->_done);
182
183 return true;
184 }
185
Francois Ferrand69603702017-09-11 12:09:40 +0200186 /**
187 * This test creates two tasks, removes the first one then waits for the second one. It then
188 * verifies that the timer manager properly clean up itself and the remaining orphaned timeout
189 * task when the manager goes out of scope and its destructor is called.
190 */
191 bool test03(int64_t timeout = 1000LL) {
192 TimerManager timerManager;
cyyca8af9b2019-01-11 22:13:12 +0800193 timerManager.threadFactory(shared_ptr<ThreadFactory>(new ThreadFactory()));
Francois Ferrand69603702017-09-11 12:09:40 +0200194 timerManager.start();
195 assert(timerManager.state() == TimerManager::STARTED);
196
197 Synchronized s(_monitor);
198
199 // Setup the two tasks
200 shared_ptr<TimerManagerTests::Task> taskToRemove
201 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 2));
202 TimerManager::Timer timer = timerManager.add(taskToRemove, taskToRemove->_timeout);
203
204 shared_ptr<TimerManagerTests::Task> task
205 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout));
206 timerManager.add(task, task->_timeout);
207
208 // Remove one task and wait until the other has completed
209 timerManager.remove(timer);
210 _monitor.wait(timeout * 2);
211
212 assert(!taskToRemove->_done);
213 assert(task->_done);
214
215 // Verify behavior when removing the removed task
216 try {
217 timerManager.remove(timer);
218 assert(0 == "ERROR: This remove should send a NoSuchTaskException exception.");
219 } catch (NoSuchTaskException&) {
220 }
221
222 return true;
223 }
224
225 /**
226 * This test creates one tasks, and tries to remove it after it has expired.
227 */
228 bool test04(int64_t timeout = 1000LL) {
229 TimerManager timerManager;
cyyca8af9b2019-01-11 22:13:12 +0800230 timerManager.threadFactory(shared_ptr<ThreadFactory>(new ThreadFactory()));
Francois Ferrand69603702017-09-11 12:09:40 +0200231 timerManager.start();
232 assert(timerManager.state() == TimerManager::STARTED);
233
234 Synchronized s(_monitor);
235
236 // Setup the task
237 shared_ptr<TimerManagerTests::Task> task
238 = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 10));
239 TimerManager::Timer timer = timerManager.add(task, task->_timeout);
240
241 // Wait until the task has completed
242 _monitor.wait(timeout);
243
244 // Verify behavior when removing the expired task
245 try {
246 timerManager.remove(timer);
247 assert(0 == "ERROR: This remove should send a NoSuchTaskException exception.");
248 } catch (NoSuchTaskException&) {
249 }
250
251 return true;
252 }
253
Marc Slemko8a40a762006-07-19 17:46:50 +0000254 friend class TestTask;
255
256 Monitor _monitor;
257};
Marc Slemko8a40a762006-07-19 17:46:50 +0000258
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100259}
260}
261}
262} // apache::thrift::concurrency