• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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               [&notification](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               [&notification](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