xref: /aosp_15_r20/external/grpc-grpc/test/core/promise/sleep_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2022 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/lib/promise/sleep.h"
16 
17 #include <chrono>
18 #include <cstddef>
19 #include <memory>
20 #include <utility>
21 #include <vector>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 
26 #include <grpc/grpc.h>
27 #include <grpc/support/log.h>
28 
29 #include "src/core/lib/event_engine/default_event_engine.h"
30 #include "src/core/lib/gprpp/notification.h"
31 #include "src/core/lib/gprpp/orphanable.h"
32 #include "src/core/lib/iomgr/exec_ctx.h"
33 #include "src/core/lib/promise/exec_ctx_wakeup_scheduler.h"
34 #include "src/core/lib/promise/race.h"
35 #include "test/core/event_engine/mock_event_engine.h"
36 #include "test/core/promise/test_wakeup_schedulers.h"
37 
38 using grpc_event_engine::experimental::EventEngine;
39 using grpc_event_engine::experimental::GetDefaultEventEngine;
40 using grpc_event_engine::experimental::MockEventEngine;
41 using testing::_;
42 using testing::DoAll;
43 using testing::Matcher;
44 using testing::Mock;
45 using testing::Return;
46 using testing::SaveArg;
47 using testing::StrictMock;
48 
49 namespace grpc_core {
50 namespace {
51 
TEST(Sleep,Zzzz)52 TEST(Sleep, Zzzz) {
53   ExecCtx exec_ctx;
54   Notification done;
55   Timestamp done_time = Timestamp::Now() + Duration::Seconds(1);
56   auto engine = GetDefaultEventEngine();
57   // Sleep for one second then set done to true.
58   auto activity = MakeActivity(
59       Sleep(done_time), InlineWakeupScheduler(),
60       [&done](absl::Status r) {
61         EXPECT_EQ(r, absl::OkStatus());
62         done.Notify();
63       },
64       engine.get());
65   done.WaitForNotification();
66   exec_ctx.InvalidateNow();
67   EXPECT_GE(Timestamp::Now(), done_time);
68 }
69 
TEST(Sleep,OverlyEagerEventEngine)70 TEST(Sleep, OverlyEagerEventEngine) {
71   StrictMock<MockEventEngine> mock_event_engine;
72 
73   ExecCtx exec_ctx;
74   bool done = false;
75   // Schedule a sleep for a very long time.
76   Timestamp done_time = Timestamp::Now() + Duration::Seconds(1e6);
77   EventEngine::Closure* wakeup = nullptr;
78   EXPECT_CALL(mock_event_engine, RunAfter(_, Matcher<EventEngine::Closure*>(_)))
79       .WillOnce(
80           DoAll(SaveArg<1>(&wakeup), Return(EventEngine::TaskHandle{42, 123})));
81   auto activity = MakeActivity(
82       Sleep(done_time), InlineWakeupScheduler(),
83       [&done](absl::Status r) {
84         EXPECT_EQ(r, absl::OkStatus());
85         done = true;
86       },
87       static_cast<EventEngine*>(&mock_event_engine));
88   Mock::VerifyAndClearExpectations(&mock_event_engine);
89   EXPECT_NE(wakeup, nullptr);
90   EXPECT_FALSE(done);
91   // Schedule the wakeup instantaneously - It won't have passed the scheduled
92   // time yet, but sleep should believe the EventEngine.
93   wakeup->Run();
94   EXPECT_TRUE(done);
95 }
96 
TEST(Sleep,AlreadyDone)97 TEST(Sleep, AlreadyDone) {
98   ExecCtx exec_ctx;
99   Notification done;
100   Timestamp done_time = Timestamp::Now() - Duration::Seconds(1);
101   auto engine = GetDefaultEventEngine();
102   // Sleep for no time at all then set done to true.
103   auto activity = MakeActivity(
104       Sleep(done_time), InlineWakeupScheduler(),
105       [&done](absl::Status r) {
106         EXPECT_EQ(r, absl::OkStatus());
107         done.Notify();
108       },
109       engine.get());
110   done.WaitForNotification();
111 }
112 
TEST(Sleep,Cancel)113 TEST(Sleep, Cancel) {
114   ExecCtx exec_ctx;
115   Notification done;
116   Timestamp done_time = Timestamp::Now() + Duration::Seconds(1);
117   auto engine = GetDefaultEventEngine();
118   // Sleep for one second but race it to complete immediately
119   auto activity = MakeActivity(
120       Race(Sleep(done_time), [] { return absl::CancelledError(); }),
121       InlineWakeupScheduler(),
122       [&done](absl::Status r) {
123         EXPECT_EQ(r, absl::CancelledError());
124         done.Notify();
125       },
126       engine.get());
127   done.WaitForNotification();
128   exec_ctx.InvalidateNow();
129   EXPECT_LT(Timestamp::Now(), done_time);
130 }
131 
TEST(Sleep,MoveSemantics)132 TEST(Sleep, MoveSemantics) {
133   // ASAN should help determine if there are any memory leaks here
134   ExecCtx exec_ctx;
135   Notification done;
136   Timestamp done_time = Timestamp::Now() + Duration::Milliseconds(111);
137   Sleep donor(done_time);
138   Sleep sleeper = std::move(donor);
139   auto engine = GetDefaultEventEngine();
140   auto activity = MakeActivity(
141       std::move(sleeper), InlineWakeupScheduler(),
142       [&done](absl::Status r) {
143         EXPECT_EQ(r, absl::OkStatus());
144         done.Notify();
145       },
146       engine.get());
147   done.WaitForNotification();
148   exec_ctx.InvalidateNow();
149   EXPECT_GE(Timestamp::Now(), done_time);
150 }
151 
TEST(Sleep,StressTest)152 TEST(Sleep, StressTest) {
153   // Kick off a bunch sleeps for one second.
154   static const int kNumActivities = 100000;
155   ExecCtx exec_ctx;
156   std::vector<std::shared_ptr<Notification>> notifications;
157   std::vector<ActivityPtr> activities;
158   auto engine = GetDefaultEventEngine();
159   gpr_log(GPR_INFO, "Starting %d sleeps for 1sec", kNumActivities);
160   for (int i = 0; i < kNumActivities; i++) {
161     auto notification = std::make_shared<Notification>();
162     auto activity = MakeActivity(
163         Sleep(Timestamp::Now() + Duration::Seconds(1)),
164         ExecCtxWakeupScheduler(),
165         [notification](absl::Status /*r*/) { notification->Notify(); },
166         engine.get());
167     notifications.push_back(std::move(notification));
168     activities.push_back(std::move(activity));
169   }
170   gpr_log(GPR_INFO,
171           "Waiting for the first %d sleeps, whilst cancelling the other half",
172           kNumActivities / 2);
173   for (size_t i = 0; i < kNumActivities / 2; i++) {
174     notifications[i]->WaitForNotification();
175     activities[i].reset();
176     activities[i + kNumActivities / 2].reset();
177     exec_ctx.Flush();
178   }
179 }
180 
181 }  // namespace
182 }  // namespace grpc_core
183 
main(int argc,char ** argv)184 int main(int argc, char** argv) {
185   ::testing::InitGoogleTest(&argc, argv);
186   grpc_init();
187   int r = RUN_ALL_TESTS();
188   grpc_shutdown();
189   return r;
190 }
191