xref: /aosp_15_r20/external/grpc-grpc/test/cpp/common/alarm_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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               [&notification](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               [&notification](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