mirror of https://github.com/grpc/grpc.git
commit
d4477c17e7
94 changed files with 3196 additions and 884 deletions
@ -0,0 +1,92 @@ |
||||
<%def name="resolver_component_tests(tests)">#!/bin/bash |
||||
# 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. |
||||
|
||||
# This file is auto-generated |
||||
|
||||
set -ex |
||||
|
||||
# all command args required in this set order |
||||
FLAGS_test_bin_path=`echo "$1" | grep '\--test_bin_path=' | cut -d "=" -f 2` |
||||
FLAGS_dns_server_bin_path=`echo "$2" | grep '\--dns_server_bin_path=' | cut -d "=" -f 2` |
||||
FLAGS_records_config_path=`echo "$3" | grep '\--records_config_path=' | cut -d "=" -f 2` |
||||
FLAGS_test_dns_server_port=`echo "$4" | grep '\--test_dns_server_port=' | cut -d "=" -f 2` |
||||
|
||||
for cmd_arg in "$FLAGS_test_bin_path" "$FLAGS_dns_server_bin_path" "$FLAGS_records_config_path" "$FLAGS_test_dns_server_port"; do |
||||
if [[ "$cmd_arg" == "" ]]; then |
||||
echo "Missing a CMD arg" && exit 1 |
||||
fi |
||||
done |
||||
|
||||
if [[ "$GRPC_DNS_RESOLVER" != "" && "$GRPC_DNS_RESOLVER" != ares ]]; then |
||||
echo "This test only works under GRPC_DNS_RESOLVER=ares. Have GRPC_DNS_RESOLVER=$GRPC_DNS_RESOLVER" && exit 1 |
||||
fi |
||||
export GRPC_DNS_RESOLVER=ares |
||||
|
||||
"$FLAGS_dns_server_bin_path" --records_config_path="$FLAGS_records_config_path" --port="$FLAGS_test_dns_server_port" 2>&1 > /dev/null & |
||||
DNS_SERVER_PID=$! |
||||
echo "Local DNS server started. PID: $DNS_SERVER_PID" |
||||
|
||||
# Health check local DNS server TCP and UDP ports |
||||
for ((i=0;i<30;i++)); |
||||
do |
||||
echo "Retry health-check DNS query to local DNS server over tcp and udp" |
||||
RETRY=0 |
||||
dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 | grep '123.123.123.123' || RETRY=1 |
||||
dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 +tcp | grep '123.123.123.123' || RETRY=1 |
||||
if [[ "$RETRY" == 0 ]]; then |
||||
break |
||||
fi; |
||||
sleep 0.1 |
||||
done |
||||
|
||||
if [[ $RETRY == 1 ]]; then |
||||
echo "FAILED TO START LOCAL DNS SERVER" |
||||
kill -SIGTERM $DNS_SERVER_PID |
||||
wait |
||||
exit 1 |
||||
fi |
||||
|
||||
function terminate_all { |
||||
echo "Received signal. Terminating $! and $DNS_SERVER_PID" |
||||
kill -SIGTERM $! || true |
||||
kill -SIGTERM $DNS_SERVER_PID || true |
||||
wait |
||||
exit 1 |
||||
} |
||||
|
||||
trap terminate_all SIGTERM SIGINT |
||||
|
||||
EXIT_CODE=0 |
||||
# TODO: this test should check for GCE residency and skip tests using _grpclb._tcp.* SRV records once GCE residency checks are made |
||||
# in the resolver. |
||||
|
||||
% for test in tests: |
||||
$FLAGS_test_bin_path \\ |
||||
|
||||
--target_name='${test['target_name']}' \\ |
||||
|
||||
--expected_addrs='${test['expected_addrs']}' \\ |
||||
|
||||
--expected_chosen_service_config='${test['expected_chosen_service_config']}' \\ |
||||
|
||||
--expected_lb_policy='${test['expected_lb_policy']}' \\ |
||||
|
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
% endfor |
||||
kill -SIGTERM $DNS_SERVER_PID || true |
||||
wait |
||||
exit $EXIT_CODE</%def> |
@ -0,0 +1,4 @@ |
||||
%YAML 1.2 |
||||
--- | |
||||
<%namespace file="resolver_component_tests_defs.include" import="*"/>\ |
||||
${resolver_component_tests(resolver_component_test_cases)} |
@ -0,0 +1,49 @@ |
||||
# Copyright 2017 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. |
||||
|
||||
package( |
||||
default_visibility = ["//visibility:public"], |
||||
features = [ |
||||
"-layering_check", |
||||
"-parse_headers", |
||||
], |
||||
) |
||||
|
||||
licenses(["notice"]) # Apache v2 |
||||
|
||||
load("//bazel:grpc_build_system.bzl", "grpc_sh_binary", "grpc_py_binary") |
||||
|
||||
load(":generate_resolver_component_tests.bzl", "generate_resolver_component_tests") |
||||
|
||||
# Meant to be invoked only through the top-level shell script driver. |
||||
grpc_sh_binary( |
||||
name = "resolver_component_tests_runner", |
||||
srcs = [ |
||||
"resolver_component_tests_runner.sh", |
||||
], |
||||
) |
||||
|
||||
grpc_py_binary( |
||||
name = "test_dns_server", |
||||
srcs = ["test_dns_server.py"], |
||||
data = [ |
||||
"resolver_test_record_groups.yaml", |
||||
], |
||||
deps = [ |
||||
"twisted", |
||||
"yaml", |
||||
] |
||||
) |
||||
|
||||
generate_resolver_component_tests() |
@ -0,0 +1,99 @@ |
||||
#!/usr/bin/env python2.7 |
||||
# 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. |
||||
|
||||
|
||||
"""Generates the appropriate build.json data for all the naming tests.""" |
||||
|
||||
|
||||
import yaml |
||||
import collections |
||||
import hashlib |
||||
import json |
||||
|
||||
_LOCAL_DNS_SERVER_ADDRESS = '127.0.0.1:15353' |
||||
|
||||
def _append_zone_name(name, zone_name): |
||||
return '%s.%s' % (name, zone_name) |
||||
|
||||
def _build_expected_addrs_cmd_arg(expected_addrs): |
||||
out = [] |
||||
for addr in expected_addrs: |
||||
out.append('%s,%s' % (addr['address'], str(addr['is_balancer']))) |
||||
return ';'.join(out) |
||||
|
||||
def main(): |
||||
resolver_component_data = '' |
||||
with open('test/cpp/naming/resolver_test_record_groups.yaml') as f: |
||||
resolver_component_data = yaml.load(f) |
||||
|
||||
json = { |
||||
'resolver_component_test_cases': [ |
||||
{ |
||||
'target_name': _append_zone_name(test_case['record_to_resolve'], |
||||
resolver_component_data['resolver_component_tests_common_zone_name']), |
||||
'expected_addrs': _build_expected_addrs_cmd_arg(test_case['expected_addrs']), |
||||
'expected_chosen_service_config': (test_case['expected_chosen_service_config'] or ''), |
||||
'expected_lb_policy': (test_case['expected_lb_policy'] or ''), |
||||
} for test_case in resolver_component_data['resolver_component_tests'] |
||||
], |
||||
'targets': [ |
||||
{ |
||||
'name': 'resolver_component_test' + unsecure_build_config_suffix, |
||||
'build': 'test', |
||||
'language': 'c++', |
||||
'gtest': False, |
||||
'run': False, |
||||
'src': ['test/cpp/naming/resolver_component_test.cc'], |
||||
'platforms': ['linux', 'posix', 'mac'], |
||||
'deps': [ |
||||
'grpc++_test_util' + unsecure_build_config_suffix, |
||||
'grpc_test_util' + unsecure_build_config_suffix, |
||||
'gpr_test_util', |
||||
'grpc++' + unsecure_build_config_suffix, |
||||
'grpc' + unsecure_build_config_suffix, |
||||
'gpr', |
||||
'grpc++_test_config', |
||||
], |
||||
} for unsecure_build_config_suffix in ['_unsecure', ''] |
||||
] + [ |
||||
{ |
||||
'name': 'resolver_component_tests_runner_invoker' + unsecure_build_config_suffix, |
||||
'build': 'test', |
||||
'language': 'c++', |
||||
'gtest': False, |
||||
'run': True, |
||||
'src': ['test/cpp/naming/resolver_component_tests_runner_invoker.cc'], |
||||
'platforms': ['linux', 'posix', 'mac'], |
||||
'deps': [ |
||||
'grpc++_test_util', |
||||
'grpc_test_util', |
||||
'gpr_test_util', |
||||
'grpc++', |
||||
'grpc', |
||||
'gpr', |
||||
'grpc++_test_config', |
||||
], |
||||
'args': [ |
||||
'--test_bin_name=resolver_component_test%s' % unsecure_build_config_suffix, |
||||
'--running_under_bazel=false', |
||||
], |
||||
} for unsecure_build_config_suffix in ['_unsecure', ''] |
||||
] |
||||
} |
||||
|
||||
print(yaml.dump(json)) |
||||
|
||||
if __name__ == '__main__': |
||||
main() |
@ -0,0 +1,64 @@ |
||||
#!/usr/bin/env python2.7 |
||||
# 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. |
||||
|
||||
load("//bazel:grpc_build_system.bzl", "grpc_sh_binary", "grpc_cc_test", "grpc_cc_binary") |
||||
|
||||
def generate_resolver_component_tests(): |
||||
for unsecure_build_config_suffix in ['_unsecure', '']: |
||||
# meant to be invoked only through the top-level shell script driver |
||||
grpc_cc_binary( |
||||
name = "resolver_component_test%s" % unsecure_build_config_suffix, |
||||
testonly = 1, |
||||
srcs = [ |
||||
"resolver_component_test.cc", |
||||
], |
||||
external_deps = [ |
||||
"gmock", |
||||
], |
||||
deps = [ |
||||
"//test/cpp/util:test_util%s" % unsecure_build_config_suffix, |
||||
"//test/core/util:grpc_test_util%s" % unsecure_build_config_suffix, |
||||
"//test/core/util:gpr_test_util", |
||||
"//:grpc++%s" % unsecure_build_config_suffix, |
||||
"//:grpc%s" % unsecure_build_config_suffix, |
||||
"//:gpr", |
||||
"//test/cpp/util:test_config", |
||||
], |
||||
) |
||||
grpc_cc_test( |
||||
name = "resolver_component_tests_runner_invoker%s" % unsecure_build_config_suffix, |
||||
srcs = [ |
||||
"resolver_component_tests_runner_invoker.cc", |
||||
], |
||||
deps = [ |
||||
"//test/cpp/util:test_util", |
||||
"//test/core/util:grpc_test_util", |
||||
"//test/core/util:gpr_test_util", |
||||
"//:grpc++", |
||||
"//:grpc", |
||||
"//:gpr", |
||||
"//test/cpp/util:test_config", |
||||
], |
||||
data = [ |
||||
":resolver_component_tests_runner", |
||||
":resolver_component_test%s" % unsecure_build_config_suffix, |
||||
":test_dns_server", |
||||
"resolver_test_record_groups.yaml", # include the transitive dependency so that the dns sever py binary can locate this |
||||
], |
||||
args = [ |
||||
"--test_bin_name=resolver_component_test%s" % unsecure_build_config_suffix, |
||||
"--running_under_bazel=true", |
||||
] |
||||
) |
@ -0,0 +1,323 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 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 <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/host_port.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/time.h> |
||||
#include <string.h> |
||||
|
||||
#include <gflags/gflags.h> |
||||
#include <gmock/gmock.h> |
||||
#include <vector> |
||||
|
||||
#include "test/cpp/util/subprocess.h" |
||||
#include "test/cpp/util/test_config.h" |
||||
|
||||
extern "C" { |
||||
#include "src/core/ext/filters/client_channel/client_channel.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/lib/channel/channel_args.h" |
||||
#include "src/core/lib/iomgr/combiner.h" |
||||
#include "src/core/lib/iomgr/executor.h" |
||||
#include "src/core/lib/iomgr/iomgr.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/support/env.h" |
||||
#include "src/core/lib/support/string.h" |
||||
#include "test/core/util/port.h" |
||||
#include "test/core/util/test_config.h" |
||||
} |
||||
|
||||
using std::vector; |
||||
using grpc::SubProcess; |
||||
using testing::UnorderedElementsAreArray; |
||||
|
||||
// Hack copied from "test/cpp/end2end/server_crash_test_client.cc"!
|
||||
// In some distros, gflags is in the namespace google, and in some others,
|
||||
// in gflags. This hack is enabling us to find both.
|
||||
namespace google {} |
||||
namespace gflags {} |
||||
using namespace google; |
||||
using namespace gflags; |
||||
|
||||
DEFINE_string(target_name, "", "Target name to resolve."); |
||||
DEFINE_string(expected_addrs, "", |
||||
"Comma-separated list of expected " |
||||
"'<ip0:port0>,<is_balancer0>;<ip1:port1>,<is_balancer1>;...' " |
||||
"addresses of " |
||||
"backend and/or balancers. 'is_balancer' should be bool, i.e. " |
||||
"true or false."); |
||||
DEFINE_string(expected_chosen_service_config, "", |
||||
"Expected service config json string that gets chosen (no " |
||||
"whitespace). Empty for none."); |
||||
DEFINE_string( |
||||
local_dns_server_address, "", |
||||
"Optional. This address is placed as the uri authority if present."); |
||||
DEFINE_string(expected_lb_policy, "", |
||||
"Expected lb policy name that appears in resolver result channel " |
||||
"arg. Empty for none."); |
||||
|
||||
namespace { |
||||
|
||||
class GrpcLBAddress final { |
||||
public: |
||||
GrpcLBAddress(std::string address, bool is_balancer) |
||||
: is_balancer(is_balancer), address(address) {} |
||||
|
||||
bool operator==(const GrpcLBAddress &other) const { |
||||
return this->is_balancer == other.is_balancer && |
||||
this->address == other.address; |
||||
} |
||||
|
||||
bool operator!=(const GrpcLBAddress &other) const { |
||||
return !(*this == other); |
||||
} |
||||
|
||||
bool is_balancer; |
||||
std::string address; |
||||
}; |
||||
|
||||
vector<GrpcLBAddress> ParseExpectedAddrs(std::string expected_addrs) { |
||||
std::vector<GrpcLBAddress> out; |
||||
while (expected_addrs.size() != 0) { |
||||
// get the next <ip>,<port> (v4 or v6)
|
||||
size_t next_comma = expected_addrs.find(","); |
||||
if (next_comma == std::string::npos) { |
||||
gpr_log( |
||||
GPR_ERROR, |
||||
"Missing ','. Expected_addrs arg should be a semi-colon-separated " |
||||
"list of " |
||||
"<ip-port>,<bool> pairs. Left-to-be-parsed arg is |%s|", |
||||
expected_addrs.c_str()); |
||||
abort(); |
||||
} |
||||
std::string next_addr = expected_addrs.substr(0, next_comma); |
||||
expected_addrs = expected_addrs.substr(next_comma + 1, std::string::npos); |
||||
// get the next is_balancer 'bool' associated with this address
|
||||
size_t next_semicolon = expected_addrs.find(";"); |
||||
bool is_balancer = |
||||
gpr_is_true(expected_addrs.substr(0, next_semicolon).c_str()); |
||||
out.emplace_back(GrpcLBAddress(next_addr, is_balancer)); |
||||
if (next_semicolon == std::string::npos) { |
||||
break; |
||||
} |
||||
expected_addrs = |
||||
expected_addrs.substr(next_semicolon + 1, std::string::npos); |
||||
} |
||||
if (out.size() == 0) { |
||||
gpr_log(GPR_ERROR, |
||||
"expected_addrs arg should be a comma-separated list of " |
||||
"<ip-port>,<bool> pairs"); |
||||
abort(); |
||||
} |
||||
return out; |
||||
} |
||||
|
||||
gpr_timespec TestDeadline(void) { |
||||
return grpc_timeout_seconds_to_deadline(100); |
||||
} |
||||
|
||||
struct ArgsStruct { |
||||
gpr_event ev; |
||||
gpr_atm done_atm; |
||||
gpr_mu *mu; |
||||
grpc_pollset *pollset; |
||||
grpc_pollset_set *pollset_set; |
||||
grpc_combiner *lock; |
||||
grpc_channel_args *channel_args; |
||||
vector<GrpcLBAddress> expected_addrs; |
||||
std::string expected_service_config_string; |
||||
std::string expected_lb_policy; |
||||
}; |
||||
|
||||
void ArgsInit(grpc_exec_ctx *exec_ctx, ArgsStruct *args) { |
||||
gpr_event_init(&args->ev); |
||||
args->pollset = (grpc_pollset *)gpr_zalloc(grpc_pollset_size()); |
||||
grpc_pollset_init(args->pollset, &args->mu); |
||||
args->pollset_set = grpc_pollset_set_create(); |
||||
grpc_pollset_set_add_pollset(exec_ctx, args->pollset_set, args->pollset); |
||||
args->lock = grpc_combiner_create(); |
||||
gpr_atm_rel_store(&args->done_atm, 0); |
||||
args->channel_args = NULL; |
||||
} |
||||
|
||||
void DoNothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} |
||||
|
||||
void ArgsFinish(grpc_exec_ctx *exec_ctx, ArgsStruct *args) { |
||||
GPR_ASSERT(gpr_event_wait(&args->ev, TestDeadline())); |
||||
grpc_pollset_set_del_pollset(exec_ctx, args->pollset_set, args->pollset); |
||||
grpc_pollset_set_destroy(exec_ctx, args->pollset_set); |
||||
grpc_closure DoNothing_cb; |
||||
GRPC_CLOSURE_INIT(&DoNothing_cb, DoNothing, NULL, grpc_schedule_on_exec_ctx); |
||||
grpc_pollset_shutdown(exec_ctx, args->pollset, &DoNothing_cb); |
||||
// exec_ctx needs to be flushed before calling grpc_pollset_destroy()
|
||||
grpc_channel_args_destroy(exec_ctx, args->channel_args); |
||||
grpc_exec_ctx_flush(exec_ctx); |
||||
grpc_pollset_destroy(exec_ctx, args->pollset); |
||||
gpr_free(args->pollset); |
||||
GRPC_COMBINER_UNREF(exec_ctx, args->lock, NULL); |
||||
} |
||||
|
||||
gpr_timespec NSecondDeadline(int seconds) { |
||||
return gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), |
||||
gpr_time_from_seconds(seconds, GPR_TIMESPAN)); |
||||
} |
||||
|
||||
void PollPollsetUntilRequestDone(ArgsStruct *args) { |
||||
gpr_timespec deadline = NSecondDeadline(10); |
||||
while (true) { |
||||
bool done = gpr_atm_acq_load(&args->done_atm) != 0; |
||||
if (done) { |
||||
break; |
||||
} |
||||
gpr_timespec time_left = |
||||
gpr_time_sub(deadline, gpr_now(GPR_CLOCK_REALTIME)); |
||||
gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRId64 ".%09d", done, |
||||
time_left.tv_sec, time_left.tv_nsec); |
||||
GPR_ASSERT(gpr_time_cmp(time_left, gpr_time_0(GPR_TIMESPAN)) >= 0); |
||||
grpc_pollset_worker *worker = NULL; |
||||
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||
gpr_mu_lock(args->mu); |
||||
GRPC_LOG_IF_ERROR( |
||||
"pollset_work", |
||||
grpc_pollset_work(&exec_ctx, args->pollset, &worker, |
||||
gpr_now(GPR_CLOCK_REALTIME), NSecondDeadline(1))); |
||||
gpr_mu_unlock(args->mu); |
||||
grpc_exec_ctx_finish(&exec_ctx); |
||||
} |
||||
gpr_event_set(&args->ev, (void *)1); |
||||
} |
||||
|
||||
void CheckServiceConfigResultLocked(grpc_channel_args *channel_args, |
||||
ArgsStruct *args) { |
||||
const grpc_arg *service_config_arg = |
||||
grpc_channel_args_find(channel_args, GRPC_ARG_SERVICE_CONFIG); |
||||
if (args->expected_service_config_string != "") { |
||||
GPR_ASSERT(service_config_arg != NULL); |
||||
GPR_ASSERT(service_config_arg->type == GRPC_ARG_STRING); |
||||
EXPECT_EQ(service_config_arg->value.string, |
||||
args->expected_service_config_string); |
||||
} else { |
||||
GPR_ASSERT(service_config_arg == NULL); |
||||
} |
||||
} |
||||
|
||||
void CheckLBPolicyResultLocked(grpc_channel_args *channel_args, |
||||
ArgsStruct *args) { |
||||
const grpc_arg *lb_policy_arg = |
||||
grpc_channel_args_find(channel_args, GRPC_ARG_LB_POLICY_NAME); |
||||
if (args->expected_lb_policy != "") { |
||||
GPR_ASSERT(lb_policy_arg != NULL); |
||||
GPR_ASSERT(lb_policy_arg->type == GRPC_ARG_STRING); |
||||
EXPECT_EQ(lb_policy_arg->value.string, args->expected_lb_policy); |
||||
} else { |
||||
GPR_ASSERT(lb_policy_arg == NULL); |
||||
} |
||||
} |
||||
|
||||
void CheckResolverResultLocked(grpc_exec_ctx *exec_ctx, void *argsp, |
||||
grpc_error *err) { |
||||
ArgsStruct *args = (ArgsStruct *)argsp; |
||||
grpc_channel_args *channel_args = args->channel_args; |
||||
const grpc_arg *channel_arg = |
||||
grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); |
||||
GPR_ASSERT(channel_arg != NULL); |
||||
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); |
||||
grpc_lb_addresses *addresses = |
||||
(grpc_lb_addresses *)channel_arg->value.pointer.p; |
||||
gpr_log(GPR_INFO, "num addrs found: %" PRIdPTR ". expected %" PRIdPTR, |
||||
addresses->num_addresses, args->expected_addrs.size()); |
||||
GPR_ASSERT(addresses->num_addresses == args->expected_addrs.size()); |
||||
std::vector<GrpcLBAddress> found_lb_addrs; |
||||
for (size_t i = 0; i < addresses->num_addresses; i++) { |
||||
grpc_lb_address addr = addresses->addresses[i]; |
||||
char *str; |
||||
grpc_sockaddr_to_string(&str, &addr.address, 1 /* normalize */); |
||||
gpr_log(GPR_INFO, "%s", str); |
||||
found_lb_addrs.emplace_back( |
||||
GrpcLBAddress(std::string(str), addr.is_balancer)); |
||||
gpr_free(str); |
||||
} |
||||
if (args->expected_addrs.size() != found_lb_addrs.size()) { |
||||
gpr_log(GPR_DEBUG, "found lb addrs size is: %" PRIdPTR |
||||
". expected addrs size is %" PRIdPTR, |
||||
found_lb_addrs.size(), args->expected_addrs.size()); |
||||
abort(); |
||||
} |
||||
EXPECT_THAT(args->expected_addrs, UnorderedElementsAreArray(found_lb_addrs)); |
||||
CheckServiceConfigResultLocked(channel_args, args); |
||||
CheckLBPolicyResultLocked(channel_args, args); |
||||
gpr_atm_rel_store(&args->done_atm, 1); |
||||
gpr_mu_lock(args->mu); |
||||
GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(args->pollset, NULL)); |
||||
gpr_mu_unlock(args->mu); |
||||
} |
||||
|
||||
TEST(ResolverComponentTest, TestResolvesRelevantRecords) { |
||||
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||
ArgsStruct args; |
||||
ArgsInit(&exec_ctx, &args); |
||||
args.expected_addrs = ParseExpectedAddrs(FLAGS_expected_addrs); |
||||
args.expected_service_config_string = FLAGS_expected_chosen_service_config; |
||||
args.expected_lb_policy = FLAGS_expected_lb_policy; |
||||
// maybe build the address with an authority
|
||||
char *whole_uri = NULL; |
||||
GPR_ASSERT(asprintf(&whole_uri, "dns://%s/%s", |
||||
FLAGS_local_dns_server_address.c_str(), |
||||
FLAGS_target_name.c_str())); |
||||
// create resolver and resolve
|
||||
grpc_resolver *resolver = grpc_resolver_create(&exec_ctx, whole_uri, NULL, |
||||
args.pollset_set, args.lock); |
||||
gpr_free(whole_uri); |
||||
grpc_closure on_resolver_result_changed; |
||||
GRPC_CLOSURE_INIT(&on_resolver_result_changed, CheckResolverResultLocked, |
||||
(void *)&args, grpc_combiner_scheduler(args.lock)); |
||||
grpc_resolver_next_locked(&exec_ctx, resolver, &args.channel_args, |
||||
&on_resolver_result_changed); |
||||
grpc_exec_ctx_flush(&exec_ctx); |
||||
PollPollsetUntilRequestDone(&args); |
||||
GRPC_RESOLVER_UNREF(&exec_ctx, resolver, NULL); |
||||
ArgsFinish(&exec_ctx, &args); |
||||
grpc_exec_ctx_finish(&exec_ctx); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) { |
||||
grpc_init(); |
||||
grpc_test_init(argc, argv); |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
ParseCommandLineFlags(&argc, &argv, true); |
||||
if (FLAGS_target_name == "") { |
||||
gpr_log(GPR_ERROR, "Missing target_name param."); |
||||
abort(); |
||||
} |
||||
if (FLAGS_local_dns_server_address != "") { |
||||
gpr_log(GPR_INFO, "Specifying authority in uris to: %s", |
||||
FLAGS_local_dns_server_address.c_str()); |
||||
} |
||||
auto result = RUN_ALL_TESTS(); |
||||
grpc_shutdown(); |
||||
return result; |
||||
} |
@ -0,0 +1,173 @@ |
||||
#!/bin/bash |
||||
# 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. |
||||
|
||||
# This file is auto-generated |
||||
|
||||
set -ex |
||||
|
||||
# all command args required in this set order |
||||
FLAGS_test_bin_path=`echo "$1" | grep '\--test_bin_path=' | cut -d "=" -f 2` |
||||
FLAGS_dns_server_bin_path=`echo "$2" | grep '\--dns_server_bin_path=' | cut -d "=" -f 2` |
||||
FLAGS_records_config_path=`echo "$3" | grep '\--records_config_path=' | cut -d "=" -f 2` |
||||
FLAGS_test_dns_server_port=`echo "$4" | grep '\--test_dns_server_port=' | cut -d "=" -f 2` |
||||
|
||||
for cmd_arg in "$FLAGS_test_bin_path" "$FLAGS_dns_server_bin_path" "$FLAGS_records_config_path" "$FLAGS_test_dns_server_port"; do |
||||
if [[ "$cmd_arg" == "" ]]; then |
||||
echo "Missing a CMD arg" && exit 1 |
||||
fi |
||||
done |
||||
|
||||
if [[ "$GRPC_DNS_RESOLVER" != "" && "$GRPC_DNS_RESOLVER" != ares ]]; then |
||||
echo "This test only works under GRPC_DNS_RESOLVER=ares. Have GRPC_DNS_RESOLVER=$GRPC_DNS_RESOLVER" && exit 1 |
||||
fi |
||||
export GRPC_DNS_RESOLVER=ares |
||||
|
||||
"$FLAGS_dns_server_bin_path" --records_config_path="$FLAGS_records_config_path" --port="$FLAGS_test_dns_server_port" 2>&1 > /dev/null & |
||||
DNS_SERVER_PID=$! |
||||
echo "Local DNS server started. PID: $DNS_SERVER_PID" |
||||
|
||||
# Health check local DNS server TCP and UDP ports |
||||
for ((i=0;i<30;i++)); |
||||
do |
||||
echo "Retry health-check DNS query to local DNS server over tcp and udp" |
||||
RETRY=0 |
||||
dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 | grep '123.123.123.123' || RETRY=1 |
||||
dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 +tcp | grep '123.123.123.123' || RETRY=1 |
||||
if [[ "$RETRY" == 0 ]]; then |
||||
break |
||||
fi; |
||||
sleep 0.1 |
||||
done |
||||
|
||||
if [[ $RETRY == 1 ]]; then |
||||
echo "FAILED TO START LOCAL DNS SERVER" |
||||
kill -SIGTERM $DNS_SERVER_PID |
||||
wait |
||||
exit 1 |
||||
fi |
||||
|
||||
function terminate_all { |
||||
echo "Received signal. Terminating $! and $DNS_SERVER_PID" |
||||
kill -SIGTERM $! || true |
||||
kill -SIGTERM $DNS_SERVER_PID || true |
||||
wait |
||||
exit 1 |
||||
} |
||||
|
||||
trap terminate_all SIGTERM SIGINT |
||||
|
||||
EXIT_CODE=0 |
||||
# TODO: this test should check for GCE residency and skip tests using _grpclb._tcp.* SRV records once GCE residency checks are made |
||||
# in the resolver. |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='srv-ipv4-single-target.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:1234,True' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='srv-ipv4-multi-target.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.5:1234,True;1.2.3.6:1234,True;1.2.3.7:1234,True' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='srv-ipv6-single-target.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='[2607:f8b0:400a:801::1001]:1234,True' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='srv-ipv6-multi-target.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1003]:1234,True;[2607:f8b0:400a:801::1004]:1234,True' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='srv-ipv4-simple-service-config.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:1234,True' \ |
||||
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}' \ |
||||
--expected_lb_policy='round_robin' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='ipv4-no-srv-simple-service-config.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:443,False' \ |
||||
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}' \ |
||||
--expected_lb_policy='round_robin' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='ipv4-no-config-for-cpp.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:443,False' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='ipv4-cpp-config-has-zero-percentage.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:443,False' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='ipv4-second-language-is-cpp.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:443,False' \ |
||||
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}' \ |
||||
--expected_lb_policy='round_robin' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='ipv4-config-with-percentages.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:443,False' \ |
||||
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}' \ |
||||
--expected_lb_policy='round_robin' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='srv-ipv4-target-has-backend-and-balancer.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='1.2.3.4:1234,True;1.2.3.4:443,False' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
$FLAGS_test_bin_path \ |
||||
--target_name='srv-ipv6-target-has-backend-and-balancer.resolver-tests.grpctestingexp.' \ |
||||
--expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1002]:443,False' \ |
||||
--expected_chosen_service_config='' \ |
||||
--expected_lb_policy='' \ |
||||
--local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port & |
||||
wait $! || EXIT_CODE=1 |
||||
|
||||
kill -SIGTERM $DNS_SERVER_PID || true |
||||
wait |
||||
exit $EXIT_CODE |
@ -0,0 +1,189 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 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 <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <signal.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <gflags/gflags.h> |
||||
#include <string> |
||||
#include <thread> |
||||
#include <vector> |
||||
|
||||
#include "test/cpp/util/subprocess.h" |
||||
#include "test/cpp/util/test_config.h" |
||||
|
||||
extern "C" { |
||||
#include "src/core/lib/support/env.h" |
||||
#include "test/core/util/port.h" |
||||
} |
||||
|
||||
DEFINE_bool( |
||||
running_under_bazel, false, |
||||
"True if this test is running under bazel. " |
||||
"False indicates that this test is running under run_tests.py. " |
||||
"Child process test binaries are located differently based on this flag. "); |
||||
|
||||
DEFINE_string(test_bin_name, "", |
||||
"Name, without the preceding path, of the test binary"); |
||||
|
||||
DEFINE_string(grpc_test_directory_relative_to_test_srcdir, "/__main__", |
||||
"This flag only applies if runner_under_bazel is true. This " |
||||
"flag is ignored if runner_under_bazel is false. " |
||||
"Directory of the <repo-root>/test directory relative to bazel's " |
||||
"TEST_SRCDIR environment variable"); |
||||
|
||||
using grpc::SubProcess; |
||||
|
||||
static volatile sig_atomic_t abort_wait_for_child = 0; |
||||
|
||||
static void sighandler(int sig) { abort_wait_for_child = 1; } |
||||
|
||||
static void register_sighandler() { |
||||
struct sigaction act; |
||||
memset(&act, 0, sizeof(act)); |
||||
act.sa_handler = sighandler; |
||||
sigaction(SIGINT, &act, NULL); |
||||
sigaction(SIGTERM, &act, NULL); |
||||
} |
||||
|
||||
namespace { |
||||
|
||||
const int kTestTimeoutSeconds = 60 * 2; |
||||
|
||||
void RunSigHandlingThread(SubProcess *test_driver, gpr_mu *test_driver_mu, |
||||
gpr_cv *test_driver_cv, int *test_driver_done) { |
||||
gpr_timespec overall_deadline = |
||||
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), |
||||
gpr_time_from_seconds(kTestTimeoutSeconds, GPR_TIMESPAN)); |
||||
while (true) { |
||||
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); |
||||
if (gpr_time_cmp(now, overall_deadline) > 0 || abort_wait_for_child) break; |
||||
gpr_mu_lock(test_driver_mu); |
||||
if (*test_driver_done) { |
||||
gpr_mu_unlock(test_driver_mu); |
||||
return; |
||||
} |
||||
gpr_timespec wait_deadline = gpr_time_add( |
||||
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(1, GPR_TIMESPAN)); |
||||
gpr_cv_wait(test_driver_cv, test_driver_mu, wait_deadline); |
||||
gpr_mu_unlock(test_driver_mu); |
||||
} |
||||
gpr_log(GPR_DEBUG, |
||||
"Test timeout reached or received signal. Interrupting test driver " |
||||
"child process."); |
||||
test_driver->Interrupt(); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
namespace grpc { |
||||
|
||||
namespace testing { |
||||
|
||||
void InvokeResolverComponentTestsRunner(std::string test_runner_bin_path, |
||||
std::string test_bin_path, |
||||
std::string dns_server_bin_path, |
||||
std::string records_config_path) { |
||||
int test_dns_server_port = grpc_pick_unused_port_or_die(); |
||||
|
||||
SubProcess *test_driver = new SubProcess( |
||||
{test_runner_bin_path, "--test_bin_path=" + test_bin_path, |
||||
"--dns_server_bin_path=" + dns_server_bin_path, |
||||
"--records_config_path=" + records_config_path, |
||||
"--test_dns_server_port=" + std::to_string(test_dns_server_port)}); |
||||
gpr_mu test_driver_mu; |
||||
gpr_mu_init(&test_driver_mu); |
||||
gpr_cv test_driver_cv; |
||||
gpr_cv_init(&test_driver_cv); |
||||
int test_driver_done = 0; |
||||
register_sighandler(); |
||||
std::thread sig_handling_thread(RunSigHandlingThread, test_driver, |
||||
&test_driver_mu, &test_driver_cv, |
||||
&test_driver_done); |
||||
int status = test_driver->Join(); |
||||
if (WIFEXITED(status)) { |
||||
if (WEXITSTATUS(status)) { |
||||
gpr_log(GPR_INFO, |
||||
"Resolver component test test-runner exited with code %d", |
||||
WEXITSTATUS(status)); |
||||
abort(); |
||||
} |
||||
} else if (WIFSIGNALED(status)) { |
||||
gpr_log(GPR_INFO, |
||||
"Resolver component test test-runner ended from signal %d", |
||||
WTERMSIG(status)); |
||||
abort(); |
||||
} else { |
||||
gpr_log(GPR_INFO, |
||||
"Resolver component test test-runner ended with unknown status %d", |
||||
status); |
||||
abort(); |
||||
} |
||||
gpr_mu_lock(&test_driver_mu); |
||||
test_driver_done = 1; |
||||
gpr_cv_signal(&test_driver_cv); |
||||
gpr_mu_unlock(&test_driver_mu); |
||||
sig_handling_thread.join(); |
||||
delete test_driver; |
||||
gpr_mu_destroy(&test_driver_mu); |
||||
gpr_cv_destroy(&test_driver_cv); |
||||
} |
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
int main(int argc, char **argv) { |
||||
grpc::testing::InitTest(&argc, &argv, true); |
||||
grpc_init(); |
||||
GPR_ASSERT(FLAGS_test_bin_name != ""); |
||||
std::string my_bin = argv[0]; |
||||
if (FLAGS_running_under_bazel) { |
||||
GPR_ASSERT(FLAGS_grpc_test_directory_relative_to_test_srcdir != ""); |
||||
// Use bazel's TEST_SRCDIR environment variable to locate the "test data"
|
||||
// binaries.
|
||||
std::string const bin_dir = |
||||
gpr_getenv("TEST_SRCDIR") + |
||||
FLAGS_grpc_test_directory_relative_to_test_srcdir + |
||||
std::string("/test/cpp/naming"); |
||||
// Invoke bazel's executeable links to the .sh and .py scripts (don't use
|
||||
// the .sh and .py suffixes) to make
|
||||
// sure that we're using bazel's test environment.
|
||||
grpc::testing::InvokeResolverComponentTestsRunner( |
||||
bin_dir + "/resolver_component_tests_runner", |
||||
bin_dir + "/" + FLAGS_test_bin_name, bin_dir + "/test_dns_server", |
||||
bin_dir + "/resolver_test_record_groups.yaml"); |
||||
} else { |
||||
// Get the current binary's directory relative to repo root to invoke the
|
||||
// correct build config (asan/tsan/dbg, etc.).
|
||||
std::string const bin_dir = my_bin.substr(0, my_bin.rfind('/')); |
||||
// Invoke the .sh and .py scripts directly where they are in source code.
|
||||
grpc::testing::InvokeResolverComponentTestsRunner( |
||||
"test/cpp/naming/resolver_component_tests_runner.sh", |
||||
bin_dir + "/" + FLAGS_test_bin_name, |
||||
"test/cpp/naming/test_dns_server.py", |
||||
"test/cpp/naming/resolver_test_record_groups.yaml"); |
||||
} |
||||
grpc_shutdown(); |
||||
return 0; |
||||
} |
@ -0,0 +1,155 @@ |
||||
resolver_component_tests_common_zone_name: resolver-tests.grpctestingexp. |
||||
resolver_component_tests: |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:1234', is_balancer: true} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: srv-ipv4-single-target |
||||
records: |
||||
_grpclb._tcp.srv-ipv4-single-target: |
||||
- {TTL: '2100', data: 0 0 1234 ipv4-single-target, type: SRV} |
||||
ipv4-single-target: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.5:1234', is_balancer: true} |
||||
- {address: '1.2.3.6:1234', is_balancer: true} |
||||
- {address: '1.2.3.7:1234', is_balancer: true} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: srv-ipv4-multi-target |
||||
records: |
||||
_grpclb._tcp.srv-ipv4-multi-target: |
||||
- {TTL: '2100', data: 0 0 1234 ipv4-multi-target, type: SRV} |
||||
ipv4-multi-target: |
||||
- {TTL: '2100', data: 1.2.3.5, type: A} |
||||
- {TTL: '2100', data: 1.2.3.6, type: A} |
||||
- {TTL: '2100', data: 1.2.3.7, type: A} |
||||
- expected_addrs: |
||||
- {address: '[2607:f8b0:400a:801::1001]:1234', is_balancer: true} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: srv-ipv6-single-target |
||||
records: |
||||
_grpclb._tcp.srv-ipv6-single-target: |
||||
- {TTL: '2100', data: 0 0 1234 ipv6-single-target, type: SRV} |
||||
ipv6-single-target: |
||||
- {TTL: '2100', data: '2607:f8b0:400a:801::1001', type: AAAA} |
||||
- expected_addrs: |
||||
- {address: '[2607:f8b0:400a:801::1002]:1234', is_balancer: true} |
||||
- {address: '[2607:f8b0:400a:801::1003]:1234', is_balancer: true} |
||||
- {address: '[2607:f8b0:400a:801::1004]:1234', is_balancer: true} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: srv-ipv6-multi-target |
||||
records: |
||||
_grpclb._tcp.srv-ipv6-multi-target: |
||||
- {TTL: '2100', data: 0 0 1234 ipv6-multi-target, type: SRV} |
||||
ipv6-multi-target: |
||||
- {TTL: '2100', data: '2607:f8b0:400a:801::1002', type: AAAA} |
||||
- {TTL: '2100', data: '2607:f8b0:400a:801::1003', type: AAAA} |
||||
- {TTL: '2100', data: '2607:f8b0:400a:801::1004', type: AAAA} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:1234', is_balancer: true} |
||||
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}' |
||||
expected_lb_policy: round_robin |
||||
record_to_resolve: srv-ipv4-simple-service-config |
||||
records: |
||||
_grpclb._tcp.srv-ipv4-simple-service-config: |
||||
- {TTL: '2100', data: 0 0 1234 ipv4-simple-service-config, type: SRV} |
||||
ipv4-simple-service-config: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
srv-ipv4-simple-service-config: |
||||
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}}]', |
||||
type: TXT} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:443', is_balancer: false} |
||||
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}' |
||||
expected_lb_policy: round_robin |
||||
record_to_resolve: ipv4-no-srv-simple-service-config |
||||
records: |
||||
ipv4-no-srv-simple-service-config: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}}]', |
||||
type: TXT} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:443', is_balancer: false} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: ipv4-no-config-for-cpp |
||||
records: |
||||
ipv4-no-config-for-cpp: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["python"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"PythonService","waitForReady":true}]}]}}]', |
||||
type: TXT} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:443', is_balancer: false} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: ipv4-cpp-config-has-zero-percentage |
||||
records: |
||||
ipv4-cpp-config-has-zero-percentage: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]', |
||||
type: TXT} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:443', is_balancer: false} |
||||
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}' |
||||
expected_lb_policy: round_robin |
||||
record_to_resolve: ipv4-second-language-is-cpp |
||||
records: |
||||
ipv4-second-language-is-cpp: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService","waitForReady":true}]}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]', |
||||
type: TXT} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:443', is_balancer: false} |
||||
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}' |
||||
expected_lb_policy: round_robin |
||||
record_to_resolve: ipv4-config-with-percentages |
||||
records: |
||||
ipv4-config-with-percentages: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NeverPickedService","waitForReady":true}]}]}},{"percentage":100,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}}]', |
||||
type: TXT} |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:1234', is_balancer: true} |
||||
- {address: '1.2.3.4:443', is_balancer: false} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: srv-ipv4-target-has-backend-and-balancer |
||||
records: |
||||
_grpclb._tcp.srv-ipv4-target-has-backend-and-balancer: |
||||
- {TTL: '2100', data: 0 0 1234 balancer-for-ipv4-has-backend-and-balancer, type: SRV} |
||||
balancer-for-ipv4-has-backend-and-balancer: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
srv-ipv4-target-has-backend-and-balancer: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- expected_addrs: |
||||
- {address: '[2607:f8b0:400a:801::1002]:1234', is_balancer: true} |
||||
- {address: '[2607:f8b0:400a:801::1002]:443', is_balancer: false} |
||||
expected_chosen_service_config: null |
||||
expected_lb_policy: null |
||||
record_to_resolve: srv-ipv6-target-has-backend-and-balancer |
||||
records: |
||||
_grpclb._tcp.srv-ipv6-target-has-backend-and-balancer: |
||||
- {TTL: '2100', data: 0 0 1234 balancer-for-ipv6-has-backend-and-balancer, type: SRV} |
||||
balancer-for-ipv6-has-backend-and-balancer: |
||||
- {TTL: '2100', data: '2607:f8b0:400a:801::1002', type: AAAA} |
||||
srv-ipv6-target-has-backend-and-balancer: |
||||
- {TTL: '2100', data: '2607:f8b0:400a:801::1002', type: AAAA} |
||||
|
||||
resolver_component_tests_TODO: |
||||
- 'TODO: enable this large-txt-record test once working. (it is much longer than 512 |
||||
bytes, likely to cause use of TCP even if max payload for UDP is changed somehow, |
||||
e.g. via notes in RFC 2671)' |
||||
- expected_addrs: |
||||
- {address: '1.2.3.4:443', is_balancer: false} |
||||
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}' |
||||
expected_lb_policy: null |
||||
record_to_resolve: srv-ipv6-target-has-backend-and-balancer |
||||
record_to_resolve: ipv4-config-causing-fallback-to-tcp |
||||
records: |
||||
ipv4-config-causing-fallback-to-tcp: |
||||
- {TTL: '2100', data: 1.2.3.4, type: A} |
||||
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}}]', |
||||
type: TXT} |
@ -0,0 +1,134 @@ |
||||
#!/usr/bin/env python2.7 |
||||
# 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. |
||||
|
||||
"""Starts a local DNS server for use in tests""" |
||||
|
||||
import argparse |
||||
import sys |
||||
import yaml |
||||
import signal |
||||
import os |
||||
|
||||
import twisted |
||||
import twisted.internet |
||||
import twisted.internet.reactor |
||||
import twisted.internet.threads |
||||
import twisted.internet.defer |
||||
import twisted.internet.protocol |
||||
import twisted.names |
||||
import twisted.names.client |
||||
import twisted.names.dns |
||||
import twisted.names.server |
||||
from twisted.names import client, server, common, authority, dns |
||||
import argparse |
||||
|
||||
_SERVER_HEALTH_CHECK_RECORD_NAME = 'health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp' # missing end '.' for twisted syntax |
||||
_SERVER_HEALTH_CHECK_RECORD_DATA = '123.123.123.123' |
||||
|
||||
class NoFileAuthority(authority.FileAuthority): |
||||
def __init__(self, soa, records): |
||||
# skip FileAuthority |
||||
common.ResolverBase.__init__(self) |
||||
self.soa = soa |
||||
self.records = records |
||||
|
||||
def start_local_dns_server(args): |
||||
all_records = {} |
||||
def _push_record(name, r): |
||||
print('pushing record: |%s|' % name) |
||||
if all_records.get(name) is not None: |
||||
all_records[name].append(r) |
||||
return |
||||
all_records[name] = [r] |
||||
|
||||
def _maybe_split_up_txt_data(name, txt_data, r_ttl): |
||||
start = 0 |
||||
txt_data_list = [] |
||||
while len(txt_data[start:]) > 0: |
||||
next_read = len(txt_data[start:]) |
||||
if next_read > 255: |
||||
next_read = 255 |
||||
txt_data_list.append(txt_data[start:start+next_read]) |
||||
start += next_read |
||||
_push_record(name, dns.Record_TXT(*txt_data_list, ttl=r_ttl)) |
||||
|
||||
with open(args.records_config_path) as config: |
||||
test_records_config = yaml.load(config) |
||||
common_zone_name = test_records_config['resolver_component_tests_common_zone_name'] |
||||
for group in test_records_config['resolver_component_tests']: |
||||
for name in group['records'].keys(): |
||||
for record in group['records'][name]: |
||||
r_type = record['type'] |
||||
r_data = record['data'] |
||||
r_ttl = int(record['TTL']) |
||||
record_full_name = '%s.%s' % (name, common_zone_name) |
||||
assert record_full_name[-1] == '.' |
||||
record_full_name = record_full_name[:-1] |
||||
if r_type == 'A': |
||||
_push_record(record_full_name, dns.Record_A(r_data, ttl=r_ttl)) |
||||
if r_type == 'AAAA': |
||||
_push_record(record_full_name, dns.Record_AAAA(r_data, ttl=r_ttl)) |
||||
if r_type == 'SRV': |
||||
p, w, port, target = r_data.split(' ') |
||||
p = int(p) |
||||
w = int(w) |
||||
port = int(port) |
||||
target_full_name = '%s.%s' % (target, common_zone_name) |
||||
r_data = '%s %s %s %s' % (p, w, port, target_full_name) |
||||
_push_record(record_full_name, dns.Record_SRV(p, w, port, target_full_name, ttl=r_ttl)) |
||||
if r_type == 'TXT': |
||||
_maybe_split_up_txt_data(record_full_name, r_data, r_ttl) |
||||
# Server health check record |
||||
_push_record(_SERVER_HEALTH_CHECK_RECORD_NAME, dns.Record_A(_SERVER_HEALTH_CHECK_RECORD_DATA, ttl=0)) |
||||
soa_record = dns.Record_SOA(mname = common_zone_name) |
||||
test_domain_com = NoFileAuthority( |
||||
soa = (common_zone_name, soa_record), |
||||
records = all_records, |
||||
) |
||||
server = twisted.names.server.DNSServerFactory( |
||||
authorities=[test_domain_com], verbose=2) |
||||
server.noisy = 2 |
||||
twisted.internet.reactor.listenTCP(args.port, server) |
||||
dns_proto = twisted.names.dns.DNSDatagramProtocol(server) |
||||
dns_proto.noisy = 2 |
||||
twisted.internet.reactor.listenUDP(args.port, dns_proto) |
||||
print('starting local dns server on 127.0.0.1:%s' % args.port) |
||||
print('starting twisted.internet.reactor') |
||||
twisted.internet.reactor.suggestThreadPoolSize(1) |
||||
twisted.internet.reactor.run() |
||||
|
||||
def _quit_on_signal(signum, _frame): |
||||
print('Received SIGNAL %d. Quitting with exit code 0' % signum) |
||||
twisted.internet.reactor.stop() |
||||
sys.stdout.flush() |
||||
sys.exit(0) |
||||
|
||||
def main(): |
||||
argp = argparse.ArgumentParser(description='Local DNS Server for resolver tests') |
||||
argp.add_argument('-p', '--port', default=None, type=int, |
||||
help='Port for DNS server to listen on for TCP and UDP.') |
||||
argp.add_argument('-r', '--records_config_path', default=None, type=str, |
||||
help=('Directory of resolver_test_record_groups.yaml file. ' |
||||
'Defauls to path needed when the test is invoked as part of run_tests.py.')) |
||||
args = argp.parse_args() |
||||
signal.signal(signal.SIGALRM, _quit_on_signal) |
||||
signal.signal(signal.SIGTERM, _quit_on_signal) |
||||
signal.signal(signal.SIGINT, _quit_on_signal) |
||||
# Prevent zombies. Tests that use this server are short-lived. |
||||
signal.alarm(2 * 60) |
||||
start_local_dns_server(args) |
||||
|
||||
if __name__ == '__main__': |
||||
main() |
@ -0,0 +1,38 @@ |
||||
#!/usr/bin/env bash |
||||
# Copyright 2017 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. |
||||
# |
||||
# This script is invoked by Jenkins and runs a diff on the microbenchmarks |
||||
set -ex |
||||
|
||||
# List of benchmarks that provide good signal for analyzing performance changes in pull requests |
||||
BENCHMARKS_TO_RUN="bm_fullstack_unary_ping_pong bm_fullstack_streaming_ping_pong bm_fullstack_streaming_pump bm_closure bm_cq bm_call_create bm_error bm_chttp2_hpack bm_chttp2_transport bm_pollset bm_metadata" |
||||
|
||||
# Enter the gRPC repo root |
||||
cd $(dirname $0)/../../.. |
||||
|
||||
source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc |
||||
|
||||
tools/run_tests/start_port_server.py |
||||
tools/jenkins/run_c_cpp_test.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \ |
||||
-d origin/$ghprbTargetBranch \ |
||||
-b $BENCHMARKS_TO_RUN || FAILED="true" |
||||
|
||||
# kill port_server.py to prevent the build from hanging |
||||
ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9 |
||||
|
||||
if [ "$FAILED" != "" ] |
||||
then |
||||
exit 1 |
||||
fi |
@ -0,0 +1,42 @@ |
||||
#!/usr/bin/env bash |
||||
# Copyright 2017 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. |
||||
# |
||||
# This script is invoked by Jenkins and runs a diff on the microbenchmarks |
||||
set -ex |
||||
|
||||
# List of benchmarks that provide good signal for analyzing performance changes in pull requests |
||||
BENCHMARKS_TO_RUN="cli_transport_stalls_per_iteration cli_stream_stalls_per_iteration svr_transport_stalls_per_iteration svr_stream_stalls_per_iteration" |
||||
|
||||
# Enter the gRPC repo root |
||||
cd $(dirname $0)/../../.. |
||||
|
||||
source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc |
||||
|
||||
tools/run_tests/start_port_server.py |
||||
tools/jenkins/run_c_cpp_test.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \ |
||||
-d origin/$ghprbTargetBranch \ |
||||
-b bm_fullstack_trickle \ |
||||
-l 4 \ |
||||
-t $BENCHMARKS_TO_RUN \ |
||||
--no-counters \ |
||||
--pr_comment_name trickle || FAILED="true" |
||||
|
||||
# kill port_server.py to prevent the build from hanging |
||||
ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9 |
||||
|
||||
if [ "$FAILED" != "" ] |
||||
then |
||||
exit 1 |
||||
fi |
Loading…
Reference in new issue