1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpcpp/alarm.h>
20 #include <grpcpp/completion_queue.h>
21 #include <gtest/gtest.h>
22
23 #include <condition_variable>
24 #include <memory>
25 #include <mutex>
26 #include <thread>
27
28 #include "src/core/util/notification.h"
29 #include "test/core/test_util/test_config.h"
30
31 namespace grpc {
32 namespace {
33
TEST(AlarmTest,RegularExpiry)34 TEST(AlarmTest, RegularExpiry) {
35 CompletionQueue cq;
36 void* junk = reinterpret_cast<void*>(1618033);
37 Alarm alarm;
38 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
39
40 void* output_tag;
41 bool ok;
42 const CompletionQueue::NextStatus status =
43 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
44
45 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
46 EXPECT_TRUE(ok);
47 EXPECT_EQ(junk, output_tag);
48 }
49
TEST(AlarmTest,RegularExpiryMultiSet)50 TEST(AlarmTest, RegularExpiryMultiSet) {
51 CompletionQueue cq;
52 void* junk = reinterpret_cast<void*>(1618033);
53 Alarm alarm;
54
55 for (int i = 0; i < 3; i++) {
56 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
57
58 void* output_tag;
59 bool ok;
60 const CompletionQueue::NextStatus status =
61 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
62
63 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
64 EXPECT_TRUE(ok);
65 EXPECT_EQ(junk, output_tag);
66 }
67 }
68
TEST(AlarmTest,RegularExpiryMultiSetMultiCQ)69 TEST(AlarmTest, RegularExpiryMultiSetMultiCQ) {
70 void* junk = reinterpret_cast<void*>(1618033);
71 Alarm alarm;
72
73 for (int i = 0; i < 3; i++) {
74 CompletionQueue cq;
75 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
76
77 void* output_tag;
78 bool ok;
79 const CompletionQueue::NextStatus status =
80 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
81
82 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
83 EXPECT_TRUE(ok);
84 EXPECT_EQ(junk, output_tag);
85 }
86 }
87
88 struct Completion {
89 bool completed = false;
90 std::mutex mu;
91 std::condition_variable cv;
92 };
93
TEST(AlarmTest,CallbackRegularExpiry)94 TEST(AlarmTest, CallbackRegularExpiry) {
95 Alarm alarm;
96
97 auto c = std::make_shared<Completion>();
98 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(1),
99 [c](bool ok) {
100 EXPECT_TRUE(ok);
101 std::lock_guard<std::mutex> l(c->mu);
102 c->completed = true;
103 c->cv.notify_one();
104 });
105
106 std::unique_lock<std::mutex> l(c->mu);
107 EXPECT_TRUE(c->cv.wait_until(
108 l, std::chrono::system_clock::now() + std::chrono::seconds(10),
109 [c] { return c->completed; }));
110 }
111
TEST(AlarmTest,CallbackZeroExpiry)112 TEST(AlarmTest, CallbackZeroExpiry) {
113 Alarm alarm;
114
115 auto c = std::make_shared<Completion>();
116 alarm.Set(grpc_timeout_seconds_to_deadline(0), [c](bool ok) {
117 EXPECT_TRUE(ok);
118 std::lock_guard<std::mutex> l(c->mu);
119 c->completed = true;
120 c->cv.notify_one();
121 });
122
123 std::unique_lock<std::mutex> l(c->mu);
124 EXPECT_TRUE(c->cv.wait_until(
125 l, std::chrono::system_clock::now() + std::chrono::seconds(10),
126 [c] { return c->completed; }));
127 }
128
TEST(AlarmTest,CallbackNegativeExpiry)129 TEST(AlarmTest, CallbackNegativeExpiry) {
130 Alarm alarm;
131
132 auto c = std::make_shared<Completion>();
133 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(-1),
134 [c](bool ok) {
135 EXPECT_TRUE(ok);
136 std::lock_guard<std::mutex> l(c->mu);
137 c->completed = true;
138 c->cv.notify_one();
139 });
140
141 std::unique_lock<std::mutex> l(c->mu);
142 EXPECT_TRUE(c->cv.wait_until(
143 l, std::chrono::system_clock::now() + std::chrono::seconds(10),
144 [c] { return c->completed; }));
145 }
146
TEST(AlarmTest,MultithreadedRegularExpiry)147 TEST(AlarmTest, MultithreadedRegularExpiry) {
148 CompletionQueue cq;
149 void* junk = reinterpret_cast<void*>(1618033);
150 void* output_tag;
151 bool ok;
152 CompletionQueue::NextStatus status;
153 Alarm alarm;
154
155 std::thread t1([&alarm, &cq, &junk] {
156 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
157 });
158
159 std::thread t2([&cq, &ok, &output_tag, &status] {
160 status =
161 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
162 });
163
164 t1.join();
165 t2.join();
166 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
167 EXPECT_TRUE(ok);
168 EXPECT_EQ(junk, output_tag);
169 }
170
TEST(AlarmTest,DeprecatedRegularExpiry)171 TEST(AlarmTest, DeprecatedRegularExpiry) {
172 CompletionQueue cq;
173 void* junk = reinterpret_cast<void*>(1618033);
174 Alarm alarm(&cq, grpc_timeout_seconds_to_deadline(1), junk);
175
176 void* output_tag;
177 bool ok;
178 const CompletionQueue::NextStatus status =
179 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
180
181 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
182 EXPECT_TRUE(ok);
183 EXPECT_EQ(junk, output_tag);
184 }
185
TEST(AlarmTest,MoveConstructor)186 TEST(AlarmTest, MoveConstructor) {
187 CompletionQueue cq;
188 void* junk = reinterpret_cast<void*>(1618033);
189 Alarm first;
190 first.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
191 Alarm second(std::move(first));
192 void* output_tag;
193 bool ok;
194 const CompletionQueue::NextStatus status =
195 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
196 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
197 EXPECT_TRUE(ok);
198 EXPECT_EQ(junk, output_tag);
199 }
200
TEST(AlarmTest,MoveAssignment)201 TEST(AlarmTest, MoveAssignment) {
202 CompletionQueue cq;
203 void* junk = reinterpret_cast<void*>(1618033);
204 Alarm first;
205 first.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
206 Alarm second(std::move(first));
207 first = std::move(second);
208
209 void* output_tag;
210 bool ok;
211 const CompletionQueue::NextStatus status =
212 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
213
214 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
215 EXPECT_TRUE(ok);
216 EXPECT_EQ(junk, output_tag);
217 }
218
TEST(AlarmTest,RegularExpiryChrono)219 TEST(AlarmTest, RegularExpiryChrono) {
220 CompletionQueue cq;
221 void* junk = reinterpret_cast<void*>(1618033);
222 std::chrono::system_clock::time_point one_sec_deadline =
223 std::chrono::system_clock::now() + std::chrono::seconds(1);
224 Alarm alarm;
225 alarm.Set(&cq, one_sec_deadline, junk);
226
227 void* output_tag;
228 bool ok;
229 const CompletionQueue::NextStatus status =
230 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
231
232 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
233 EXPECT_TRUE(ok);
234 EXPECT_EQ(junk, output_tag);
235 }
236
TEST(AlarmTest,ZeroExpiry)237 TEST(AlarmTest, ZeroExpiry) {
238 CompletionQueue cq;
239 void* junk = reinterpret_cast<void*>(1618033);
240 Alarm alarm;
241 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(0), junk);
242
243 void* output_tag;
244 bool ok;
245 const CompletionQueue::NextStatus status =
246 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
247
248 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
249 EXPECT_TRUE(ok);
250 EXPECT_EQ(junk, output_tag);
251 }
252
TEST(AlarmTest,NegativeExpiry)253 TEST(AlarmTest, NegativeExpiry) {
254 CompletionQueue cq;
255 void* junk = reinterpret_cast<void*>(1618033);
256 Alarm alarm;
257 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(-1), junk);
258
259 void* output_tag;
260 bool ok;
261 const CompletionQueue::NextStatus status =
262 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
263
264 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
265 EXPECT_TRUE(ok);
266 EXPECT_EQ(junk, output_tag);
267 }
268
269 // Infinite past or unix epoch should fire immediately.
TEST(AlarmTest,InfPastExpiry)270 TEST(AlarmTest, InfPastExpiry) {
271 CompletionQueue cq;
272 void* junk = reinterpret_cast<void*>(1618033);
273 Alarm alarm;
274 alarm.Set(&cq, gpr_inf_past(GPR_CLOCK_REALTIME), junk);
275
276 void* output_tag;
277 bool ok;
278 CompletionQueue::NextStatus status =
279 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
280
281 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
282 EXPECT_TRUE(ok);
283 EXPECT_EQ(junk, output_tag);
284
285 alarm.Set(&cq, std::chrono::system_clock::time_point(), junk);
286 status = cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
287
288 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
289 EXPECT_TRUE(ok);
290 EXPECT_EQ(junk, output_tag);
291 }
292
TEST(AlarmTest,Cancellation)293 TEST(AlarmTest, Cancellation) {
294 CompletionQueue cq;
295 void* junk = reinterpret_cast<void*>(1618033);
296 Alarm alarm;
297 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
298 alarm.Cancel();
299
300 void* output_tag;
301 bool ok;
302 const CompletionQueue::NextStatus status =
303 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
304
305 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
306 EXPECT_FALSE(ok);
307 EXPECT_EQ(junk, output_tag);
308 }
309
TEST(AlarmTest,CancellationMultiSet)310 TEST(AlarmTest, CancellationMultiSet) {
311 // Tests the cancellation and re-Set paths together.
312 CompletionQueue cq;
313 void* junk = reinterpret_cast<void*>(1618033);
314 Alarm alarm;
315 // First iteration
316 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(5), junk);
317 alarm.Cancel();
318 void* output_tag;
319 bool ok;
320 CompletionQueue::NextStatus status =
321 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
322 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
323 EXPECT_FALSE(ok);
324 EXPECT_EQ(junk, output_tag);
325 // Second iteration
326 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(5), junk);
327 alarm.Cancel();
328 status = cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
329 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
330 EXPECT_FALSE(ok);
331 EXPECT_EQ(junk, output_tag);
332 }
333
TEST(AlarmTest,CallbackCancellation)334 TEST(AlarmTest, CallbackCancellation) {
335 Alarm alarm;
336
337 auto c = std::make_shared<Completion>();
338 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(10),
339 [c](bool ok) {
340 EXPECT_FALSE(ok);
341 std::lock_guard<std::mutex> l(c->mu);
342 c->completed = true;
343 c->cv.notify_one();
344 });
345 alarm.Cancel();
346
347 std::unique_lock<std::mutex> l(c->mu);
348 EXPECT_TRUE(c->cv.wait_until(
349 l, std::chrono::system_clock::now() + std::chrono::seconds(1),
350 [c] { return c->completed; }));
351 }
352
TEST(AlarmTest,CallbackCancellationMultiSet)353 TEST(AlarmTest, CallbackCancellationMultiSet) {
354 // Tests the cancellation and re-Set paths.
355 Alarm alarm;
356 // First iteration
357 {
358 grpc_core::Notification notification;
359 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(10),
360 [¬ification](bool ok) {
361 EXPECT_FALSE(ok);
362 notification.Notify();
363 });
364 alarm.Cancel();
365 notification.WaitForNotification();
366 }
367 // First iteration
368 {
369 grpc_core::Notification notification;
370 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(10),
371 [¬ification](bool ok) {
372 EXPECT_FALSE(ok);
373 notification.Notify();
374 });
375 alarm.Cancel();
376 notification.WaitForNotification();
377 }
378 }
379
TEST(AlarmTest,CallbackCancellationLocked)380 TEST(AlarmTest, CallbackCancellationLocked) {
381 Alarm alarm;
382
383 auto c = std::make_shared<Completion>();
384 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(10),
385 [c](bool ok) {
386 EXPECT_FALSE(ok);
387 std::lock_guard<std::mutex> l(c->mu);
388 c->completed = true;
389 c->cv.notify_one();
390 });
391 std::unique_lock<std::mutex> l(c->mu);
392 alarm.Cancel();
393
394 EXPECT_TRUE(c->cv.wait_until(
395 l, std::chrono::system_clock::now() + std::chrono::seconds(1),
396 [c] { return c->completed; }));
397 }
398
TEST(AlarmTest,SetDestruction)399 TEST(AlarmTest, SetDestruction) {
400 CompletionQueue cq;
401 void* junk = reinterpret_cast<void*>(1618033);
402 {
403 Alarm alarm;
404 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
405 }
406
407 void* output_tag;
408 bool ok;
409 const CompletionQueue::NextStatus status =
410 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
411
412 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
413 EXPECT_FALSE(ok);
414 EXPECT_EQ(junk, output_tag);
415 }
416
TEST(AlarmTest,CallbackSetDestruction)417 TEST(AlarmTest, CallbackSetDestruction) {
418 auto c = std::make_shared<Completion>();
419 {
420 Alarm alarm;
421 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(10),
422 [c](bool ok) {
423 EXPECT_FALSE(ok);
424 std::lock_guard<std::mutex> l(c->mu);
425 c->completed = true;
426 c->cv.notify_one();
427 });
428 }
429
430 std::unique_lock<std::mutex> l(c->mu);
431 EXPECT_TRUE(c->cv.wait_until(
432 l, std::chrono::system_clock::now() + std::chrono::seconds(1),
433 [c] { return c->completed; }));
434 }
435
TEST(AlarmTest,UnsetDestruction)436 TEST(AlarmTest, UnsetDestruction) {
437 CompletionQueue cq;
438 Alarm alarm;
439 }
440
TEST(AlarmTest,CallbackSetInCallback)441 TEST(AlarmTest, CallbackSetInCallback) {
442 Completion c;
443 std::mutex alarm_mu;
444 Alarm alarm;
445 {
446 std::lock_guard<std::mutex> l(alarm_mu);
447 alarm.Set(std::chrono::system_clock::now() + std::chrono::seconds(1),
448 [&](bool ok) {
449 EXPECT_TRUE(ok);
450 std::lock_guard<std::mutex> l(alarm_mu);
451 alarm.Set(
452 std::chrono::system_clock::now() + std::chrono::seconds(1),
453 [&](bool ok) {
454 EXPECT_TRUE(ok);
455 std::lock_guard<std::mutex> l(c.mu);
456 c.completed = true;
457 c.cv.notify_one();
458 });
459 });
460 }
461 std::unique_lock<std::mutex> l(c.mu);
462 c.cv.wait(l, [&] { return c.completed; });
463 }
464
465 } // namespace
466 } // namespace grpc
467
main(int argc,char ** argv)468 int main(int argc, char** argv) {
469 grpc::testing::TestEnvironment env(&argc, argv);
470 ::testing::InitGoogleTest(&argc, argv);
471 return RUN_ALL_TESTS();
472 }
473