1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <inttypes.h>
20
21 #include <functional>
22 #include <memory>
23 #include <string>
24 #include <utility>
25 #include <vector>
26
27 #include "absl/status/status.h"
28 #include "absl/status/statusor.h"
29 #include "absl/strings/string_view.h"
30 #include "gtest/gtest.h"
31
32 #include <grpc/event_engine/event_engine.h>
33 #include <grpc/grpc.h>
34 #include <grpc/impl/channel_arg_names.h>
35 #include <grpc/support/alloc.h>
36 #include <grpc/support/atm.h>
37 #include <grpc/support/log.h>
38 #include <grpc/support/sync.h>
39 #include <grpc/support/time.h>
40
41 #include "src/core/lib/channel/channel_args.h"
42 #include "src/core/lib/config/core_configuration.h"
43 #include "src/core/lib/event_engine/default_event_engine.h"
44 #include "src/core/lib/experiments/experiments.h"
45 #include "src/core/lib/gprpp/debug_location.h"
46 #include "src/core/lib/gprpp/no_destruct.h"
47 #include "src/core/lib/gprpp/notification.h"
48 #include "src/core/lib/gprpp/orphanable.h"
49 #include "src/core/lib/gprpp/time.h"
50 #include "src/core/lib/gprpp/work_serializer.h"
51 #include "src/core/lib/iomgr/closure.h"
52 #include "src/core/lib/iomgr/error.h"
53 #include "src/core/lib/iomgr/exec_ctx.h"
54 #include "src/core/lib/iomgr/iomgr_fwd.h"
55 #include "src/core/lib/iomgr/pollset.h"
56 #include "src/core/lib/iomgr/pollset_set.h"
57 #include "src/core/lib/iomgr/resolve_address.h"
58 #include "src/core/lib/iomgr/resolved_address.h"
59 #include "src/core/lib/uri/uri_parser.h"
60 #include "src/core/resolver/dns/c_ares/grpc_ares_wrapper.h"
61 #include "src/core/resolver/endpoint_addresses.h"
62 #include "src/core/resolver/resolver.h"
63 #include "src/core/resolver/resolver_factory.h"
64 #include "src/core/resolver/resolver_registry.h"
65 #include "test/core/util/test_config.h"
66
67 using ::grpc_event_engine::experimental::GetDefaultEventEngine;
68
69 constexpr int kMinResolutionPeriodMs = 1000;
70
71 static std::shared_ptr<grpc_core::WorkSerializer>* g_work_serializer;
72
73 static grpc_ares_request* (*g_default_dns_lookup_ares)(
74 const char* dns_server, const char* name, const char* default_port,
75 grpc_pollset_set* interested_parties, grpc_closure* on_done,
76 std::unique_ptr<grpc_core::EndpointAddressesList>* addresses,
77 int query_timeout_ms);
78
79 // Counter incremented by TestDNSResolver::LookupHostname indicating the
80 // number of times a system-level resolution has happened.
81 static int g_resolution_count;
82
83 static struct iomgr_args {
84 gpr_event ev;
85 gpr_atm done_atm;
86 gpr_mu* mu;
87 grpc_pollset* pollset;
88 grpc_pollset_set* pollset_set;
89 } g_iomgr_args;
90
91 namespace {
92
93 class TestDNSResolver : public grpc_core::DNSResolver {
94 public:
TestDNSResolver(std::shared_ptr<grpc_core::DNSResolver> default_resolver)95 explicit TestDNSResolver(
96 std::shared_ptr<grpc_core::DNSResolver> default_resolver)
97 : default_resolver_(std::move(default_resolver)),
98 engine_(GetDefaultEventEngine()) {}
99 // Wrapper around default resolve_address in order to count the number of
100 // times we incur in a system-level name resolution.
LookupHostname(std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolved,absl::string_view name,absl::string_view default_port,grpc_core::Duration timeout,grpc_pollset_set * interested_parties,absl::string_view name_server)101 TaskHandle LookupHostname(
102 std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
103 on_resolved,
104 absl::string_view name, absl::string_view default_port,
105 grpc_core::Duration timeout, grpc_pollset_set* interested_parties,
106 absl::string_view name_server) override {
107 auto result = default_resolver_->LookupHostname(
108 std::move(on_resolved), name, default_port, timeout, interested_parties,
109 name_server);
110 ++g_resolution_count;
111 static grpc_core::Timestamp last_resolution_time =
112 grpc_core::Timestamp::ProcessEpoch();
113 if (last_resolution_time == grpc_core::Timestamp::ProcessEpoch()) {
114 last_resolution_time = grpc_core::Timestamp::FromTimespecRoundUp(
115 gpr_now(GPR_CLOCK_MONOTONIC));
116 } else {
117 auto now = grpc_core::Timestamp::FromTimespecRoundUp(
118 gpr_now(GPR_CLOCK_MONOTONIC));
119 EXPECT_GE(now - last_resolution_time,
120 grpc_core::Duration::Milliseconds(kMinResolutionPeriodMs));
121 last_resolution_time = now;
122 }
123 // For correct time diff comparisons, make sure that any subsequent calls
124 // to grpc_core::Timestamp::Now() on this thread don't return a time
125 // which is earlier than that returned by the call(s) to
126 // gpr_now(GPR_CLOCK_MONOTONIC) within this function. This is important
127 // because the resolver's last_resolution_timestamp_ will be taken from
128 // grpc_core::Timestamp::Now() right after this returns.
129 grpc_core::ExecCtx::Get()->InvalidateNow();
130 return result;
131 }
132
LookupHostnameBlocking(absl::string_view name,absl::string_view default_port)133 absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
134 absl::string_view name, absl::string_view default_port) override {
135 return default_resolver_->LookupHostnameBlocking(name, default_port);
136 }
137
LookupSRV(std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolved,absl::string_view,grpc_core::Duration,grpc_pollset_set *,absl::string_view)138 TaskHandle LookupSRV(
139 std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
140 on_resolved,
141 absl::string_view /* name */, grpc_core::Duration /* timeout */,
142 grpc_pollset_set* /* interested_parties */,
143 absl::string_view /* name_server */) override {
144 engine_->Run([on_resolved] {
145 grpc_core::ApplicationCallbackExecCtx app_exec_ctx;
146 grpc_core::ExecCtx exec_ctx;
147 on_resolved(absl::UnimplementedError(
148 "The Testing DNS resolver does not support looking up SRV records"));
149 });
150 return {-1, -1};
151 };
152
LookupTXT(std::function<void (absl::StatusOr<std::string>)> on_resolved,absl::string_view,grpc_core::Duration,grpc_pollset_set *,absl::string_view)153 TaskHandle LookupTXT(
154 std::function<void(absl::StatusOr<std::string>)> on_resolved,
155 absl::string_view /* name */, grpc_core::Duration /* timeout */,
156 grpc_pollset_set* /* interested_parties */,
157 absl::string_view /* name_server */) override {
158 // Not supported
159 engine_->Run([on_resolved] {
160 grpc_core::ApplicationCallbackExecCtx app_exec_ctx;
161 grpc_core::ExecCtx exec_ctx;
162 on_resolved(absl::UnimplementedError(
163 "The Testing DNS resolver does not support looking up TXT records"));
164 });
165 return {-1, -1};
166 };
167
168 // Not cancellable
Cancel(TaskHandle)169 bool Cancel(TaskHandle /*handle*/) override { return false; }
170
171 private:
172 std::shared_ptr<grpc_core::DNSResolver> default_resolver_;
173 std::shared_ptr<grpc_event_engine::experimental::EventEngine> engine_;
174 };
175
176 } // namespace
177
test_dns_lookup_ares(const char * dns_server,const char * name,const char * default_port,grpc_pollset_set *,grpc_closure * on_done,std::unique_ptr<grpc_core::EndpointAddressesList> * addresses,int query_timeout_ms)178 static grpc_ares_request* test_dns_lookup_ares(
179 const char* dns_server, const char* name, const char* default_port,
180 grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done,
181 std::unique_ptr<grpc_core::EndpointAddressesList>* addresses,
182 int query_timeout_ms) {
183 // A records should suffice
184 grpc_ares_request* result = g_default_dns_lookup_ares(
185 dns_server, name, default_port, g_iomgr_args.pollset_set, on_done,
186 addresses, query_timeout_ms);
187 ++g_resolution_count;
188 static auto last_resolution_time = grpc_core::Timestamp::ProcessEpoch();
189 auto now =
190 grpc_core::Timestamp::FromTimespecRoundUp(gpr_now(GPR_CLOCK_MONOTONIC));
191 gpr_log(GPR_DEBUG,
192 "last_resolution_time:%" PRId64 " now:%" PRId64
193 " min_time_between:%d",
194 last_resolution_time.milliseconds_after_process_epoch(),
195 now.milliseconds_after_process_epoch(), kMinResolutionPeriodMs);
196 if (last_resolution_time != grpc_core::Timestamp::ProcessEpoch()) {
197 EXPECT_GE(now - last_resolution_time,
198 grpc_core::Duration::Milliseconds(kMinResolutionPeriodMs));
199 }
200 last_resolution_time = now;
201 // For correct time diff comparisons, make sure that any subsequent calls
202 // to grpc_core::Timestamp::Now() on this thread don't return a time
203 // which is earlier than that returned by the call(s) to
204 // gpr_now(GPR_CLOCK_MONOTONIC) within this function. This is important
205 // because the resolver's last_resolution_timestamp_ will be taken from
206 // grpc_core::Timestamp::Now() right after this returns.
207 grpc_core::ExecCtx::Get()->InvalidateNow();
208 return result;
209 }
210
test_deadline(void)211 static gpr_timespec test_deadline(void) {
212 return grpc_timeout_seconds_to_deadline(100);
213 }
214
do_nothing(void *,grpc_error_handle)215 static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
216
iomgr_args_init(iomgr_args * args)217 static void iomgr_args_init(iomgr_args* args) {
218 gpr_event_init(&args->ev);
219 args->pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
220 grpc_pollset_init(args->pollset, &args->mu);
221 args->pollset_set = grpc_pollset_set_create();
222 grpc_pollset_set_add_pollset(args->pollset_set, args->pollset);
223 gpr_atm_rel_store(&args->done_atm, 0);
224 }
225
iomgr_args_finish(iomgr_args * args)226 static void iomgr_args_finish(iomgr_args* args) {
227 ASSERT_TRUE(gpr_event_wait(&args->ev, test_deadline()));
228 grpc_pollset_set_del_pollset(args->pollset_set, args->pollset);
229 grpc_pollset_set_destroy(args->pollset_set);
230 grpc_closure do_nothing_cb;
231 GRPC_CLOSURE_INIT(&do_nothing_cb, do_nothing, nullptr,
232 grpc_schedule_on_exec_ctx);
233 gpr_mu_lock(args->mu);
234 grpc_pollset_shutdown(args->pollset, &do_nothing_cb);
235 gpr_mu_unlock(args->mu);
236 // exec_ctx needs to be flushed before calling grpc_pollset_destroy()
237 grpc_core::ExecCtx::Get()->Flush();
238 grpc_pollset_destroy(args->pollset);
239 gpr_free(args->pollset);
240 }
241
n_sec_deadline(int seconds)242 static grpc_core::Timestamp n_sec_deadline(int seconds) {
243 return grpc_core::Timestamp::FromTimespecRoundUp(
244 grpc_timeout_seconds_to_deadline(seconds));
245 }
246
poll_pollset_until_request_done(iomgr_args * args)247 static void poll_pollset_until_request_done(iomgr_args* args) {
248 grpc_core::ExecCtx exec_ctx;
249 grpc_core::Timestamp deadline = n_sec_deadline(10);
250 while (true) {
251 bool done = gpr_atm_acq_load(&args->done_atm) != 0;
252 if (done) {
253 break;
254 }
255 grpc_core::Duration time_left = deadline - grpc_core::Timestamp::Now();
256 gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRId64, done, time_left.millis());
257 ASSERT_GE(time_left, grpc_core::Duration::Zero());
258 grpc_pollset_worker* worker = nullptr;
259 gpr_mu_lock(args->mu);
260 GRPC_LOG_IF_ERROR("pollset_work", grpc_pollset_work(args->pollset, &worker,
261 n_sec_deadline(1)));
262 gpr_mu_unlock(args->mu);
263 grpc_core::ExecCtx::Get()->Flush();
264 }
265 gpr_event_set(&args->ev, reinterpret_cast<void*>(1));
266 }
267
268 struct OnResolutionCallbackArg;
269
270 class ResultHandler : public grpc_core::Resolver::ResultHandler {
271 public:
272 using ResultCallback = void (*)(OnResolutionCallbackArg* state);
273
SetCallback(ResultCallback result_cb,OnResolutionCallbackArg * state)274 void SetCallback(ResultCallback result_cb, OnResolutionCallbackArg* state) {
275 ASSERT_EQ(result_cb_, nullptr);
276 result_cb_ = result_cb;
277 ASSERT_EQ(state_, nullptr);
278 state_ = state;
279 }
280
ReportResult(grpc_core::Resolver::Result result)281 void ReportResult(grpc_core::Resolver::Result result) override {
282 if (result.result_health_callback != nullptr) {
283 result.result_health_callback(absl::OkStatus());
284 }
285 ASSERT_NE(result_cb_, nullptr);
286 ASSERT_NE(state_, nullptr);
287 ResultCallback cb = result_cb_;
288 OnResolutionCallbackArg* state = state_;
289 result_cb_ = nullptr;
290 state_ = nullptr;
291 cb(state);
292 }
293
294 private:
295 ResultCallback result_cb_ = nullptr;
296 OnResolutionCallbackArg* state_ = nullptr;
297 };
298
299 struct OnResolutionCallbackArg {
300 const char* uri_str = nullptr;
301 grpc_core::OrphanablePtr<grpc_core::Resolver> resolver;
302 ResultHandler* result_handler;
303 };
304
305 // Set to true by the last callback in the resolution chain.
306 static grpc_core::NoDestruct<grpc_core::Notification> g_all_callbacks_invoked;
307
308 // It's interesting to run a few rounds of this test because as
309 // we run more rounds, the base starting time
310 // (i.e. ExecCtx g_start_time) gets further and further away
311 // from "Now()". Thus the more rounds ran, the more highlighted the
312 // difference is between absolute and relative times values.
on_fourth_resolution(OnResolutionCallbackArg * cb_arg)313 static void on_fourth_resolution(OnResolutionCallbackArg* cb_arg) {
314 gpr_log(GPR_INFO, "4th: g_resolution_count: %d", g_resolution_count);
315 ASSERT_EQ(g_resolution_count, 4);
316 cb_arg->resolver.reset();
317 gpr_atm_rel_store(&g_iomgr_args.done_atm, 1);
318 gpr_mu_lock(g_iomgr_args.mu);
319 GRPC_LOG_IF_ERROR("pollset_kick",
320 grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
321 gpr_mu_unlock(g_iomgr_args.mu);
322 delete cb_arg;
323 g_all_callbacks_invoked->Notify();
324 }
325
on_third_resolution(OnResolutionCallbackArg * cb_arg)326 static void on_third_resolution(OnResolutionCallbackArg* cb_arg) {
327 gpr_log(GPR_INFO, "3rd: g_resolution_count: %d", g_resolution_count);
328 ASSERT_EQ(g_resolution_count, 3);
329 cb_arg->result_handler->SetCallback(on_fourth_resolution, cb_arg);
330 cb_arg->resolver->RequestReresolutionLocked();
331 gpr_mu_lock(g_iomgr_args.mu);
332 GRPC_LOG_IF_ERROR("pollset_kick",
333 grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
334 gpr_mu_unlock(g_iomgr_args.mu);
335 }
336
on_second_resolution(OnResolutionCallbackArg * cb_arg)337 static void on_second_resolution(OnResolutionCallbackArg* cb_arg) {
338 gpr_log(GPR_INFO, "2nd: g_resolution_count: %d", g_resolution_count);
339 // The resolution callback was not invoked until new data was
340 // available, which was delayed until after the cooldown period.
341 ASSERT_EQ(g_resolution_count, 2);
342 cb_arg->result_handler->SetCallback(on_third_resolution, cb_arg);
343 cb_arg->resolver->RequestReresolutionLocked();
344 gpr_mu_lock(g_iomgr_args.mu);
345 GRPC_LOG_IF_ERROR("pollset_kick",
346 grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
347 gpr_mu_unlock(g_iomgr_args.mu);
348 }
349
on_first_resolution(OnResolutionCallbackArg * cb_arg)350 static void on_first_resolution(OnResolutionCallbackArg* cb_arg) {
351 gpr_log(GPR_INFO, "1st: g_resolution_count: %d", g_resolution_count);
352 // There's one initial system-level resolution and one invocation of a
353 // notification callback (the current function).
354 ASSERT_EQ(g_resolution_count, 1);
355 cb_arg->result_handler->SetCallback(on_second_resolution, cb_arg);
356 cb_arg->resolver->RequestReresolutionLocked();
357 gpr_mu_lock(g_iomgr_args.mu);
358 GRPC_LOG_IF_ERROR("pollset_kick",
359 grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
360 gpr_mu_unlock(g_iomgr_args.mu);
361 }
362
start_test_under_work_serializer(void * arg)363 static void start_test_under_work_serializer(void* arg) {
364 OnResolutionCallbackArg* res_cb_arg =
365 static_cast<OnResolutionCallbackArg*>(arg);
366 res_cb_arg->result_handler = new ResultHandler();
367 grpc_core::ResolverFactory* factory = grpc_core::CoreConfiguration::Get()
368 .resolver_registry()
369 .LookupResolverFactory("dns");
370 absl::StatusOr<grpc_core::URI> uri =
371 grpc_core::URI::Parse(res_cb_arg->uri_str);
372 gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", res_cb_arg->uri_str,
373 std::string(factory->scheme()).c_str());
374 if (!uri.ok()) {
375 gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
376 ASSERT_TRUE(uri.ok());
377 }
378 grpc_core::ResolverArgs args;
379 args.uri = std::move(*uri);
380 args.work_serializer = *g_work_serializer;
381 args.result_handler = std::unique_ptr<grpc_core::Resolver::ResultHandler>(
382 res_cb_arg->result_handler);
383 g_resolution_count = 0;
384
385 grpc_arg cooldown_arg = grpc_channel_arg_integer_create(
386 const_cast<char*>(GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS),
387 kMinResolutionPeriodMs);
388 grpc_channel_args cooldown_args = {1, &cooldown_arg};
389 args.args = grpc_core::ChannelArgs::FromC(&cooldown_args);
390 args.args = args.args.SetObject(GetDefaultEventEngine());
391 res_cb_arg->resolver = factory->CreateResolver(std::move(args));
392 ASSERT_NE(res_cb_arg->resolver, nullptr);
393 // First resolution, would incur in system-level resolution.
394 res_cb_arg->result_handler->SetCallback(on_first_resolution, res_cb_arg);
395 res_cb_arg->resolver->StartLocked();
396 }
397
test_cooldown()398 static void test_cooldown() {
399 grpc_core::ExecCtx exec_ctx;
400 iomgr_args_init(&g_iomgr_args);
401 OnResolutionCallbackArg* res_cb_arg = new OnResolutionCallbackArg();
402 res_cb_arg->uri_str = "dns:127.0.0.1";
403
404 (*g_work_serializer)
405 ->Run([res_cb_arg]() { start_test_under_work_serializer(res_cb_arg); },
406 DEBUG_LOCATION);
407 grpc_core::ExecCtx::Get()->Flush();
408 poll_pollset_until_request_done(&g_iomgr_args);
409 iomgr_args_finish(&g_iomgr_args);
410 }
411
TEST(DnsResolverCooldownTest,MainTest)412 TEST(DnsResolverCooldownTest, MainTest) {
413 // TODO(yijiem): This test tests the cooldown behavior of the PollingResolver
414 // interface. To do that, it overrides the grpc_dns_lookup_hostname_ares
415 // function and overrides the iomgr's g_dns_resolver system. We would need to
416 // rewrite this test for EventEngine using a custom EE DNSResolver or adding
417 // to the resolver_fuzzer.
418 if (grpc_core::IsEventEngineDnsEnabled()) {
419 GTEST_SKIP() << "Not with event engine dns";
420 }
421 grpc_init();
422
423 auto work_serializer = std::make_shared<grpc_core::WorkSerializer>(
424 grpc_event_engine::experimental::GetDefaultEventEngine());
425 g_work_serializer = &work_serializer;
426
427 g_default_dns_lookup_ares = grpc_dns_lookup_hostname_ares;
428 grpc_dns_lookup_hostname_ares = test_dns_lookup_ares;
429 grpc_core::ResetDNSResolver(
430 std::make_unique<TestDNSResolver>(grpc_core::GetDNSResolver()));
431
432 test_cooldown();
433
434 grpc_shutdown();
435 g_all_callbacks_invoked->WaitForNotification();
436 }
437
main(int argc,char ** argv)438 int main(int argc, char** argv) {
439 grpc::testing::TestEnvironment env(&argc, argv);
440 ::testing::InitGoogleTest(&argc, argv);
441 return RUN_ALL_TESTS();
442 }
443