1 // Copyright 2023 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/ext/transport/chttp2/transport/ping_callbacks.h"
16
17 #include <chrono>
18
19 #include "absl/random/random.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "src/core/util/crash.h"
23 #include "test/core/event_engine/mock_event_engine.h"
24
25 using grpc_event_engine::experimental::EventEngine;
26 using grpc_event_engine::experimental::MockEventEngine;
27 using testing::_;
28 using testing::Matcher;
29 using testing::Return;
30 using testing::StrictMock;
31
32 namespace grpc_core {
33 namespace {
34
TEST(PingCallbacksTest,RequestPingRequestsPing)35 TEST(PingCallbacksTest, RequestPingRequestsPing) {
36 Chttp2PingCallbacks callbacks;
37 EXPECT_FALSE(callbacks.ping_requested());
38 callbacks.RequestPing();
39 EXPECT_TRUE(callbacks.ping_requested());
40 }
41
TEST(PingCallbacksTest,OnPingRequestsPing)42 TEST(PingCallbacksTest, OnPingRequestsPing) {
43 Chttp2PingCallbacks callbacks;
44 EXPECT_FALSE(callbacks.ping_requested());
45 callbacks.OnPing([] {}, [] {});
46 EXPECT_TRUE(callbacks.ping_requested());
47 }
48
TEST(PingCallbacksTest,OnPingAckRequestsPing)49 TEST(PingCallbacksTest, OnPingAckRequestsPing) {
50 Chttp2PingCallbacks callbacks;
51 EXPECT_FALSE(callbacks.ping_requested());
52 callbacks.OnPingAck([] {});
53 EXPECT_TRUE(callbacks.ping_requested());
54 }
55
TEST(PingCallbacksTest,PingAckBeforeTimerStarted)56 TEST(PingCallbacksTest, PingAckBeforeTimerStarted) {
57 StrictMock<MockEventEngine> event_engine;
58 absl::BitGen bitgen;
59 Chttp2PingCallbacks callbacks;
60 bool started = false;
61 bool acked = false;
62 EXPECT_FALSE(callbacks.ping_requested());
63 EXPECT_FALSE(callbacks.started_new_ping_without_setting_timeout());
64 // Request ping
65 callbacks.OnPing(
66 [&started] {
67 EXPECT_FALSE(started);
68 started = true;
69 },
70 [&acked] {
71 EXPECT_FALSE(acked);
72 acked = true;
73 });
74 EXPECT_TRUE(callbacks.ping_requested());
75 EXPECT_FALSE(callbacks.started_new_ping_without_setting_timeout());
76 EXPECT_EQ(callbacks.pings_inflight(), 0);
77 EXPECT_FALSE(started);
78 EXPECT_FALSE(acked);
79 auto id = callbacks.StartPing(bitgen);
80 EXPECT_TRUE(callbacks.started_new_ping_without_setting_timeout());
81 EXPECT_FALSE(callbacks.ping_requested());
82 EXPECT_EQ(callbacks.pings_inflight(), 1);
83 EXPECT_TRUE(started);
84 EXPECT_FALSE(acked);
85 callbacks.AckPing(id, &event_engine);
86 EXPECT_TRUE(callbacks.started_new_ping_without_setting_timeout());
87 EXPECT_FALSE(callbacks.ping_requested());
88 EXPECT_EQ(callbacks.pings_inflight(), 0);
89 EXPECT_TRUE(started);
90 EXPECT_TRUE(acked);
91 callbacks.OnPingTimeout(Duration::Milliseconds(1), &event_engine,
92 [] { Crash("should never reach here"); });
93 }
94
TEST(PingCallbacksTest,PingRoundtrips)95 TEST(PingCallbacksTest, PingRoundtrips) {
96 StrictMock<MockEventEngine> event_engine;
97 absl::BitGen bitgen;
98 Chttp2PingCallbacks callbacks;
99 bool started = false;
100 bool acked = false;
101 EXPECT_FALSE(callbacks.ping_requested());
102 // Request ping
103 callbacks.OnPing(
104 [&started] {
105 EXPECT_FALSE(started);
106 started = true;
107 },
108 [&acked] {
109 EXPECT_FALSE(acked);
110 acked = true;
111 });
112 EXPECT_TRUE(callbacks.ping_requested());
113 EXPECT_EQ(callbacks.pings_inflight(), 0);
114 EXPECT_FALSE(started);
115 EXPECT_FALSE(acked);
116 // Start ping should call the start methods, set a timeout, and clear the
117 // request
118 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
119 Matcher<absl::AnyInvocable<void()>>(_)))
120 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
121 auto id = callbacks.StartPing(bitgen);
122 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
123 [] { Crash("should not reach here"); });
124 EXPECT_FALSE(callbacks.ping_requested());
125 EXPECT_EQ(callbacks.pings_inflight(), 1);
126 EXPECT_TRUE(started);
127 EXPECT_FALSE(acked);
128 // Ack should cancel the timeout
129 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
130 .WillOnce(Return(true));
131 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
132 EXPECT_EQ(callbacks.pings_inflight(), 0);
133 EXPECT_FALSE(callbacks.ping_requested());
134 EXPECT_TRUE(started);
135 EXPECT_TRUE(acked);
136 }
137
TEST(PingCallbacksTest,PingRoundtripsWithInfiniteTimeout)138 TEST(PingCallbacksTest, PingRoundtripsWithInfiniteTimeout) {
139 StrictMock<MockEventEngine> event_engine;
140 absl::BitGen bitgen;
141 Chttp2PingCallbacks callbacks;
142 bool started = false;
143 bool acked = false;
144 EXPECT_FALSE(callbacks.ping_requested());
145 // Request ping
146 callbacks.OnPing(
147 [&started] {
148 EXPECT_FALSE(started);
149 started = true;
150 },
151 [&acked] {
152 EXPECT_FALSE(acked);
153 acked = true;
154 });
155 EXPECT_TRUE(callbacks.ping_requested());
156 EXPECT_EQ(callbacks.pings_inflight(), 0);
157 EXPECT_FALSE(started);
158 EXPECT_FALSE(acked);
159 auto id = callbacks.StartPing(bitgen);
160 EXPECT_FALSE(callbacks.ping_requested());
161 EXPECT_EQ(callbacks.pings_inflight(), 1);
162 EXPECT_TRUE(started);
163 EXPECT_FALSE(acked);
164 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
165 EXPECT_EQ(callbacks.pings_inflight(), 0);
166 EXPECT_FALSE(callbacks.ping_requested());
167 EXPECT_TRUE(started);
168 EXPECT_TRUE(acked);
169 }
170
TEST(PingCallbacksTest,InvalidPingIdFlagsError)171 TEST(PingCallbacksTest, InvalidPingIdFlagsError) {
172 StrictMock<MockEventEngine> event_engine;
173 Chttp2PingCallbacks callbacks;
174 EXPECT_FALSE(callbacks.AckPing(1234, &event_engine));
175 }
176
TEST(PingCallbacksTest,DuplicatePingIdFlagsError)177 TEST(PingCallbacksTest, DuplicatePingIdFlagsError) {
178 StrictMock<MockEventEngine> event_engine;
179 absl::BitGen bitgen;
180 Chttp2PingCallbacks callbacks;
181 bool started = false;
182 bool acked = false;
183 EXPECT_FALSE(callbacks.ping_requested());
184 callbacks.OnPing(
185 [&started] {
186 EXPECT_FALSE(started);
187 started = true;
188 },
189 [&acked] {
190 EXPECT_FALSE(acked);
191 acked = true;
192 });
193 EXPECT_TRUE(callbacks.ping_requested());
194 EXPECT_FALSE(started);
195 EXPECT_FALSE(acked);
196 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
197 Matcher<absl::AnyInvocable<void()>>(_)))
198 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
199 auto id = callbacks.StartPing(bitgen);
200 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
201 [] { Crash("should not reach here"); });
202 EXPECT_FALSE(callbacks.ping_requested());
203 EXPECT_TRUE(started);
204 EXPECT_FALSE(acked);
205 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
206 .WillOnce(Return(true));
207 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
208 EXPECT_FALSE(callbacks.ping_requested());
209 EXPECT_TRUE(started);
210 EXPECT_TRUE(acked);
211 // Second ping ack on the same id should fail
212 EXPECT_FALSE(callbacks.AckPing(id, &event_engine));
213 }
214
TEST(PingCallbacksTest,OnPingAckCanPiggybackInflightPings)215 TEST(PingCallbacksTest, OnPingAckCanPiggybackInflightPings) {
216 StrictMock<MockEventEngine> event_engine;
217 absl::BitGen bitgen;
218 Chttp2PingCallbacks callbacks;
219 bool started = false;
220 bool acked_first = false;
221 bool acked_second = false;
222 EXPECT_FALSE(callbacks.ping_requested());
223 callbacks.OnPing(
224 [&started] {
225 EXPECT_FALSE(started);
226 started = true;
227 },
228 [&acked_first] {
229 EXPECT_FALSE(acked_first);
230 acked_first = true;
231 });
232 EXPECT_TRUE(callbacks.ping_requested());
233 EXPECT_FALSE(started);
234 EXPECT_FALSE(acked_first);
235 EXPECT_FALSE(acked_second);
236 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
237 Matcher<absl::AnyInvocable<void()>>(_)))
238 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
239 auto id = callbacks.StartPing(bitgen);
240 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
241 [] { Crash("should not reach here"); });
242 EXPECT_FALSE(callbacks.ping_requested());
243 EXPECT_TRUE(started);
244 EXPECT_FALSE(acked_first);
245 EXPECT_FALSE(acked_second);
246 callbacks.OnPingAck([&acked_second] {
247 EXPECT_FALSE(acked_second);
248 acked_second = true;
249 });
250 EXPECT_FALSE(callbacks.ping_requested());
251 EXPECT_TRUE(started);
252 EXPECT_FALSE(acked_first);
253 EXPECT_FALSE(acked_second);
254 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
255 .WillOnce(Return(true));
256 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
257 EXPECT_FALSE(callbacks.ping_requested());
258 EXPECT_TRUE(started);
259 EXPECT_TRUE(acked_first);
260 EXPECT_TRUE(acked_second);
261 }
262
TEST(PingCallbacksTest,PingAckRoundtrips)263 TEST(PingCallbacksTest, PingAckRoundtrips) {
264 StrictMock<MockEventEngine> event_engine;
265 absl::BitGen bitgen;
266 Chttp2PingCallbacks callbacks;
267 bool acked = false;
268 EXPECT_FALSE(callbacks.ping_requested());
269 callbacks.OnPingAck([&acked] {
270 EXPECT_FALSE(acked);
271 acked = true;
272 });
273 EXPECT_TRUE(callbacks.ping_requested());
274 EXPECT_FALSE(acked);
275 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
276 Matcher<absl::AnyInvocable<void()>>(_)))
277 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
278 auto id = callbacks.StartPing(bitgen);
279 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
280 [] { Crash("should not reach here"); });
281 EXPECT_FALSE(callbacks.ping_requested());
282 EXPECT_FALSE(acked);
283 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
284 .WillOnce(Return(true));
285 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
286 EXPECT_FALSE(callbacks.ping_requested());
287 EXPECT_TRUE(acked);
288 }
289
TEST(PingCallbacksTest,MultiPingRoundtrips)290 TEST(PingCallbacksTest, MultiPingRoundtrips) {
291 StrictMock<MockEventEngine> event_engine;
292 absl::BitGen bitgen;
293 Chttp2PingCallbacks callbacks;
294 bool started1 = false;
295 bool acked1 = false;
296 bool started2 = false;
297 bool acked2 = false;
298 EXPECT_FALSE(callbacks.ping_requested());
299 callbacks.OnPing(
300 [&started1] {
301 EXPECT_FALSE(started1);
302 started1 = true;
303 },
304 [&acked1] {
305 EXPECT_FALSE(acked1);
306 acked1 = true;
307 });
308 EXPECT_TRUE(callbacks.ping_requested());
309 EXPECT_FALSE(started1);
310 EXPECT_FALSE(acked1);
311 EXPECT_FALSE(started2);
312 EXPECT_FALSE(acked2);
313 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
314 Matcher<absl::AnyInvocable<void()>>(_)))
315 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
316 auto id1 = callbacks.StartPing(bitgen);
317 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
318 [] { Crash("should not reach here"); });
319 EXPECT_FALSE(callbacks.ping_requested());
320 EXPECT_TRUE(started1);
321 EXPECT_FALSE(acked1);
322 EXPECT_FALSE(started2);
323 EXPECT_FALSE(acked2);
324 callbacks.OnPing(
325 [&started2] {
326 EXPECT_FALSE(started2);
327 started2 = true;
328 },
329 [&acked2] {
330 EXPECT_FALSE(acked2);
331 acked2 = true;
332 });
333 EXPECT_TRUE(callbacks.ping_requested());
334 EXPECT_TRUE(started1);
335 EXPECT_FALSE(acked1);
336 EXPECT_FALSE(started2);
337 EXPECT_FALSE(acked2);
338 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
339 Matcher<absl::AnyInvocable<void()>>(_)))
340 .WillOnce([]() { return EventEngine::TaskHandle{123, 789}; });
341 auto id2 = callbacks.StartPing(bitgen);
342 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
343 [] { Crash("should not reach here"); });
344 EXPECT_NE(id1, id2);
345 EXPECT_TRUE(started1);
346 EXPECT_FALSE(acked1);
347 EXPECT_TRUE(started2);
348 EXPECT_FALSE(acked2);
349 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
350 .WillOnce(Return(true));
351 EXPECT_TRUE(callbacks.AckPing(id1, &event_engine));
352 EXPECT_FALSE(callbacks.ping_requested());
353 EXPECT_TRUE(started1);
354 EXPECT_TRUE(acked1);
355 EXPECT_TRUE(started2);
356 EXPECT_FALSE(acked2);
357 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 789}))
358 .WillOnce(Return(true));
359 EXPECT_TRUE(callbacks.AckPing(id2, &event_engine));
360 EXPECT_FALSE(callbacks.ping_requested());
361 EXPECT_TRUE(started1);
362 EXPECT_TRUE(acked1);
363 EXPECT_TRUE(started2);
364 EXPECT_TRUE(acked2);
365 }
366
TEST(PingCallbacksTest,MultiPingRoundtripsWithOutOfOrderAcks)367 TEST(PingCallbacksTest, MultiPingRoundtripsWithOutOfOrderAcks) {
368 StrictMock<MockEventEngine> event_engine;
369 absl::BitGen bitgen;
370 Chttp2PingCallbacks callbacks;
371 bool started1 = false;
372 bool acked1 = false;
373 bool started2 = false;
374 bool acked2 = false;
375 EXPECT_FALSE(callbacks.ping_requested());
376 callbacks.OnPing(
377 [&started1] {
378 EXPECT_FALSE(started1);
379 started1 = true;
380 },
381 [&acked1] {
382 EXPECT_FALSE(acked1);
383 acked1 = true;
384 });
385 EXPECT_TRUE(callbacks.ping_requested());
386 EXPECT_FALSE(started1);
387 EXPECT_FALSE(acked1);
388 EXPECT_FALSE(started2);
389 EXPECT_FALSE(acked2);
390 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
391 Matcher<absl::AnyInvocable<void()>>(_)))
392 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
393 auto id1 = callbacks.StartPing(bitgen);
394 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
395 [] { Crash("should not reach here"); });
396 EXPECT_FALSE(callbacks.ping_requested());
397 EXPECT_TRUE(started1);
398 EXPECT_FALSE(acked1);
399 EXPECT_FALSE(started2);
400 EXPECT_FALSE(acked2);
401 callbacks.OnPing(
402 [&started2] {
403 EXPECT_FALSE(started2);
404 started2 = true;
405 },
406 [&acked2] {
407 EXPECT_FALSE(acked2);
408 acked2 = true;
409 });
410 EXPECT_TRUE(callbacks.ping_requested());
411 EXPECT_TRUE(started1);
412 EXPECT_FALSE(acked1);
413 EXPECT_FALSE(started2);
414 EXPECT_FALSE(acked2);
415 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
416 Matcher<absl::AnyInvocable<void()>>(_)))
417 .WillOnce([]() { return EventEngine::TaskHandle{123, 789}; });
418 auto id2 = callbacks.StartPing(bitgen);
419 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
420 [] { Crash("should not reach here"); });
421 EXPECT_NE(id1, id2);
422 EXPECT_TRUE(started1);
423 EXPECT_FALSE(acked1);
424 EXPECT_TRUE(started2);
425 EXPECT_FALSE(acked2);
426 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 789}))
427 .WillOnce(Return(true));
428 EXPECT_TRUE(callbacks.AckPing(id2, &event_engine));
429 EXPECT_FALSE(callbacks.ping_requested());
430 EXPECT_TRUE(started1);
431 EXPECT_FALSE(acked1);
432 EXPECT_TRUE(started2);
433 EXPECT_TRUE(acked2);
434 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
435 .WillOnce(Return(true));
436 EXPECT_TRUE(callbacks.AckPing(id1, &event_engine));
437 EXPECT_FALSE(callbacks.ping_requested());
438 EXPECT_TRUE(started1);
439 EXPECT_TRUE(acked1);
440 EXPECT_TRUE(started2);
441 EXPECT_TRUE(acked2);
442 }
443
TEST(PingCallbacksTest,CoalescedPingsRoundtrip)444 TEST(PingCallbacksTest, CoalescedPingsRoundtrip) {
445 StrictMock<MockEventEngine> event_engine;
446 absl::BitGen bitgen;
447 Chttp2PingCallbacks callbacks;
448 bool started1 = false;
449 bool acked1 = false;
450 bool started2 = false;
451 bool acked2 = false;
452 EXPECT_FALSE(callbacks.ping_requested());
453 callbacks.OnPing(
454 [&started1] {
455 EXPECT_FALSE(started1);
456 started1 = true;
457 },
458 [&acked1] {
459 EXPECT_FALSE(acked1);
460 acked1 = true;
461 });
462 callbacks.OnPing(
463 [&started2] {
464 EXPECT_FALSE(started2);
465 started2 = true;
466 },
467 [&acked2] {
468 EXPECT_FALSE(acked2);
469 acked2 = true;
470 });
471 EXPECT_TRUE(callbacks.ping_requested());
472 EXPECT_FALSE(started1);
473 EXPECT_FALSE(acked1);
474 EXPECT_FALSE(started2);
475 EXPECT_FALSE(acked2);
476 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
477 Matcher<absl::AnyInvocable<void()>>(_)))
478 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
479 auto id = callbacks.StartPing(bitgen);
480 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
481 [] { Crash("should not reach here"); });
482 EXPECT_FALSE(callbacks.ping_requested());
483 EXPECT_TRUE(started1);
484 EXPECT_FALSE(acked1);
485 EXPECT_TRUE(started2);
486 EXPECT_FALSE(acked2);
487 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
488 .WillOnce(Return(true));
489 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
490 EXPECT_FALSE(callbacks.ping_requested());
491 EXPECT_TRUE(started1);
492 EXPECT_TRUE(acked1);
493 EXPECT_TRUE(started2);
494 EXPECT_TRUE(acked2);
495 }
496
TEST(PingCallbacksTest,CancelAllCancelsCallbacks)497 TEST(PingCallbacksTest, CancelAllCancelsCallbacks) {
498 StrictMock<MockEventEngine> event_engine;
499 absl::BitGen bitgen;
500 Chttp2PingCallbacks callbacks;
501 bool started = false;
502 bool acked = false;
503 EXPECT_FALSE(callbacks.ping_requested());
504 callbacks.OnPing(
505 [&started] {
506 EXPECT_FALSE(started);
507 started = true;
508 },
509 [&acked] {
510 EXPECT_FALSE(acked);
511 acked = true;
512 });
513 EXPECT_TRUE(callbacks.ping_requested());
514 callbacks.CancelAll(&event_engine);
515 EXPECT_FALSE(started);
516 EXPECT_FALSE(acked);
517 EXPECT_FALSE(callbacks.ping_requested());
518 // Can still send a ping, no callback should be invoked
519 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
520 Matcher<absl::AnyInvocable<void()>>(_)))
521 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
522 auto id = callbacks.StartPing(bitgen);
523 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
524 [] { Crash("should not reach here"); });
525 EXPECT_FALSE(started);
526 EXPECT_FALSE(acked);
527 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
528 .WillOnce(Return(true));
529 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
530 EXPECT_FALSE(started);
531 EXPECT_FALSE(acked);
532 EXPECT_FALSE(callbacks.ping_requested());
533 }
534
TEST(PingCallbacksTest,CancelAllCancelsInflightPings)535 TEST(PingCallbacksTest, CancelAllCancelsInflightPings) {
536 StrictMock<MockEventEngine> event_engine;
537 absl::BitGen bitgen;
538 Chttp2PingCallbacks callbacks;
539 bool started = false;
540 bool acked = false;
541 EXPECT_FALSE(callbacks.ping_requested());
542 callbacks.OnPing(
543 [&started] {
544 EXPECT_FALSE(started);
545 started = true;
546 },
547 [&acked] {
548 EXPECT_FALSE(acked);
549 acked = true;
550 });
551 EXPECT_TRUE(callbacks.ping_requested());
552 EXPECT_FALSE(started);
553 EXPECT_FALSE(acked);
554 EXPECT_CALL(event_engine, RunAfter(EventEngine::Duration(Duration::Hours(24)),
555 Matcher<absl::AnyInvocable<void()>>(_)))
556 .WillOnce([]() { return EventEngine::TaskHandle{123, 456}; });
557 auto id = callbacks.StartPing(bitgen);
558 callbacks.OnPingTimeout(Duration::Hours(24), &event_engine,
559 [] { Crash("should not reach here"); });
560 EXPECT_FALSE(callbacks.ping_requested());
561 EXPECT_TRUE(started);
562 EXPECT_FALSE(acked);
563 EXPECT_CALL(event_engine, Cancel(EventEngine::TaskHandle{123, 456}))
564 .WillOnce(Return(true));
565 callbacks.CancelAll(&event_engine);
566 // Ensure Cancel call comes from CancelAll
567 ::testing::Mock::VerifyAndClearExpectations(&event_engine);
568 EXPECT_FALSE(acked);
569 EXPECT_FALSE(callbacks.ping_requested());
570 // Ping should still be valid, but no callback should be invoked
571 EXPECT_TRUE(callbacks.AckPing(id, &event_engine));
572 EXPECT_FALSE(acked);
573 EXPECT_FALSE(callbacks.ping_requested());
574 }
575
576 } // namespace
577 } // namespace grpc_core
578
main(int argc,char ** argv)579 int main(int argc, char** argv) {
580 ::testing::InitGoogleTest(&argc, argv);
581 return RUN_ALL_TESTS();
582 }
583