Skip to content

Commit 4829312

Browse files
authored
test(common): speed up context tests on Windows (#8226)
1 parent e288bda commit 4829312

1 file changed

Lines changed: 83 additions & 53 deletions

File tree

google/cloud/testing_util/validate_metadata.cc

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,87 @@ StatusOr<std::map<std::string, std::string> > ExtractParamsFromMethod(
150150
return res;
151151
}
152152

153+
/**
154+
* Cache the state required to implement `GetMetadata()`.
155+
*
156+
* The implementation of `GetMetadata()` requires substantial state, including
157+
* a gRPC server and completion queues. On Windows it is fairly expensive to
158+
* startup and shutdown these resources, we need to cache them so the tests run
159+
* fast.
160+
*/
161+
class GetMetadataState {
162+
public:
163+
GetMetadataState() {
164+
// Start the generic server.
165+
grpc::ServerBuilder builder;
166+
builder.RegisterAsyncGenericService(&generic_service_);
167+
srv_cq_ = builder.AddCompletionQueue();
168+
server_ = builder.BuildAndStart();
169+
}
170+
~GetMetadataState() {
171+
// Shut everything down.
172+
server_->Shutdown(std::chrono::system_clock::now());
173+
srv_cq_->Shutdown();
174+
cli_cq_.Shutdown();
175+
176+
// Drain completion queues.
177+
void* placeholder;
178+
bool ok;
179+
while (srv_cq_->Next(&placeholder, &ok))
180+
;
181+
while (cli_cq_.Next(&placeholder, &ok))
182+
;
183+
}
184+
185+
std::multimap<std::string, std::string> GetMetadata(
186+
grpc::ClientContext& context) {
187+
// Set the deadline to far in the future. If the deadline is in the past,
188+
// gRPC doesn't send the initial metadata at all (which makes sense, given
189+
// that the context is already expired). The `context` is destroyed by this
190+
// function anyway, so we're not making things worse by changing the
191+
// deadline.
192+
context.set_deadline(std::chrono::system_clock::now() +
193+
std::chrono::hours(24));
194+
195+
// Send some garbage with the supplied context.
196+
grpc::GenericStub generic_stub(
197+
server_->InProcessChannel(grpc::ChannelArguments()));
198+
199+
auto cli_stream =
200+
generic_stub.PrepareCall(&context, "made_up_method", &cli_cq_);
201+
cli_stream->StartCall(nullptr);
202+
bool ok;
203+
void* placeholder;
204+
cli_cq_.Next(&placeholder, &ok); // actually start the client call
205+
206+
// Receive the garbage with the supplied context.
207+
grpc::GenericServerContext server_context;
208+
grpc::GenericServerAsyncReaderWriter reader_writer(&server_context);
209+
generic_service_.RequestCall(&server_context, &reader_writer, srv_cq_.get(),
210+
srv_cq_.get(), nullptr);
211+
srv_cq_->Next(&placeholder, &ok); // actually receive the data
212+
213+
// Now we've got the data - save it before cleaning up.
214+
std::multimap<std::string, std::string> res;
215+
auto const& cli_md = server_context.client_metadata();
216+
std::transform(cli_md.begin(), cli_md.end(),
217+
std::inserter(res, res.begin()),
218+
[](std::pair<grpc::string_ref, grpc::string_ref> const& md) {
219+
return std::make_pair(
220+
std::string(md.first.data(), md.first.length()),
221+
std::string(md.second.data(), md.second.length()));
222+
});
223+
224+
return res;
225+
}
226+
227+
private:
228+
grpc::CompletionQueue cli_cq_;
229+
grpc::AsyncGenericService generic_service_;
230+
std::unique_ptr<grpc::ServerCompletionQueue> srv_cq_;
231+
std::unique_ptr<grpc::Server> server_;
232+
};
233+
153234
} // namespace
154235

155236
/**
@@ -226,59 +307,8 @@ Status IsContextMDValid(
226307

227308
std::multimap<std::string, std::string> GetMetadata(
228309
grpc::ClientContext& context) {
229-
// Set the deadline to far in the future. If the deadline is in the past, gRPC
230-
// doesn't send the initial metadata at all (which makes sense, given that the
231-
// context is already expired). The `context` is destroyed by this function
232-
// anyway, so we're not making things worse by changing the deadline.
233-
context.set_deadline(std::chrono::system_clock::now() +
234-
std::chrono::hours(24));
235-
236-
// Start the generic server.
237-
grpc::ServerBuilder builder;
238-
grpc::AsyncGenericService generic_service;
239-
builder.RegisterAsyncGenericService(&generic_service);
240-
auto srv_cq = builder.AddCompletionQueue();
241-
auto server = builder.BuildAndStart();
242-
243-
// Send some garbage with the supplied context.
244-
grpc::GenericStub generic_stub(
245-
server->InProcessChannel(grpc::ChannelArguments()));
246-
grpc::CompletionQueue cli_cq;
247-
auto cli_stream =
248-
generic_stub.PrepareCall(&context, "made_up_method", &cli_cq);
249-
cli_stream->StartCall(nullptr);
250-
bool ok;
251-
void* placeholder;
252-
cli_cq.Next(&placeholder, &ok); // actually start the client call
253-
254-
// Receive the garbage with the supplied context.
255-
grpc::GenericServerContext server_context;
256-
grpc::GenericServerAsyncReaderWriter reader_writer(&server_context);
257-
generic_service.RequestCall(&server_context, &reader_writer, srv_cq.get(),
258-
srv_cq.get(), nullptr);
259-
srv_cq->Next(&placeholder, &ok); // actually receive the data
260-
261-
// Now we've got the data - save it before cleaning up.
262-
std::multimap<std::string, std::string> res;
263-
auto const& cli_md = server_context.client_metadata();
264-
std::transform(cli_md.begin(), cli_md.end(), std::inserter(res, res.begin()),
265-
[](std::pair<grpc::string_ref, grpc::string_ref> const& md) {
266-
return std::make_pair(
267-
std::string(md.first.data(), md.first.length()),
268-
std::string(md.second.data(), md.second.length()));
269-
});
270-
271-
// Shut everything down.
272-
server->Shutdown(std::chrono::system_clock::now());
273-
srv_cq->Shutdown();
274-
cli_cq.Shutdown();
275-
// Drain completion queues.
276-
while (srv_cq->Next(&placeholder, &ok))
277-
;
278-
while (cli_cq.Next(&placeholder, &ok))
279-
;
280-
281-
return res;
310+
static auto* const kState = new GetMetadataState;
311+
return kState->GetMetadata(context);
282312
}
283313

284314
} // namespace testing_util

0 commit comments

Comments
 (0)