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