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
50 struct Completion {
51 bool completed = false;
52 std::mutex mu;
53 std::condition_variable cv;
54 };
55
TEST(AlarmTest,CallbackRegularExpiry)56 TEST(AlarmTest, CallbackRegularExpiry) {
57 Alarm alarm;
58
59 auto c = std::make_shared<Completion>();
60 alarm.experimental().Set(
61 std::chrono::system_clock::now() + std::chrono::seconds(1), [c](bool ok) {
62 EXPECT_TRUE(ok);
63 std::lock_guard<std::mutex> l(c->mu);
64 c->completed = true;
65 c->cv.notify_one();
66 });
67
68 std::unique_lock<std::mutex> l(c->mu);
69 EXPECT_TRUE(c->cv.wait_until(
70 l, std::chrono::system_clock::now() + std::chrono::seconds(10),
71 [c] { return c->completed; }));
72 }
73
TEST(AlarmTest,CallbackZeroExpiry)74 TEST(AlarmTest, CallbackZeroExpiry) {
75 Alarm alarm;
76
77 auto c = std::make_shared<Completion>();
78 alarm.experimental().Set(grpc_timeout_seconds_to_deadline(0), [c](bool ok) {
79 EXPECT_TRUE(ok);
80 std::lock_guard<std::mutex> l(c->mu);
81 c->completed = true;
82 c->cv.notify_one();
83 });
84
85 std::unique_lock<std::mutex> l(c->mu);
86 EXPECT_TRUE(c->cv.wait_until(
87 l, std::chrono::system_clock::now() + std::chrono::seconds(10),
88 [c] { return c->completed; }));
89 }
90
TEST(AlarmTest,CallbackNegativeExpiry)91 TEST(AlarmTest, CallbackNegativeExpiry) {
92 Alarm alarm;
93
94 auto c = std::make_shared<Completion>();
95 alarm.experimental().Set(
96 std::chrono::system_clock::now() + std::chrono::seconds(-1),
97 [c](bool ok) {
98 EXPECT_TRUE(ok);
99 std::lock_guard<std::mutex> l(c->mu);
100 c->completed = true;
101 c->cv.notify_one();
102 });
103
104 std::unique_lock<std::mutex> l(c->mu);
105 EXPECT_TRUE(c->cv.wait_until(
106 l, std::chrono::system_clock::now() + std::chrono::seconds(10),
107 [c] { return c->completed; }));
108 }
109
TEST(AlarmTest,MultithreadedRegularExpiry)110 TEST(AlarmTest, MultithreadedRegularExpiry) {
111 CompletionQueue cq;
112 void* junk = reinterpret_cast<void*>(1618033);
113 void* output_tag;
114 bool ok;
115 CompletionQueue::NextStatus status;
116 Alarm alarm;
117
118 std::thread t1([&alarm, &cq, &junk] {
119 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
120 });
121
122 std::thread t2([&cq, &ok, &output_tag, &status] {
123 status =
124 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
125 });
126
127 t1.join();
128 t2.join();
129 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
130 EXPECT_TRUE(ok);
131 EXPECT_EQ(junk, output_tag);
132 }
133
TEST(AlarmTest,DeprecatedRegularExpiry)134 TEST(AlarmTest, DeprecatedRegularExpiry) {
135 CompletionQueue cq;
136 void* junk = reinterpret_cast<void*>(1618033);
137 Alarm alarm(&cq, grpc_timeout_seconds_to_deadline(1), junk);
138
139 void* output_tag;
140 bool ok;
141 const CompletionQueue::NextStatus status =
142 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
143
144 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
145 EXPECT_TRUE(ok);
146 EXPECT_EQ(junk, output_tag);
147 }
148
TEST(AlarmTest,MoveConstructor)149 TEST(AlarmTest, MoveConstructor) {
150 CompletionQueue cq;
151 void* junk = reinterpret_cast<void*>(1618033);
152 Alarm first;
153 first.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
154 Alarm second(std::move(first));
155 void* output_tag;
156 bool ok;
157 const CompletionQueue::NextStatus status =
158 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
159 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
160 EXPECT_TRUE(ok);
161 EXPECT_EQ(junk, output_tag);
162 }
163
TEST(AlarmTest,MoveAssignment)164 TEST(AlarmTest, MoveAssignment) {
165 CompletionQueue cq;
166 void* junk = reinterpret_cast<void*>(1618033);
167 Alarm first;
168 first.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
169 Alarm second(std::move(first));
170 first = std::move(second);
171
172 void* output_tag;
173 bool ok;
174 const CompletionQueue::NextStatus status =
175 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
176
177 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
178 EXPECT_TRUE(ok);
179 EXPECT_EQ(junk, output_tag);
180 }
181
TEST(AlarmTest,RegularExpiryChrono)182 TEST(AlarmTest, RegularExpiryChrono) {
183 CompletionQueue cq;
184 void* junk = reinterpret_cast<void*>(1618033);
185 std::chrono::system_clock::time_point one_sec_deadline =
186 std::chrono::system_clock::now() + std::chrono::seconds(1);
187 Alarm alarm;
188 alarm.Set(&cq, one_sec_deadline, junk);
189
190 void* output_tag;
191 bool ok;
192 const CompletionQueue::NextStatus status =
193 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
194
195 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
196 EXPECT_TRUE(ok);
197 EXPECT_EQ(junk, output_tag);
198 }
199
TEST(AlarmTest,ZeroExpiry)200 TEST(AlarmTest, ZeroExpiry) {
201 CompletionQueue cq;
202 void* junk = reinterpret_cast<void*>(1618033);
203 Alarm alarm;
204 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(0), junk);
205
206 void* output_tag;
207 bool ok;
208 const CompletionQueue::NextStatus status =
209 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
210
211 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
212 EXPECT_TRUE(ok);
213 EXPECT_EQ(junk, output_tag);
214 }
215
TEST(AlarmTest,NegativeExpiry)216 TEST(AlarmTest, NegativeExpiry) {
217 CompletionQueue cq;
218 void* junk = reinterpret_cast<void*>(1618033);
219 Alarm alarm;
220 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(-1), junk);
221
222 void* output_tag;
223 bool ok;
224 const CompletionQueue::NextStatus status =
225 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
226
227 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
228 EXPECT_TRUE(ok);
229 EXPECT_EQ(junk, output_tag);
230 }
231
TEST(AlarmTest,Cancellation)232 TEST(AlarmTest, Cancellation) {
233 CompletionQueue cq;
234 void* junk = reinterpret_cast<void*>(1618033);
235 Alarm alarm;
236 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
237 alarm.Cancel();
238
239 void* output_tag;
240 bool ok;
241 const CompletionQueue::NextStatus status =
242 cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
243
244 EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
245 EXPECT_FALSE(ok);
246 EXPECT_EQ(junk, output_tag);
247 }
248
TEST(AlarmTest,CallbackCancellation)249 TEST(AlarmTest, CallbackCancellation) {
250 Alarm alarm;
251
252 auto c = std::make_shared<Completion>();
253 alarm.experimental().Set(
254 std::chrono::system_clock::now() + std::chrono::seconds(10),
255 [c](bool ok) {
256 EXPECT_FALSE(ok);
257 std::lock_guard<std::mutex> l(c->mu);
258 c->completed = true;
259 c->cv.notify_one();
260 });
261 alarm.Cancel();
262
263 std::unique_lock<std::mutex> l(c->mu);
264 EXPECT_TRUE(c->cv.wait_until(
265 l, std::chrono::system_clock::now() + std::chrono::seconds(1),
266 [c] { return c->completed; }));
267 }
268
TEST(AlarmTest,SetDestruction)269 TEST(AlarmTest, SetDestruction) {
270 CompletionQueue cq;
271 void* junk = reinterpret_cast<void*>(1618033);
272 {
273 Alarm alarm;
274 alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
275 }
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,CallbackSetDestruction)287 TEST(AlarmTest, CallbackSetDestruction) {
288 auto c = std::make_shared<Completion>();
289 {
290 Alarm alarm;
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 }
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,UnsetDestruction)307 TEST(AlarmTest, UnsetDestruction) {
308 CompletionQueue cq;
309 Alarm alarm;
310 }
311
312 } // namespace
313 } // namespace grpc
314
main(int argc,char ** argv)315 int main(int argc, char** argv) {
316 grpc_test_init(argc, argv);
317 ::testing::InitGoogleTest(&argc, argv);
318 return RUN_ALL_TESTS();
319 }
320