xref: /aosp_15_r20/external/grpc-grpc/test/core/transport/test_suite/test.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 #ifndef GRPC_TEST_CORE_TRANSPORT_TEST_SUITE_TEST_H
16 #define GRPC_TEST_CORE_TRANSPORT_TEST_SUITE_TEST_H
17 
18 #include <initializer_list>
19 #include <memory>
20 #include <queue>
21 
22 #include "absl/functional/any_invocable.h"
23 #include "absl/random/bit_gen_ref.h"
24 #include "absl/strings/string_view.h"
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 
28 #include "src/core/lib/gprpp/time.h"
29 #include "src/core/lib/iomgr/timer_manager.h"
30 #include "src/core/lib/promise/cancel_callback.h"
31 #include "src/core/lib/promise/promise.h"
32 #include "src/core/lib/resource_quota/resource_quota.h"
33 #include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h"
34 #include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h"
35 #include "test/core/transport/test_suite/fixture.h"
36 
37 namespace grpc_core {
38 
39 namespace transport_test_detail {
40 
41 struct NameAndLocation {
42   // NOLINTNEXTLINE
43   NameAndLocation(const char* name, SourceLocation location = {})
location_NameAndLocation44       : location_(location), name_(name) {}
NextNameAndLocation45   NameAndLocation Next() const {
46     return NameAndLocation(name_, location_, step_ + 1);
47   }
48 
locationNameAndLocation49   SourceLocation location() const { return location_; }
nameNameAndLocation50   absl::string_view name() const { return name_; }
stepNameAndLocation51   int step() const { return step_; }
52 
53  private:
NameAndLocationNameAndLocation54   NameAndLocation(absl::string_view name, SourceLocation location, int step)
55       : location_(location), name_(name), step_(step) {}
56   SourceLocation location_;
57   absl::string_view name_;
58   int step_ = 1;
59 };
60 
61 class ActionState {
62  public:
63   enum State : uint8_t {
64     kNotCreated,
65     kNotStarted,
66     kStarted,
67     kDone,
68     kCancelled,
69   };
70 
StateString(State state)71   static absl::string_view StateString(State state) {
72     switch (state) {
73       case kNotCreated:
74         return "��";
75       case kNotStarted:
76         return "⏰";
77       case kStarted:
78         return "��";
79       case kDone:
80         return "��";
81       case kCancelled:
82         return "��";
83     }
84   }
85 
86   explicit ActionState(NameAndLocation name_and_location);
87 
Get()88   State Get() const { return state_; }
Set(State state)89   void Set(State state) {
90     gpr_log(GPR_INFO, "%s",
91             absl::StrCat(StateString(state), " ", name(), " [", step(), "] ",
92                          file(), ":", line())
93                 .c_str());
94     state_ = state;
95   }
name_and_location()96   const NameAndLocation& name_and_location() const {
97     return name_and_location_;
98   }
location()99   SourceLocation location() const { return name_and_location().location(); }
file()100   const char* file() const { return location().file(); }
line()101   int line() const { return location().line(); }
name()102   absl::string_view name() const { return name_and_location().name(); }
step()103   int step() const { return name_and_location().step(); }
104   bool IsDone();
105 
106  private:
107   const NameAndLocation name_and_location_;
108   std::atomic<State> state_;
109 };
110 
111 using PromiseSpawner = std::function<void(absl::string_view, Promise<Empty>)>;
112 using ActionStateFactory =
113     absl::FunctionRef<std::shared_ptr<ActionState>(NameAndLocation)>;
114 
115 template <typename Context>
SpawnerForContext(Context context,grpc_event_engine::experimental::EventEngine * event_engine)116 PromiseSpawner SpawnerForContext(
117     Context context,
118     grpc_event_engine::experimental::EventEngine* event_engine) {
119   return [context = std::move(context), event_engine](
120              absl::string_view name, Promise<Empty> promise) mutable {
121     // Pass new promises via event engine to allow fuzzers to explore
122     // reorderings of possibly interleaved spawns.
123     event_engine->Run([name, context = std::move(context),
124                        promise = std::move(promise)]() mutable {
125       context.SpawnInfallible(name, std::move(promise));
126     });
127   };
128 }
129 
130 template <typename Arg>
131 using NextSpawner = absl::AnyInvocable<void(Arg)>;
132 
133 template <typename R>
WrapPromiseAndNext(std::shared_ptr<ActionState> action_state,Promise<R> promise,NextSpawner<R> next)134 Promise<Empty> WrapPromiseAndNext(std::shared_ptr<ActionState> action_state,
135                                   Promise<R> promise, NextSpawner<R> next) {
136   return Promise<Empty>(OnCancel(
137       [action_state, promise = std::move(promise),
138        next = std::move(next)]() mutable -> Poll<Empty> {
139         action_state->Set(ActionState::kStarted);
140         auto r = promise();
141         if (auto* p = r.value_if_ready()) {
142           action_state->Set(ActionState::kDone);
143           next(std::move(*p));
144           return Empty{};
145         } else {
146           return Pending{};
147         }
148       },
149       [action_state]() { action_state->Set(ActionState::kCancelled); }));
150 }
151 
152 template <typename Arg>
WrapFollowUps(NameAndLocation,ActionStateFactory,PromiseSpawner)153 NextSpawner<Arg> WrapFollowUps(NameAndLocation, ActionStateFactory,
154                                PromiseSpawner) {
155   return [](Empty) {};
156 }
157 
158 template <typename Arg, typename FirstFollowUp, typename... FollowUps>
WrapFollowUps(NameAndLocation loc,ActionStateFactory action_state_factory,PromiseSpawner spawner,FirstFollowUp first,FollowUps...follow_ups)159 NextSpawner<Arg> WrapFollowUps(NameAndLocation loc,
160                                ActionStateFactory action_state_factory,
161                                PromiseSpawner spawner, FirstFollowUp first,
162                                FollowUps... follow_ups) {
163   using Factory = promise_detail::OncePromiseFactory<Arg, FirstFollowUp>;
164   using FactoryPromise = typename Factory::Promise;
165   using Result = typename FactoryPromise::Result;
166   auto action_state = action_state_factory(loc);
167   return [spawner, factory = Factory(std::move(first)),
168           next = WrapFollowUps<Result>(loc.Next(), action_state_factory,
169                                        spawner, std::move(follow_ups)...),
170           action_state = std::move(action_state),
171           name = loc.name()](Arg arg) mutable {
172     action_state->Set(ActionState::kNotStarted);
173     spawner(name,
174             WrapPromiseAndNext(std::move(action_state),
175                                Promise<Result>(factory.Make(std::move(arg))),
176                                std::move(next)));
177   };
178 }
179 
180 template <typename First, typename... FollowUps>
StartSeq(NameAndLocation loc,ActionStateFactory action_state_factory,PromiseSpawner spawner,First first,FollowUps...followups)181 void StartSeq(NameAndLocation loc, ActionStateFactory action_state_factory,
182               PromiseSpawner spawner, First first, FollowUps... followups) {
183   using Factory = promise_detail::OncePromiseFactory<void, First>;
184   using FactoryPromise = typename Factory::Promise;
185   using Result = typename FactoryPromise::Result;
186   auto action_state = action_state_factory(loc);
187   auto next = WrapFollowUps<Result>(loc.Next(), action_state_factory, spawner,
188                                     std::move(followups)...);
189   spawner(
190       loc.name(),
191       [spawner, first = Factory(std::move(first)), next = std::move(next),
192        action_state = std::move(action_state), name = loc.name()]() mutable {
193         action_state->Set(ActionState::kNotStarted);
194         spawner(name, WrapPromiseAndNext(std::move(action_state),
195                                          Promise<Result>(first.Make()),
196                                          std::move(next)));
197         return Empty{};
198       });
199 }
200 
201 };  // namespace transport_test_detail
202 
203 class TransportTest : public ::testing::Test {
204  public:
205   void RunTest();
206 
207  protected:
TransportTest(std::unique_ptr<TransportFixture> fixture,const fuzzing_event_engine::Actions & actions,absl::BitGenRef rng)208   TransportTest(std::unique_ptr<TransportFixture> fixture,
209                 const fuzzing_event_engine::Actions& actions,
210                 absl::BitGenRef rng)
211       : event_engine_(std::make_shared<
212                       grpc_event_engine::experimental::FuzzingEventEngine>(
213             []() {
214               grpc_timer_manager_set_threading(false);
215               grpc_event_engine::experimental::FuzzingEventEngine::Options
216                   options;
217               return options;
218             }(),
219             actions)),
220         fixture_(std::move(fixture)),
221         rng_(rng) {}
222 
223   void SetServerAcceptor();
224   CallInitiator CreateCall();
225 
226   std::string RandomString(int min_length, int max_length,
227                            absl::string_view character_set);
228   std::string RandomStringFrom(
229       std::initializer_list<absl::string_view> choices);
230   std::string RandomMetadataKey();
231   std::string RandomMetadataValue(absl::string_view key);
232   std::string RandomMetadataBinaryKey();
233   std::string RandomMetadataBinaryValue();
234   std::vector<std::pair<std::string, std::string>> RandomMetadata();
235   std::string RandomMessage();
rng()236   absl::BitGenRef rng() { return rng_; }
237 
238   CallHandler TickUntilServerCall();
239   void WaitForAllPendingWork();
240 
241   // Alternative for Seq for test driver code.
242   // Registers each step so that WaitForAllPendingWork() can report progress,
243   // and wait for completion... AND generate good failure messages when a
244   // sequence doesn't complete in a timely manner.
245   template <typename Context, typename... Actions>
SpawnTestSeq(Context context,transport_test_detail::NameAndLocation name_and_location,Actions...actions)246   void SpawnTestSeq(Context context,
247                     transport_test_detail::NameAndLocation name_and_location,
248                     Actions... actions) {
249     transport_test_detail::StartSeq(
250         name_and_location,
251         [this](transport_test_detail::NameAndLocation name_and_location) {
252           auto action = std::make_shared<transport_test_detail::ActionState>(
253               name_and_location);
254           pending_actions_.push(action);
255           return action;
256         },
257         transport_test_detail::SpawnerForContext(std::move(context),
258                                                  event_engine_.get()),
259         std::move(actions)...);
260   }
261 
262  private:
263   virtual void TestImpl() = 0;
264 
265   void Timeout();
266 
267   class Acceptor final : public ServerTransport::Acceptor {
268    public:
Acceptor(grpc_event_engine::experimental::EventEngine * event_engine,MemoryAllocator * allocator)269     Acceptor(grpc_event_engine::experimental::EventEngine* event_engine,
270              MemoryAllocator* allocator)
271         : event_engine_(event_engine), allocator_(allocator) {}
272 
273     Arena* CreateArena() override;
274     absl::StatusOr<CallInitiator> CreateCall(
275         ClientMetadata& client_initial_metadata, Arena* arena) override;
276     absl::optional<CallHandler> PopHandler();
277 
278    private:
279     std::queue<CallHandler> handlers_;
280     grpc_event_engine::experimental::EventEngine* const event_engine_;
281     MemoryAllocator* const allocator_;
282   };
283 
284   class WatchDog {
285    public:
WatchDog(TransportTest * test)286     explicit WatchDog(TransportTest* test) : test_(test) {}
~WatchDog()287     ~WatchDog() { test_->event_engine_->Cancel(timer_); }
288 
289    private:
290     TransportTest* const test_;
291     grpc_event_engine::experimental::EventEngine::TaskHandle const timer_{
292         test_->event_engine_->RunAfter(Duration::Minutes(5),
293                                        [this]() { test_->Timeout(); })};
294   };
295 
296   std::shared_ptr<grpc_event_engine::experimental::FuzzingEventEngine>
297       event_engine_{
298           std::make_shared<grpc_event_engine::experimental::FuzzingEventEngine>(
299               []() {
300                 grpc_timer_manager_set_threading(false);
301                 grpc_event_engine::experimental::FuzzingEventEngine::Options
302                     options;
303                 return options;
304               }(),
305               fuzzing_event_engine::Actions())};
306   std::unique_ptr<TransportFixture> fixture_;
307   MemoryAllocator allocator_ = MakeResourceQuota("test-quota")
308                                    ->memory_quota()
309                                    ->CreateMemoryAllocator("test-allocator");
310   Acceptor acceptor_{event_engine_.get(), &allocator_};
311   TransportFixture::ClientAndServerTransportPair transport_pair_ =
312       fixture_->CreateTransportPair(event_engine_);
313   std::queue<std::shared_ptr<transport_test_detail::ActionState>>
314       pending_actions_;
315   absl::BitGenRef rng_;
316 };
317 
318 class TransportTestRegistry {
319  public:
320   static TransportTestRegistry& Get();
321   void RegisterTest(
322       absl::string_view name,
323       absl::AnyInvocable<TransportTest*(std::unique_ptr<TransportFixture>,
324                                         const fuzzing_event_engine::Actions&,
325                                         absl::BitGenRef) const>
326           create);
327 
328   struct Test {
329     absl::string_view name;
330     absl::AnyInvocable<TransportTest*(std::unique_ptr<TransportFixture>,
331                                       const fuzzing_event_engine::Actions&,
332                                       absl::BitGenRef) const>
333         create;
334   };
335 
tests()336   const std::vector<Test>& tests() const { return tests_; }
337 
338  private:
339   std::vector<Test> tests_;
340 };
341 
342 }  // namespace grpc_core
343 
344 #define TRANSPORT_TEST(name)                                                 \
345   class TransportTest_##name : public grpc_core::TransportTest {             \
346    public:                                                                   \
347     using TransportTest::TransportTest;                                      \
348     void TestBody() override { RunTest(); }                                  \
349                                                                              \
350    private:                                                                  \
351     void TestImpl() override;                                                \
352     static grpc_core::TransportTest* Create(                                 \
353         std::unique_ptr<grpc_core::TransportFixture> fixture,                \
354         const fuzzing_event_engine::Actions& actions, absl::BitGenRef rng) { \
355       return new TransportTest_##name(std::move(fixture), actions, rng);     \
356     }                                                                        \
357     static int registered_;                                                  \
358   };                                                                         \
359   int TransportTest_##name::registered_ =                                    \
360       (grpc_core::TransportTestRegistry::Get().RegisterTest(#name, &Create), \
361        0);                                                                   \
362   void TransportTest_##name::TestImpl()
363 
364 #endif  // GRPC_TEST_CORE_TRANSPORT_TEST_SUITE_TEST_H
365