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 "test/core/transport/test_suite/test.h"
16
17 #include <initializer_list>
18
19 #include "absl/random/random.h"
20
21 namespace grpc_core {
22
23 ///////////////////////////////////////////////////////////////////////////////
24 // TransportTestRegistry
25
Get()26 TransportTestRegistry& TransportTestRegistry::Get() {
27 static TransportTestRegistry* registry = new TransportTestRegistry();
28 return *registry;
29 }
30
RegisterTest(absl::string_view name,absl::AnyInvocable<TransportTest * (std::unique_ptr<TransportFixture>,const fuzzing_event_engine::Actions &,absl::BitGenRef)const> create)31 void TransportTestRegistry::RegisterTest(
32 absl::string_view name,
33 absl::AnyInvocable<TransportTest*(std::unique_ptr<TransportFixture>,
34 const fuzzing_event_engine::Actions&,
35 absl::BitGenRef) const>
36 create) {
37 if (absl::StartsWith(name, "DISABLED_")) return;
38 tests_.push_back({name, std::move(create)});
39 }
40
41 ///////////////////////////////////////////////////////////////////////////////
42 // TransportTest
43
RunTest()44 void TransportTest::RunTest() {
45 TestImpl();
46 EXPECT_EQ(pending_actions_.size(), 0)
47 << "There are still pending actions: did you forget to call "
48 "WaitForAllPendingWork()?";
49 transport_pair_.client.reset();
50 transport_pair_.server.reset();
51 event_engine_->TickUntilIdle();
52 event_engine_->UnsetGlobalHooks();
53 }
54
SetServerAcceptor()55 void TransportTest::SetServerAcceptor() {
56 transport_pair_.server->server_transport()->SetAcceptor(&acceptor_);
57 }
58
CreateCall()59 CallInitiator TransportTest::CreateCall() {
60 auto call = MakeCall(event_engine_.get(), Arena::Create(1024, &allocator_));
61 call.handler.SpawnInfallible("start-call", [this, handler = call.handler]() {
62 transport_pair_.client->client_transport()->StartCall(handler);
63 return Empty{};
64 });
65 return std::move(call.initiator);
66 }
67
TickUntilServerCall()68 CallHandler TransportTest::TickUntilServerCall() {
69 WatchDog watchdog(this);
70 for (;;) {
71 auto handler = acceptor_.PopHandler();
72 if (handler.has_value()) return std::move(*handler);
73 event_engine_->Tick();
74 }
75 }
76
WaitForAllPendingWork()77 void TransportTest::WaitForAllPendingWork() {
78 WatchDog watchdog(this);
79 while (!pending_actions_.empty()) {
80 if (pending_actions_.front()->IsDone()) {
81 pending_actions_.pop();
82 continue;
83 }
84 event_engine_->Tick();
85 }
86 }
87
Timeout()88 void TransportTest::Timeout() {
89 std::vector<std::string> lines;
90 lines.emplace_back("Timeout waiting for pending actions to complete");
91 while (!pending_actions_.empty()) {
92 auto action = std::move(pending_actions_.front());
93 pending_actions_.pop();
94 if (action->IsDone()) continue;
95 absl::string_view state_name =
96 transport_test_detail::ActionState::StateString(action->Get());
97 absl::string_view file_name = action->file();
98 auto pos = file_name.find_last_of('/');
99 if (pos != absl::string_view::npos) {
100 file_name = file_name.substr(pos + 1);
101 }
102 lines.emplace_back(absl::StrCat(" ", state_name, " ", action->name(), " [",
103 action->step(), "]: ", file_name, ":",
104 action->line()));
105 }
106 Crash(absl::StrJoin(lines, "\n"));
107 }
108
RandomString(int min_length,int max_length,absl::string_view character_set)109 std::string TransportTest::RandomString(int min_length, int max_length,
110 absl::string_view character_set) {
111 std::string out;
112 int length = absl::LogUniform<int>(rng_, min_length, max_length + 1);
113 for (int i = 0; i < length; ++i) {
114 out.push_back(
115 character_set[absl::Uniform<uint8_t>(rng_, 0, character_set.size())]);
116 }
117 return out;
118 }
119
RandomStringFrom(std::initializer_list<absl::string_view> choices)120 std::string TransportTest::RandomStringFrom(
121 std::initializer_list<absl::string_view> choices) {
122 size_t idx = absl::Uniform<size_t>(rng_, 0, choices.size());
123 auto it = choices.begin();
124 for (size_t i = 0; i < idx; ++i) ++it;
125 return std::string(*it);
126 }
127
RandomMetadataKey()128 std::string TransportTest::RandomMetadataKey() {
129 if (absl::Bernoulli(rng_, 0.1)) {
130 return RandomStringFrom({
131 ":path",
132 ":method",
133 ":status",
134 ":authority",
135 ":scheme",
136 });
137 }
138 std::string out;
139 do {
140 out = RandomString(1, 128, "abcdefghijklmnopqrstuvwxyz-_");
141 } while (absl::EndsWith(out, "-bin"));
142 return out;
143 }
144
RandomMetadataValue(absl::string_view key)145 std::string TransportTest::RandomMetadataValue(absl::string_view key) {
146 if (key == ":method") {
147 return RandomStringFrom({"GET", "POST", "PUT"});
148 }
149 if (key == ":status") {
150 return absl::StrCat(absl::Uniform<int>(rng_, 100, 600));
151 }
152 if (key == ":scheme") {
153 return RandomStringFrom({"http", "https"});
154 }
155 if (key == "te") {
156 return "trailers";
157 }
158 static const NoDestruct<std::string> kChars{[]() {
159 std::string out;
160 for (char c = 32; c < 127; c++) out.push_back(c);
161 return out;
162 }()};
163 return RandomString(0, 128, *kChars);
164 }
165
RandomMetadataBinaryKey()166 std::string TransportTest::RandomMetadataBinaryKey() {
167 return RandomString(1, 128, "abcdefghijklmnopqrstuvwxyz-_") + "-bin";
168 }
169
RandomMetadataBinaryValue()170 std::string TransportTest::RandomMetadataBinaryValue() {
171 static const NoDestruct<std::string> kChars{[]() {
172 std::string out;
173 for (int c = 0; c < 256; c++) {
174 out.push_back(static_cast<char>(static_cast<uint8_t>(c)));
175 }
176 return out;
177 }()};
178 return RandomString(0, 4096, *kChars);
179 }
180
181 std::vector<std::pair<std::string, std::string>>
RandomMetadata()182 TransportTest::RandomMetadata() {
183 size_t size = 0;
184 const size_t max_size = absl::LogUniform<size_t>(rng_, 64, 8000);
185 std::vector<std::pair<std::string, std::string>> out;
186 for (;;) {
187 std::string key;
188 std::string value;
189 if (absl::Bernoulli(rng_, 0.1)) {
190 key = RandomMetadataBinaryKey();
191 value = RandomMetadataBinaryValue();
192 } else {
193 key = RandomMetadataKey();
194 value = RandomMetadataValue(key);
195 }
196 bool include = true;
197 for (size_t i = 0; i < out.size(); ++i) {
198 if (out[i].first == key) {
199 include = false;
200 break;
201 }
202 }
203 if (!include) continue;
204 size_t this_size = 32 + key.size() + value.size();
205 if (size + this_size > max_size) {
206 if (out.empty()) continue;
207 break;
208 }
209 size += this_size;
210 out.emplace_back(std::move(key), std::move(value));
211 }
212 return out;
213 }
214
RandomMessage()215 std::string TransportTest::RandomMessage() {
216 static const NoDestruct<std::string> kChars{[]() {
217 std::string out;
218 for (int c = 0; c < 256; c++) {
219 out.push_back(static_cast<char>(static_cast<uint8_t>(c)));
220 }
221 return out;
222 }()};
223 return RandomString(0, 1024 * 1024, *kChars);
224 }
225
226 ///////////////////////////////////////////////////////////////////////////////
227 // TransportTest::Acceptor
228
CreateArena()229 Arena* TransportTest::Acceptor::CreateArena() {
230 return Arena::Create(1024, allocator_);
231 }
232
CreateCall(ClientMetadata &,Arena * arena)233 absl::StatusOr<CallInitiator> TransportTest::Acceptor::CreateCall(
234 ClientMetadata&, Arena* arena) {
235 auto call = MakeCall(event_engine_, arena);
236 handlers_.push(std::move(call.handler));
237 return std::move(call.initiator);
238 }
239
PopHandler()240 absl::optional<CallHandler> TransportTest::Acceptor::PopHandler() {
241 if (!handlers_.empty()) {
242 auto handler = std::move(handlers_.front());
243 handlers_.pop();
244 return handler;
245 }
246 return absl::nullopt;
247 }
248
249 ///////////////////////////////////////////////////////////////////////////////
250 // ActionState
251
252 namespace transport_test_detail {
253
ActionState(NameAndLocation name_and_location)254 ActionState::ActionState(NameAndLocation name_and_location)
255 : name_and_location_(name_and_location), state_(kNotCreated) {}
256
IsDone()257 bool ActionState::IsDone() {
258 switch (state_) {
259 case kNotCreated:
260 case kNotStarted:
261 case kStarted:
262 return false;
263 case kDone:
264 case kCancelled:
265 return true;
266 }
267 }
268
269 } // namespace transport_test_detail
270
271 } // namespace grpc_core
272