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