blob: 0b3126321a420490210315826149e81263ecc4f9 [file] [log] [blame]
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <string.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include "src/core/ext/filters/client_channel/resolver.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/timer.h"
#include "test/core/util/test_config.h"
static gpr_mu g_mu;
static bool g_fail_resolution = true;
static grpc_core::Combiner* g_combiner;
static void my_resolve_address(const char* addr, const char* /*default_port*/,
grpc_pollset_set* /*interested_parties*/,
grpc_closure* on_done,
grpc_resolved_addresses** addrs) {
gpr_mu_lock(&g_mu);
GPR_ASSERT(0 == strcmp("test", addr));
grpc_error* error = GRPC_ERROR_NONE;
if (g_fail_resolution) {
g_fail_resolution = false;
gpr_mu_unlock(&g_mu);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure");
} else {
gpr_mu_unlock(&g_mu);
*addrs = static_cast<grpc_resolved_addresses*>(gpr_malloc(sizeof(**addrs)));
(*addrs)->naddrs = 1;
(*addrs)->addrs = static_cast<grpc_resolved_address*>(
gpr_malloc(sizeof(*(*addrs)->addrs)));
(*addrs)->addrs[0].len = 123;
}
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, error);
}
static grpc_address_resolver_vtable test_resolver = {my_resolve_address,
nullptr};
static grpc_ares_request* my_dns_lookup_ares_locked(
const char* /*dns_server*/, const char* addr, const char* /*default_port*/,
grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addresses,
std::unique_ptr<grpc_core::ServerAddressList>* /*balancer_addresses*/,
char** /*service_config_json*/, int /*query_timeout_ms*/,
grpc_core::Combiner* /*combiner*/) {
gpr_mu_lock(&g_mu);
GPR_ASSERT(0 == strcmp("test", addr));
grpc_error* error = GRPC_ERROR_NONE;
if (g_fail_resolution) {
g_fail_resolution = false;
gpr_mu_unlock(&g_mu);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure");
} else {
gpr_mu_unlock(&g_mu);
*addresses = grpc_core::MakeUnique<grpc_core::ServerAddressList>();
grpc_resolved_address dummy_resolved_address;
memset(&dummy_resolved_address, 0, sizeof(dummy_resolved_address));
dummy_resolved_address.len = 123;
(*addresses)->emplace_back(dummy_resolved_address, nullptr);
}
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, error);
return nullptr;
}
static void my_cancel_ares_request_locked(grpc_ares_request* request) {
GPR_ASSERT(request == nullptr);
}
static grpc_core::OrphanablePtr<grpc_core::Resolver> create_resolver(
const char* name,
std::unique_ptr<grpc_core::Resolver::ResultHandler> result_handler) {
grpc_core::ResolverFactory* factory =
grpc_core::ResolverRegistry::LookupResolverFactory("dns");
grpc_uri* uri = grpc_uri_parse(name, 0);
GPR_ASSERT(uri);
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
args.result_handler = std::move(result_handler);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory->CreateResolver(std::move(args));
grpc_uri_destroy(uri);
return resolver;
}
class ResultHandler : public grpc_core::Resolver::ResultHandler {
public:
struct ResolverOutput {
grpc_core::Resolver::Result result;
grpc_error* error = nullptr;
gpr_event ev;
ResolverOutput() { gpr_event_init(&ev); }
~ResolverOutput() { GRPC_ERROR_UNREF(error); }
};
void SetOutput(ResolverOutput* output) {
gpr_atm_rel_store(&output_, reinterpret_cast<gpr_atm>(output));
}
void ReturnResult(grpc_core::Resolver::Result result) override {
ResolverOutput* output =
reinterpret_cast<ResolverOutput*>(gpr_atm_acq_load(&output_));
GPR_ASSERT(output != nullptr);
output->result = std::move(result);
output->error = GRPC_ERROR_NONE;
gpr_event_set(&output->ev, (void*)1);
}
void ReturnError(grpc_error* error) override {
ResolverOutput* output =
reinterpret_cast<ResolverOutput*>(gpr_atm_acq_load(&output_));
GPR_ASSERT(output != nullptr);
output->error = error;
gpr_event_set(&output->ev, (void*)1);
}
private:
gpr_atm output_ = 0; // ResolverOutput*
};
// interleave waiting for an event with a timer check
static bool wait_loop(int deadline_seconds, gpr_event* ev) {
while (deadline_seconds) {
gpr_log(GPR_DEBUG, "Test: waiting for %d more seconds", deadline_seconds);
if (gpr_event_wait(ev, grpc_timeout_seconds_to_deadline(1))) return true;
deadline_seconds--;
grpc_core::ExecCtx exec_ctx;
grpc_timer_check(nullptr);
}
return false;
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
gpr_mu_init(&g_mu);
g_combiner = grpc_combiner_create();
grpc_set_resolver_impl(&test_resolver);
grpc_dns_lookup_ares_locked = my_dns_lookup_ares_locked;
grpc_cancel_ares_request_locked = my_cancel_ares_request_locked;
{
grpc_core::ExecCtx exec_ctx;
ResultHandler* result_handler = new ResultHandler();
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver = create_resolver(
"dns:test",
std::unique_ptr<grpc_core::Resolver::ResultHandler>(result_handler));
ResultHandler::ResolverOutput output1;
result_handler->SetOutput(&output1);
resolver->StartLocked();
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(wait_loop(5, &output1.ev));
GPR_ASSERT(output1.result.addresses.empty());
GPR_ASSERT(output1.error != GRPC_ERROR_NONE);
ResultHandler::ResolverOutput output2;
result_handler->SetOutput(&output2);
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(wait_loop(30, &output2.ev));
GPR_ASSERT(!output2.result.addresses.empty());
GPR_ASSERT(output2.error == GRPC_ERROR_NONE);
GRPC_COMBINER_UNREF(g_combiner, "test");
}
grpc_shutdown();
gpr_mu_destroy(&g_mu);
}