• 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 <condition_variable>
20 #include <memory>
21 #include <mutex>
22 #include <thread>
23 
24 #include <grpcpp/alarm.h>
25 #include <grpcpp/completion_queue.h>
26 
27 #include <gtest/gtest.h>
28 
29 #include "test/core/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.experimental().Set(
99       std::chrono::system_clock::now() + std::chrono::seconds(1), [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.experimental().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.experimental().Set(
134       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 
TEST(AlarmTest,Cancellation)270 TEST(AlarmTest, Cancellation) {
271   CompletionQueue cq;
272   void* junk = reinterpret_cast<void*>(1618033);
273   Alarm alarm;
274   alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
275   alarm.Cancel();
276 
277   void* output_tag;
278   bool ok;
279   const CompletionQueue::NextStatus status =
280       cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
281 
282   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
283   EXPECT_FALSE(ok);
284   EXPECT_EQ(junk, output_tag);
285 }
286 
TEST(AlarmTest,CallbackCancellation)287 TEST(AlarmTest, CallbackCancellation) {
288   Alarm alarm;
289 
290   auto c = std::make_shared<Completion>();
291   alarm.experimental().Set(
292       std::chrono::system_clock::now() + std::chrono::seconds(10),
293       [c](bool ok) {
294         EXPECT_FALSE(ok);
295         std::lock_guard<std::mutex> l(c->mu);
296         c->completed = true;
297         c->cv.notify_one();
298       });
299   alarm.Cancel();
300 
301   std::unique_lock<std::mutex> l(c->mu);
302   EXPECT_TRUE(c->cv.wait_until(
303       l, std::chrono::system_clock::now() + std::chrono::seconds(1),
304       [c] { return c->completed; }));
305 }
306 
TEST(AlarmTest,CallbackCancellationLocked)307 TEST(AlarmTest, CallbackCancellationLocked) {
308   Alarm alarm;
309 
310   auto c = std::make_shared<Completion>();
311   alarm.experimental().Set(
312       std::chrono::system_clock::now() + std::chrono::seconds(10),
313       [c](bool ok) {
314         EXPECT_FALSE(ok);
315         std::lock_guard<std::mutex> l(c->mu);
316         c->completed = true;
317         c->cv.notify_one();
318       });
319   std::unique_lock<std::mutex> l(c->mu);
320   alarm.Cancel();
321 
322   EXPECT_TRUE(c->cv.wait_until(
323       l, std::chrono::system_clock::now() + std::chrono::seconds(1),
324       [c] { return c->completed; }));
325 }
326 
TEST(AlarmTest,SetDestruction)327 TEST(AlarmTest, SetDestruction) {
328   CompletionQueue cq;
329   void* junk = reinterpret_cast<void*>(1618033);
330   {
331     Alarm alarm;
332     alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
333   }
334 
335   void* output_tag;
336   bool ok;
337   const CompletionQueue::NextStatus status =
338       cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
339 
340   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
341   EXPECT_FALSE(ok);
342   EXPECT_EQ(junk, output_tag);
343 }
344 
TEST(AlarmTest,CallbackSetDestruction)345 TEST(AlarmTest, CallbackSetDestruction) {
346   auto c = std::make_shared<Completion>();
347   {
348     Alarm alarm;
349     alarm.experimental().Set(
350         std::chrono::system_clock::now() + std::chrono::seconds(10),
351         [c](bool ok) {
352           EXPECT_FALSE(ok);
353           std::lock_guard<std::mutex> l(c->mu);
354           c->completed = true;
355           c->cv.notify_one();
356         });
357   }
358 
359   std::unique_lock<std::mutex> l(c->mu);
360   EXPECT_TRUE(c->cv.wait_until(
361       l, std::chrono::system_clock::now() + std::chrono::seconds(1),
362       [c] { return c->completed; }));
363 }
364 
TEST(AlarmTest,UnsetDestruction)365 TEST(AlarmTest, UnsetDestruction) {
366   CompletionQueue cq;
367   Alarm alarm;
368 }
369 
370 }  // namespace
371 }  // namespace grpc
372 
main(int argc,char ** argv)373 int main(int argc, char** argv) {
374   grpc::testing::TestEnvironment env(argc, argv);
375   ::testing::InitGoogleTest(&argc, argv);
376   return RUN_ALL_TESTS();
377 }
378