diff --git a/.bazelrc b/.bazelrc index 0b9d8ff54..e48c98831 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,17 +1,28 @@ -# The following .bazelrc content is forked from the main Envoy repository. This is necessary since +# The following .bazelrc content is forked from the main Envoy repository. This is necessary since # this needs to be available before we can access the Envoy repository contents via Bazel. # Envoy specific Bazel build/test options. -# Bazel doesn't need more than 200MB of memory based on memory profiling: +# Bazel doesn't need more than 200MB of memory for local build based on memory profiling: # https://docs.bazel.build/versions/master/skylark/performance.html#memory-profiling +# The default JVM max heapsize is 1/4 of physical memory up to 32GB which could be large +# enough to consume all memory constrained by cgroup in large host, which is the case in CircleCI. # Limiting JVM heapsize here to let it do GC more when approaching the limit to # leave room for compiler/linker. -startup --host_jvm_args=-Xmx512m +# The number 2G is choosed heuristically to both support in CircleCI and large enough for RBE. +# Startup options cannot be selected via config. +startup --host_jvm_args=-Xmx2g + build --workspace_status_command=bazel/get_workspace_status build --experimental_remap_main_repo +build --experimental_local_memory_estimate +build --host_force_python=PY2 +build --action_env=BAZEL_LINKLIBS=-l%:libstdc++.a +build --action_env=BAZEL_LINKOPTS=-lm:-static-libgcc # Basic ASAN/UBSAN that works for gcc +build:asan --action_env=BAZEL_LINKLIBS= +build:asan --action_env=BAZEL_LINKOPTS=-lstdc++:-lm build:asan --define ENVOY_CONFIG_ASAN=1 build:asan --copt -fsanitize=address,undefined build:asan --linkopt -fsanitize=address,undefined @@ -43,6 +54,7 @@ build:clang-tsan --define ENVOY_CONFIG_TSAN=1 build:clang-tsan --copt -fsanitize=thread build:clang-tsan --linkopt -fsanitize=thread build:clang-tsan --linkopt -fuse-ld=lld +build:clang-tsan --linkopt -static-libsan build:clang-tsan --define tcmalloc=disabled # Needed due to https://github.com/libevent/libevent/issues/777 build:clang-tsan --copt -DEVENT__DISABLE_DEBUG_MODE @@ -61,8 +73,55 @@ build:clang-msan --copt -fsanitize-memory-track-origins=2 build:libc++ --action_env=CC build:libc++ --action_env=CXX build:libc++ --action_env=CXXFLAGS=-stdlib=libc++ +build:libc++ --action_env=BAZEL_CXXOPTS=-stdlib=libc++ +build:libc++ --action_env=BAZEL_LINKLIBS=-l%:libc++.a:-l%:libc++abi.a:-lm build:libc++ --action_env=PATH +build:libc++ --host_linkopt=-fuse-ld=lld build:libc++ --define force_libcpp=enabled +# Optimize build for binary size reduction. +build:sizeopt -c opt --copt -Os + # Test options -test --test_env=HEAPCHECK=normal --test_env=PPROF_PATH +build --test_env=HEAPCHECK=normal --test_env=PPROF_PATH + +# Remote execution: https://docs.bazel.build/versions/master/remote-execution.html +build:rbe-toolchain --host_javabase=@rbe_ubuntu_clang//java:jdk +build:rbe-toolchain --javabase=@rbe_ubuntu_clang//java:jdk +build:rbe-toolchain --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 +build:rbe-toolchain --java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 +build:rbe-toolchain --host_platform=@envoy//bazel/toolchains:rbe_ubuntu_clang_platform +build:rbe-toolchain --platforms=@envoy//bazel/toolchains:rbe_ubuntu_clang_platform +build:rbe-toolchain --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 +build:rbe-toolchain --crosstool_top=@rbe_ubuntu_clang//cc:toolchain +build:rbe-toolchain --extra_toolchains=@rbe_ubuntu_clang//config:cc-toolchain +build:rbe-toolchain --linkopt=-fuse-ld=lld +build:rbe-toolchain --action_env=CC=clang --action_env=CXX=clang++ --action_env=PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/llvm-8/bin + +build:remote --spawn_strategy=remote,sandboxed,local +build:remote --strategy=Javac=remote,sandboxed,local +build:remote --strategy=Closure=remote,sandboxed,local +build:remote --strategy=Genrule=remote,sandboxed,local +build:remote --remote_timeout=3600 +build:remote --auth_enabled=true +build:remote --experimental_inmemory_jdeps_files +build:remote --experimental_inmemory_dotd_files +build:remote --experimental_remote_download_outputs=toplevel +test:remote --experimental_remote_download_outputs=minimal + +build:remote-clang --config=remote +build:remote-clang --config=rbe-toolchain + +# Docker sandbox +build:docker-sandbox --experimental_docker_image=envoyproxy/envoy-build:cfc514546bc0284536893cca5fa43d7128edcd35 +build:docker-sandbox --spawn_strategy=docker +build:docker-sandbox --strategy=Javac=docker +build:docker-sandbox --strategy=Closure=docker +build:docker-sandbox --strategy=Genrule=docker +build:docker-sandbox --define=EXECUTOR=remote +build:docker-sandbox --experimental_docker_verbose +build:docker-sandbox --experimental_enable_docker_sandbox + +build:docker-clang --config=docker-sandbox +build:docker-clang --config=rbe-toolchain + diff --git a/.circleci/config.yml b/.circleci/config.yml index 94552fad6..4a102e52f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ references: envoy-build-image: &envoy-build-image - envoyproxy/envoy-build:d0cefa7f071dbd4ef24399c2db8656c3a5d8c3ef + envoyproxy/envoy-build:8246167b9d238797cbc6c03dccc9e3921c37617d version: 2 jobs: diff --git a/.gitignore b/.gitignore index 8b53bf503..19ef59f6d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,10 @@ generated/ .cmake .rnd .vscode/ +venv/* bazel.output.txt envoy/ *.pyc __pycache__ -tools/pyformat \ No newline at end of file +tools/pyformat +test/coverage/BUILD diff --git a/WORKSPACE b/WORKSPACE index dcde98112..fd0b828a0 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -4,26 +4,21 @@ load("//bazel:repositories.bzl", "nighthawk_dependencies") nighthawk_dependencies() +load("@envoy//bazel:api_binding.bzl", "envoy_api_binding") + +envoy_api_binding() + load("@envoy//bazel:api_repositories.bzl", "envoy_api_dependencies") envoy_api_dependencies() load("@envoy//bazel:repositories.bzl", "envoy_dependencies") -load("@envoy//bazel:cc_configure.bzl", "cc_configure") envoy_dependencies() -cc_configure() - -load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies") - -rules_foreign_cc_dependencies() - -load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") - -go_rules_dependencies() +load("@envoy//bazel:dependency_imports.bzl", "envoy_dependency_imports") -go_register_toolchains() +envoy_dependency_imports() # For PIP support: load("@io_bazel_rules_python//python:pip.bzl", "pip_import", "pip_repositories") diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 1007ba0d7..5af5323f8 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -1,7 +1,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -ENVOY_COMMIT = "2f569b9a8d3f0d7a43ffa69e3e5ba947cd3a9f8b" -ENVOY_SHA = "ec47fee6604468bc392937967415c736f19fb22129929881270a1635ad216d87" +ENVOY_COMMIT = "bdd6788f1e01787d015eabd9902f4b565e5dea98" +ENVOY_SHA = "a53022b5c985e4c8bb999f2bed40f66a8621aea44312c8fe2fee6d65cd824da8" RULES_PYTHON_COMMIT = "fdbb17a4118a1728d19e638a5291b4c4266ea5b8" RULES_PYTHON_SHA = "9a3d71e348da504a9c4c5e8abd4cb822f7afb32c613dc6ee8b8535333a81a938" diff --git a/ci/do_ci.sh b/ci/do_ci.sh index ccae0454b..fe99aec28 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -6,7 +6,7 @@ export BUILDIFIER_BIN="/usr/local/bin/buildifier" function do_build () { bazel build $BAZEL_BUILD_OPTIONS --verbose_failures=true //:nighthawk_client //:nighthawk_test_server \ - //:nighthawk_service + //:nighthawk_service } function do_test() { @@ -27,7 +27,17 @@ function do_clang_tidy() { } function do_coverage() { - ci/run_coverage.sh + setup_clang_toolchain + echo "bazel coverage build with tests ${TEST_TARGETS}" + + # Reduce the amount of memory Bazel tries to use to prevent it from launching too many subprocesses. + # This should prevent the system from running out of memory and killing tasks. See discussion on + # https://github.com/envoyproxy/envoy/pull/5611. + [ -z "$CIRCLECI" ] || export BAZEL_BUILD_OPTIONS="${BAZEL_BUILD_OPTIONS} --local_ram_resources=12288" + + export TEST_TARGETS="//test/..." + test/run_envoy_bazel_coverage.sh ${TEST_TARGETS} + exit 0 } function setup_gcc_toolchain() { @@ -96,14 +106,10 @@ if [ -n "$CIRCLECI" ]; then mv "${HOME:-/root}/.gitconfig" "${HOME:-/root}/.gitconfig_save" echo 1 fi - NUM_CPUS=8 - if [ "$1" == "coverage" ]; then - NUM_CPUS=6 - fi fi - if grep 'docker\|lxc' /proc/1/cgroup; then +if grep 'docker\|lxc' /proc/1/cgroup; then # Create a fake home. Python site libs tries to do getpwuid(3) if we don't and the CI # Docker image gets confused as it has no passwd entry when running non-root # unless we do this. @@ -136,10 +142,6 @@ export BAZEL_TEST_OPTIONS="${BAZEL_BUILD_OPTIONS} --test_env=HOME --test_env=PYT setup_clang_toolchain -if [ "$1" == "coverage" ]; then - setup_gcc_toolchain -fi - case "$1" in build) do_build diff --git a/ci/run_coverage.sh b/ci/run_coverage.sh deleted file mode 100755 index 625573ba9..000000000 --- a/ci/run_coverage.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -set -e - -[[ -z "${SRCDIR}" ]] && SRCDIR="${PWD}" -[[ -z "${BAZEL_COVERAGE}" ]] && BAZEL_COVERAGE=bazel -[[ -z "${VALIDATE_COVERAGE}" ]] && VALIDATE_COVERAGE=true - -# This is the target that will be run to generate coverage data. It can be overridden by consumer -# projects that want to run coverage on a different/combined target. -[[ -z "${COVERAGE_TARGET}" ]] && COVERAGE_TARGET="//test/..." - -bazel clean - -# Generate coverage data. -"${BAZEL_COVERAGE}" coverage ${BAZEL_TEST_OPTIONS} \ -"${COVERAGE_TARGET}" \ ---experimental_cc_coverage \ ---instrumentation_filter=//source/...,//include/... \ ---coverage_report_generator=@bazel_tools//tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator:Main \ ---combined_report=lcov - -# Generate HTML -declare -r COVERAGE_DIR="${SRCDIR}"/generated/coverage -declare -r COVERAGE_SUMMARY="${COVERAGE_DIR}/coverage_summary.txt" -mkdir -p "${COVERAGE_DIR}" -genhtml bazel-out/_coverage/_coverage_report.dat --output-directory="${COVERAGE_DIR}" | tee "${COVERAGE_SUMMARY}" - -[[ -z "${ENVOY_COVERAGE_DIR}" ]] || rsync -av "${COVERAGE_DIR}"/ "${ENVOY_COVERAGE_DIR}" - -if [ "$VALIDATE_COVERAGE" == "true" ] -then - COVERAGE_VALUE=$(grep -Po '.*lines[.]*: \K(\d|\.)*' "${COVERAGE_SUMMARY}") - # TODO(oschaaf): The target is 97.5%, so up this whenever possible in follow ups. - COVERAGE_THRESHOLD=97.3 - COVERAGE_FAILED=$(echo "${COVERAGE_VALUE}<${COVERAGE_THRESHOLD}" | bc) - - echo "HTML coverage report is in ${COVERAGE_DIR}/coverage.html" - - if test ${COVERAGE_FAILED} -eq 1; then - echo Code coverage ${COVERAGE_VALUE} is lower than limit of ${COVERAGE_THRESHOLD} - exit 1 - else - echo Code coverage ${COVERAGE_VALUE} is good and higher than limit of ${COVERAGE_THRESHOLD} - fi -fi diff --git a/include/nighthawk/client/benchmark_client.h b/include/nighthawk/client/benchmark_client.h index feb30ef51..c19695973 100644 --- a/include/nighthawk/client/benchmark_client.h +++ b/include/nighthawk/client/benchmark_client.h @@ -20,8 +20,9 @@ class BenchmarkClient { /** * Initialize will be called on the worker thread after it has started. * @param runtime to be used during initialization. + * @param thread local storage to be used. */ - virtual void initialize(Envoy::Runtime::Loader& runtime) PURE; + virtual void initialize(Envoy::Runtime::Loader& runtime, Envoy::ThreadLocal::Instance& tls) PURE; /** * Terminate will be called on the worker thread before it ends. diff --git a/integration/BUILD b/integration/BUILD index 8b39e4000..0f43e33c4 100644 --- a/integration/BUILD +++ b/integration/BUILD @@ -8,10 +8,12 @@ load("@python_pip_deps//:requirements.bzl", "requirement") envoy_package() -py_test( - name = "integration_test", +py_library( + name = "integration_test_base", srcs = [ - "integration_test.py", + "common.py", + "integration_test_fixtures.py", + "nighthawk_test_server.py", ], data = [ "configurations/nighthawk_http_origin.yaml", @@ -20,8 +22,6 @@ py_test( "//:nighthawk_test_server", "@envoy//test/config/integration/certs", ], - python_version = "PY3", - srcs_version = "PY3ONLY", deps = [ requirement("requests"), # The following are implied by 'request'. @@ -31,3 +31,24 @@ py_test( requirement("idna"), ], ) + +py_binary( + name = "cpp_benchmark_client_server", + srcs = [ + "cpp_benchmark_client_server.py", + ], + deps = [ + ":integration_test_base", + ], +) + +py_test( + name = "integration_test", + srcs = [ + "integration_test.py", + "test_integration_basics.py", + ], + deps = [ + ":integration_test_base", + ], +) diff --git a/integration/cpp_benchmark_client_server.py b/integration/cpp_benchmark_client_server.py new file mode 100644 index 000000000..5ff8a27b4 --- /dev/null +++ b/integration/cpp_benchmark_client_server.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"""@package integration_test.py +Entry point for our integration testing +""" + +import logging +import os +import sys +import unittest + +from common import IpVersion, NighthawkException +from integration_test_fixtures import (HttpIntegrationTestBase, HttpsIntegrationTestBase, + IntegrationTestBase) + +assert sys.version_info >= (3, 0) + +httpbase = None + + +def serverStartHook(ip_version, is_https): + IntegrationTestBase.ip_version = ip_version + logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) + global httpbase + + if is_https: + httpbase = HttpsIntegrationTestBase() + httpbase.overrideTestServerConfigPath("test/test_data/benchmark_https_client_test_envoy.yaml") + else: + httpbase = HttpIntegrationTestBase() + httpbase.overrideTestServerConfigPath("test/test_data/benchmark_http_client_test_envoy.yaml") + + httpbase.setUp() + return httpbase.server_port + + +def getRunningServerPid(): + return httpbase.getServerPid() + + +def waitForExit(): + return httpbase.waitForServerExit() + + +def main(): + if len(sys.argv) != 3: + print("cpp_benchmark_client_server.py [ipv4|ipv6] [http|https]") + return -1 + port = serverStartHook( + IpVersion.IPV6 if str.lower(sys.argv[1]) == "ipv6" else IpVersion.IPV4, + str.lower(sys.argv[2]) == "https") + print(str(port)) + print(str(getRunningServerPid())) + sys.stdout.flush() + return waitForExit() + + +if __name__ == '__main__': + main() diff --git a/integration/integration_test_fixtures.py b/integration/integration_test_fixtures.py index 79f3bbf5f..38b6eb6c3 100644 --- a/integration/integration_test_fixtures.py +++ b/integration/integration_test_fixtures.py @@ -35,6 +35,10 @@ def __init__(self, *args, **kwargs): self.server_port = -1 self.admin_port = -1 self.parameters = {} + self.parameters["test_rundir"] = self.test_rundir + + def overrideTestServerConfigPath(self, config_path): + self.nighthawk_test_config_path = os.path.join(self.test_rundir, config_path) # TODO(oschaaf): For the NH test server, add a way to let it determine a port by itself and pull that # out. @@ -55,7 +59,6 @@ def setUp(self): Performs sanity checks and starts up the server. Upon exit the server is ready to accept connections. """ self.assertTrue(os.path.exists(self.nighthawk_test_server_path)) - self.assertTrue(os.path.exists(self.nighthawk_client_path)) self.server_port = self.getFreeListenerPortForAddress(self.server_ip) self.admin_port = self.getFreeListenerPortForAddress(self.server_ip) self.parameters["admin_port"] = self.admin_port @@ -70,6 +73,12 @@ def tearDown(self): """ self.assertEqual(0, self.test_server.stop()) + def waitForServerExit(self): + return self.test_server.waitForExit() + + def getServerPid(self): + return self.test_server.getPid() + def getNighthawkCounterMapFromJson(self, parsed_json): """ Utility method to get the counters from the json indexed by name. @@ -121,6 +130,7 @@ def runNighthawkClient(self, args, expect_failure=False, timeout=30): Runs Nighthawk against the test server, returning a json-formatted result. If the timeout is exceeded an exception will be raised. """ + self.assertTrue(os.path.exists(self.nighthawk_client_path)) if IntegrationTestBase.ip_version == IpVersion.IPV6: args.insert(0, "--address-family v6") args.insert(0, "--output-format json") diff --git a/integration/nighthawk_test_server.py b/integration/nighthawk_test_server.py index ad8d28fe5..bf8f9c16c 100644 --- a/integration/nighthawk_test_server.py +++ b/integration/nighthawk_test_server.py @@ -43,7 +43,11 @@ def serverThreadRunner(self): parameterized_config_path = tmp.name tmp.write(config) - args = [self.server_binary_path, self.server_binary_config_path_arg, parameterized_config_path] + args = [ + self.server_binary_path, self.server_binary_config_path_arg, parameterized_config_path, + "--base-id", + str(self.server_port) + ] logging.info("Test server popen() args: [%s]" % args) self.server_process = subprocess.Popen(args) self.server_process.communicate() @@ -66,6 +70,13 @@ def start(self): self.server_thread.start() return self.waitUntilServerListening() + def waitForExit(self): + self.server_thread.join() + return self.server_process.returncode + + def getPid(self): + return self.server_process.pid + def stop(self): self.server_process.terminate() self.server_thread.join() diff --git a/source/client/benchmark_client_impl.cc b/source/client/benchmark_client_impl.cc index 1de45bbea..7a148a4a4 100644 --- a/source/client/benchmark_client_impl.cc +++ b/source/client/benchmark_client_impl.cc @@ -81,7 +81,8 @@ class H2Pool : public PrefetchablePool, public Envoy::Http::Http2::ProdConnPoolI void BenchmarkClientHttpImpl::prefetchPoolConnections() { pool_->prefetchConnections(); } -void BenchmarkClientHttpImpl::initialize(Envoy::Runtime::Loader& runtime) { +void BenchmarkClientHttpImpl::initialize(Envoy::Runtime::Loader& runtime, + Envoy::ThreadLocal::Instance& tls) { ASSERT(uri_->address() != nullptr); envoy::api::v2::Cluster cluster_config; envoy::api::v2::core::BindConfig bind_config; @@ -97,6 +98,12 @@ void BenchmarkClientHttpImpl::initialize(Envoy::Runtime::Loader& runtime) { thresholds->mutable_max_requests()->set_value(max_active_requests_); Envoy::Network::TransportSocketFactoryPtr socket_factory; + ssl_context_manager_ = + std::make_unique( + api_.timeSource()); + transport_socket_factory_context_ = std::make_unique( + store_.createScope("client."), dispatcher_, generator_, store_, api_, *ssl_context_manager_, + Envoy::ProtobufMessage::getStrictValidationVisitor(), tls); if (uri_->scheme() == "https") { auto common_tls_context = cluster_config.mutable_tls_context()->mutable_common_tls_context(); @@ -119,13 +126,6 @@ void BenchmarkClientHttpImpl::initialize(Envoy::Runtime::Loader& runtime) { Envoy::Server::Configuration::UpstreamTransportSocketConfigFactory>( transport_socket.name()); - ssl_context_manager_ = - std::make_unique( - api_.timeSource()); - transport_socket_factory_context_ = std::make_unique( - store_.createScope("client."), dispatcher_, generator_, store_, api_, *ssl_context_manager_, - Envoy::ProtobufMessage::getStrictValidationVisitor()); - Envoy::ProtobufTypes::MessagePtr message = Envoy::Config::Utility::translateToFactoryConfig( transport_socket, transport_socket_factory_context_->messageValidationVisitor(), config_factory); @@ -142,11 +142,10 @@ void BenchmarkClientHttpImpl::initialize(Envoy::Runtime::Loader& runtime) { socket_factory = std::make_unique(); }; - // TODO(oschaaf): pass in the right validation visitor. cluster_ = std::make_unique( cluster_config, bind_config, runtime, std::move(socket_factory), store_.createScope("client."), false /*added_via_api*/, - Envoy::ProtobufMessage::getStrictValidationVisitor()); + Envoy::ProtobufMessage::getStrictValidationVisitor(), *transport_socket_factory_context_); ASSERT(uri_->address() != nullptr); diff --git a/source/client/benchmark_client_impl.h b/source/client/benchmark_client_impl.h index c6cb5f33e..542402e9b 100644 --- a/source/client/benchmark_client_impl.h +++ b/source/client/benchmark_client_impl.h @@ -71,7 +71,7 @@ class BenchmarkClientHttpImpl : public BenchmarkClient, } // BenchmarkClient - void initialize(Envoy::Runtime::Loader& runtime) override; + void initialize(Envoy::Runtime::Loader& runtime, Envoy::ThreadLocal::Instance& tls) override; void terminate() override; StatisticPtrMap statistics() const override; bool measureLatencies() const override { return measure_latencies_; } diff --git a/source/client/client_worker_impl.cc b/source/client/client_worker_impl.cc index 2e97726ce..7a6980e7a 100644 --- a/source/client/client_worker_impl.cc +++ b/source/client/client_worker_impl.cc @@ -22,7 +22,7 @@ void ClientWorkerImpl::simpleWarmup() { } void ClientWorkerImpl::work() { - benchmark_client_->initialize(*Envoy::Runtime::LoaderSingleton::getExisting()); + benchmark_client_->initialize(*Envoy::Runtime::LoaderSingleton::getExisting(), tls_); simpleWarmup(); benchmark_client_->setMeasureLatencies(true); sequencer_->start(); diff --git a/source/client/process_impl.cc b/source/client/process_impl.cc index 80fdbdb7b..c6e3a8d77 100644 --- a/source/client/process_impl.cc +++ b/source/client/process_impl.cc @@ -19,7 +19,10 @@ #include "common/event/real_time_system.h" #include "common/filesystem/filesystem_impl.h" #include "common/frequency.h" +#include "common/init/manager_impl.h" +#include "common/local_info/local_info_impl.h" #include "common/network/utility.h" +#include "common/protobuf/message_validator_impl.h" #include "common/runtime/runtime_impl.h" #include "common/thread_local/thread_local_impl.h" #include "common/uri_impl.h" @@ -186,13 +189,17 @@ bool ProcessImpl::run(OutputCollector& collector) { return false; } const std::vector& workers = createWorkers(uri, determineConcurrency()); - - bool ok = true; Envoy::Runtime::RandomGeneratorImpl generator; - Envoy::Runtime::ScopedLoaderSingleton loader( - Envoy::Runtime::LoaderPtr{new Envoy::Runtime::LoaderImpl( - *dispatcher_, tls_, {}, "foo-cluster", *store_, generator, api_)}); + auto local_info = Envoy::LocalInfo::LocalInfoImpl( + {}, Network::Utility::getLocalAddress(Envoy::Network::Address::IpVersion::v4), + "nighthawk_service_zone", "nighthawk_service_cluster", "nighthawk_service_node"); + Envoy::Init::ManagerImpl init_manager("nighthawk_init_manager"); + Envoy::Runtime::ScopedLoaderSingleton loader(Envoy::Runtime::LoaderPtr{ + new Envoy::Runtime::LoaderImpl(*dispatcher_, tls_, {}, local_info, init_manager, *store_, + generator, + Envoy::ProtobufMessage::getStrictValidationVisitor(), api_)}); + bool ok = true; for (auto& w : workers_) { w->start(); } diff --git a/source/common/BUILD b/source/common/BUILD index e94893b1f..b9f5d9126 100644 --- a/source/common/BUILD +++ b/source/common/BUILD @@ -13,6 +13,7 @@ envoy_cc_library( srcs = [ "rate_limiter_impl.cc", "sequencer_impl.cc", + "ssl.cc", "statistic_impl.cc", "uri_impl.cc", "utility.cc", diff --git a/source/common/rate_limiter_impl.cc b/source/common/rate_limiter_impl.cc index bc7f8a9b3..b75b86d37 100644 --- a/source/common/rate_limiter_impl.cc +++ b/source/common/rate_limiter_impl.cc @@ -52,7 +52,9 @@ void BurstingRateLimiter::releaseOne() { LinearRateLimiter::LinearRateLimiter(Envoy::TimeSource& time_source, const Frequency frequency) : time_source_(time_source), acquireable_count_(0), acquired_count_(0), frequency_(frequency) { - ASSERT(frequency.value() > 0, "Frequency must be > 0"); + if (frequency.value() <= 0) { + throw NighthawkException("Frequency must be > 0"); + } } bool LinearRateLimiter::tryAcquireOne() { diff --git a/source/common/ssl.cc b/source/common/ssl.cc new file mode 100644 index 000000000..b6564f79f --- /dev/null +++ b/source/common/ssl.cc @@ -0,0 +1,159 @@ +#include "common/ssl.h" + +namespace Nighthawk { +namespace Ssl { + +bool FakeAdmin::addHandler(const std::string&, const std::string&, Envoy::Server::Admin::HandlerCb, + bool, bool) { + return true; +}; + +bool FakeAdmin::removeHandler(const std::string&) { return true; }; + +const Envoy::Network::Socket& FakeAdmin::socket() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; }; + +Envoy::Server::ConfigTracker& FakeAdmin::getConfigTracker() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; }; + +void FakeAdmin::startHttpListener(const std::string&, const std::string&, + Envoy::Network::Address::InstanceConstSharedPtr, + const Envoy::Network::Socket::OptionsSharedPtr&, + Envoy::Stats::ScopePtr&&){}; + +Envoy::Http::Code FakeAdmin::request(absl::string_view, absl::string_view, Envoy::Http::HeaderMap&, + std::string&) { + return Envoy::Http::Code::OK; +}; + +void FakeAdmin::addListenerToHandler(Envoy::Network::ConnectionHandler*){}; + +bool FakeClusterManager::addOrUpdateCluster(const envoy::api::v2::Cluster&, const std::string&) { + return true; +} + +void FakeClusterManager::setInitializedCb(std::function) {} + +Envoy::Upstream::ClusterManager::ClusterInfoMap FakeClusterManager::clusters() { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +Envoy::Upstream::ThreadLocalCluster* FakeClusterManager::get(absl::string_view) { return nullptr; } + +Envoy::Http::ConnectionPool::Instance* + +FakeClusterManager::httpConnPoolForCluster(const std::string&, Envoy::Upstream::ResourcePriority, + Envoy::Http::Protocol, + Envoy::Upstream::LoadBalancerContext*) { + return nullptr; +} + +Envoy::Tcp::ConnectionPool::Instance* +FakeClusterManager::tcpConnPoolForCluster(const std::string&, Envoy::Upstream::ResourcePriority, + Envoy::Upstream::LoadBalancerContext*, + Envoy::Network::TransportSocketOptionsSharedPtr) { + return nullptr; +} + +Envoy::Upstream::Host::CreateConnectionData +FakeClusterManager::tcpConnForCluster(const std::string&, Envoy::Upstream::LoadBalancerContext*, + Envoy::Network::TransportSocketOptionsSharedPtr) { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +Envoy::Http::AsyncClient& FakeClusterManager::httpAsyncClientForCluster(const std::string&) { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +bool FakeClusterManager::removeCluster(const std::string&) { return true; } + +void FakeClusterManager::shutdown() {} + +const envoy::api::v2::core::BindConfig& FakeClusterManager::bindConfig() const { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +Envoy::Config::GrpcMux& FakeClusterManager::adsMux() { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + +Envoy::Grpc::AsyncClientManager& FakeClusterManager::grpcAsyncClientManager() { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +const std::string& FakeClusterManager::localClusterName() const { return foo_string_; } + +Envoy::Upstream::ClusterUpdateCallbacksHandlePtr +FakeClusterManager::addThreadLocalClusterUpdateCallbacks(Envoy::Upstream::ClusterUpdateCallbacks&) { + return nullptr; +} + +Envoy::Upstream::ClusterManagerFactory& FakeClusterManager::clusterManagerFactory() { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +Envoy::Config::SubscriptionFactory& FakeClusterManager::subscriptionFactory() { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +std::size_t FakeClusterManager::warmingClusterCount() const { return 0u; } + +MinimalTransportSocketFactoryContext::MinimalTransportSocketFactoryContext( + Envoy::Stats::ScopePtr&& stats_scope, Envoy::Event::Dispatcher& dispatcher, + Envoy::Runtime::RandomGenerator& random, Envoy::Stats::Store& stats, Envoy::Api::Api& api, + Envoy::Extensions::TransportSockets::Tls::ContextManagerImpl& ssl_context_manager, + Envoy::ProtobufMessage::ValidationVisitor& validation_visitor, + Envoy::ThreadLocal::Instance& tls) + : ssl_context_manager_(ssl_context_manager), stats_scope_(std::move(stats_scope)), + secret_manager_(config_tracker_), dispatcher_(dispatcher), random_(random), stats_(stats), + api_(api), validation_visitor_(validation_visitor), + local_info_({}, + Envoy::Network::Utility::getLocalAddress(Envoy::Network::Address::IpVersion::v4), + "nighthawk_service_zone", "nighthawk_service_cluster", "nighthawk_service_node"), + manager_(api_.threadFactory()), tls_(tls) {} + +Envoy::Server::Admin& MinimalTransportSocketFactoryContext::admin() { return admin_; } + +Envoy::Ssl::ContextManager& MinimalTransportSocketFactoryContext::sslContextManager() { + return ssl_context_manager_; +} + +Envoy::Stats::Scope& MinimalTransportSocketFactoryContext::statsScope() const { + return *stats_scope_; +} + +Envoy::Secret::SecretManager& MinimalTransportSocketFactoryContext::secretManager() { + return secret_manager_; +} + +Envoy::Upstream::ClusterManager& MinimalTransportSocketFactoryContext::clusterManager() { + return cluster_manager_; +} + +const Envoy::LocalInfo::LocalInfo& MinimalTransportSocketFactoryContext::localInfo() { + return local_info_; +} + +Envoy::Event::Dispatcher& MinimalTransportSocketFactoryContext::dispatcher() { return dispatcher_; } + +Envoy::Runtime::RandomGenerator& MinimalTransportSocketFactoryContext::random() { return random_; } + +Envoy::Stats::Store& MinimalTransportSocketFactoryContext::stats() { return stats_; } + +void MinimalTransportSocketFactoryContext::setInitManager(Envoy::Init::Manager&) {} + +Envoy::Init::Manager* MinimalTransportSocketFactoryContext::initManager() { return nullptr; } + +Envoy::Singleton::Manager& MinimalTransportSocketFactoryContext::singletonManager() { + return manager_; +} + +Envoy::ThreadLocal::SlotAllocator& MinimalTransportSocketFactoryContext::threadLocal() { + return tls_; +} + +Envoy::Api::Api& MinimalTransportSocketFactoryContext::api() { return api_; } + +Envoy::ProtobufMessage::ValidationVisitor& +MinimalTransportSocketFactoryContext::messageValidationVisitor() { + return validation_visitor_; +} + +} // namespace Ssl +} // namespace Nighthawk \ No newline at end of file diff --git a/source/common/ssl.h b/source/common/ssl.h index 2eff0bd21..2e26c10c7 100644 --- a/source/common/ssl.h +++ b/source/common/ssl.h @@ -5,8 +5,13 @@ #include "envoy/network/transport_socket.h" +#include "common/local_info/local_info_impl.h" +#include "common/network/utility.h" #include "common/secret/secret_manager_impl.h" +#include "common/singleton/manager_impl.h" +#include "common/thread_local/thread_local_impl.h" +#include "server/http/config_tracker_impl.h" #include "server/transport_socket_config_impl.h" #include "extensions/transport_sockets/tls/context_config_impl.h" @@ -17,6 +22,59 @@ namespace Nighthawk { namespace Ssl { +// Shim class that we aneed a concrete implementations for, but +// which isn't actually used. +class FakeAdmin : public Envoy::Server::Admin { +public: + bool addHandler(const std::string&, const std::string&, Envoy::Server::Admin::HandlerCb, bool, + bool) override; + bool removeHandler(const std::string&) override; + const Envoy::Network::Socket& socket() override; + Envoy::Server::ConfigTracker& getConfigTracker() override; + void startHttpListener(const std::string&, const std::string&, + Envoy::Network::Address::InstanceConstSharedPtr, + const Envoy::Network::Socket::OptionsSharedPtr&, + Envoy::Stats::ScopePtr&&) override; + Envoy::Http::Code request(absl::string_view, absl::string_view, Envoy::Http::HeaderMap&, + std::string&) override; + void addListenerToHandler(Envoy::Network::ConnectionHandler*) override; +}; + +// Shim class that we aneed a concrete implementations for, but +// which isn't actually used. +class FakeClusterManager : public Envoy::Upstream::ClusterManager { +public: + bool addOrUpdateCluster(const envoy::api::v2::Cluster&, const std::string&) override; + void setInitializedCb(std::function) override; + Envoy::Upstream::ClusterManager::ClusterInfoMap clusters() override; + Envoy::Upstream::ThreadLocalCluster* get(absl::string_view) override; + Envoy::Http::ConnectionPool::Instance* + httpConnPoolForCluster(const std::string&, Envoy::Upstream::ResourcePriority, + Envoy::Http::Protocol, Envoy::Upstream::LoadBalancerContext*) override; + Envoy::Tcp::ConnectionPool::Instance* + tcpConnPoolForCluster(const std::string&, Envoy::Upstream::ResourcePriority, + Envoy::Upstream::LoadBalancerContext*, + Envoy::Network::TransportSocketOptionsSharedPtr) override; + Envoy::Upstream::Host::CreateConnectionData + tcpConnForCluster(const std::string&, Envoy::Upstream::LoadBalancerContext*, + Envoy::Network::TransportSocketOptionsSharedPtr) override; + Envoy::Http::AsyncClient& httpAsyncClientForCluster(const std::string&) override; + bool removeCluster(const std::string&) override; + void shutdown() override; + const envoy::api::v2::core::BindConfig& bindConfig() const override; + Envoy::Config::GrpcMux& adsMux() override; + Envoy::Grpc::AsyncClientManager& grpcAsyncClientManager() override; + const std::string& localClusterName() const override; + Envoy::Upstream::ClusterUpdateCallbacksHandlePtr + addThreadLocalClusterUpdateCallbacks(Envoy::Upstream::ClusterUpdateCallbacks&) override; + Envoy::Upstream::ClusterManagerFactory& clusterManagerFactory() override; + Envoy::Config::SubscriptionFactory& subscriptionFactory() override; + std::size_t warmingClusterCount() const override; + +private: + std::string foo_string_; +}; + class MinimalTransportSocketFactoryContext : public Envoy::Server::Configuration::TransportSocketFactoryContext { public: @@ -24,52 +82,40 @@ class MinimalTransportSocketFactoryContext Envoy::Stats::ScopePtr&& stats_scope, Envoy::Event::Dispatcher& dispatcher, Envoy::Runtime::RandomGenerator& random, Envoy::Stats::Store& stats, Envoy::Api::Api& api, Envoy::Extensions::TransportSockets::Tls::ContextManagerImpl& ssl_context_manager, - Envoy::ProtobufMessage::ValidationVisitor& validation_visitor) - : ssl_context_manager_(ssl_context_manager), stats_scope_(std::move(stats_scope)), - dispatcher_(dispatcher), random_(random), stats_(stats), api_(api), - validation_visitor_(validation_visitor) {} - - Envoy::Server::Admin& admin() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - Envoy::Ssl::ContextManager& sslContextManager() override { return ssl_context_manager_; } - - Envoy::Stats::Scope& statsScope() const override { return *stats_scope_; } - - Envoy::Secret::SecretManager& secretManager() override { return secret_manager_; } - - Envoy::Upstream::ClusterManager& clusterManager() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - const Envoy::LocalInfo::LocalInfo& localInfo() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - Envoy::Event::Dispatcher& dispatcher() override { return dispatcher_; } - - Envoy::Runtime::RandomGenerator& random() override { return random_; } - - Envoy::Stats::Store& stats() override { return stats_; } - - void setInitManager(Envoy::Init::Manager&) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - Envoy::Init::Manager* initManager() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - Envoy::Singleton::Manager& singletonManager() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - Envoy::ThreadLocal::SlotAllocator& threadLocal() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - Envoy::Api::Api& api() override { return api_; } - - Envoy::ProtobufMessage::ValidationVisitor& messageValidationVisitor() override { - return validation_visitor_; - } + Envoy::ProtobufMessage::ValidationVisitor& validation_visitor, + Envoy::ThreadLocal::Instance& tls); + + Envoy::Server::Admin& admin() override; + Envoy::Ssl::ContextManager& sslContextManager() override; + Envoy::Stats::Scope& statsScope() const override; + Envoy::Secret::SecretManager& secretManager() override; + Envoy::Upstream::ClusterManager& clusterManager() override; + const Envoy::LocalInfo::LocalInfo& localInfo() override; + Envoy::Event::Dispatcher& dispatcher() override; + Envoy::Runtime::RandomGenerator& random() override; + Envoy::Stats::Store& stats() override; + void setInitManager(Envoy::Init::Manager&) override; + Envoy::Init::Manager* initManager() override; + Envoy::Singleton::Manager& singletonManager() override; + Envoy::ThreadLocal::SlotAllocator& threadLocal() override; + Envoy::Api::Api& api() override; + Envoy::ProtobufMessage::ValidationVisitor& messageValidationVisitor() override; private: Envoy::Extensions::TransportSockets::Tls::ContextManagerImpl& ssl_context_manager_; Envoy::Stats::ScopePtr stats_scope_; + Envoy::Server::ConfigTrackerImpl config_tracker_; Envoy::Secret::SecretManagerImpl secret_manager_; Envoy::Event::Dispatcher& dispatcher_; Envoy::Runtime::RandomGenerator& random_; Envoy::Stats::Store& stats_; Envoy::Api::Api& api_; Envoy::ProtobufMessage::ValidationVisitor& validation_visitor_; + FakeAdmin admin_; + FakeClusterManager cluster_manager_; + Envoy::LocalInfo::LocalInfoImpl local_info_; + Envoy::Singleton::ManagerImpl manager_; + Envoy::ThreadLocal::Instance& tls_; }; } // namespace Ssl diff --git a/source/common/uri_impl.cc b/source/common/uri_impl.cc index 30a148ba6..00f596888 100644 --- a/source/common/uri_impl.cc +++ b/source/common/uri_impl.cc @@ -60,13 +60,14 @@ bool UriImpl::performDnsLookup(Envoy::Event::Dispatcher& dispatcher, Envoy::Network::ActiveDnsQuery* active_dns_query_ = dns_resolver->resolve( hostname, dns_lookup_family, - [this, &dispatcher, &active_dns_query_]( - const std::list&& address_list) -> void { + [this, &dispatcher, + &active_dns_query_](std::list&& response) -> void { active_dns_query_ = nullptr; - if (!address_list.empty()) { - address_ = Envoy::Network::Utility::getAddressWithPort(*address_list.front(), port()); + if (!response.empty()) { + address_ = + Envoy::Network::Utility::getAddressWithPort(*response.front().address_, port()); ENVOY_LOG(debug, "DNS resolution complete for {} ({} entries, using {}).", - hostWithoutPort(), address_list.size(), address_->asString()); + hostWithoutPort(), response.size(), address_->asString()); } dispatcher.exit(); }); diff --git a/test/BUILD b/test/BUILD index 75c6bc615..26a91c1c3 100644 --- a/test/BUILD +++ b/test/BUILD @@ -37,6 +37,7 @@ envoy_cc_test( "sequencer_test.cc", "service_main_test.cc", "service_test.cc", + "ssl_test.cc", "statistic_test.cc", "stream_decoder_test.cc", "utility_test.cc", @@ -44,17 +45,20 @@ envoy_cc_test( ], data = [ "test_data/benchmark_http_client_test_envoy.yaml", + "test_data/benchmark_https_client_test_envoy.yaml", "test_data/hdr_proto_json.gold", "test_data/lorem_ipsum.txt", "test_data/output_collector.json.gold", "test_data/output_collector.txt.gold", "test_data/output_collector.yaml.gold", + "//integration:cpp_benchmark_client_server", "@envoy//test/config/integration/certs", "@envoy//test/test_common:thread_factory_for_test_lib", "@envoy_api//envoy/api/v2:cds_export_cc", ], repository = "@envoy", deps = [ + "//:nighthawk_test_server", "//source/client:nighthawk_client_lib", "//source/client:nighthawk_service_lib", "//test:nighthawk_mocks", @@ -66,6 +70,7 @@ envoy_cc_test( "@envoy//source/common/stats:isolated_store_lib", "@envoy//test/integration:integration_lib", "@envoy//test/mocks/event:event_mocks", + "@envoy//test/mocks/protobuf:protobuf_mocks", "@envoy//test/mocks/thread_local:thread_local_mocks", "@envoy//test/server:utility_lib", "@envoy//test/test_common:simulated_time_system_lib", diff --git a/test/benchmark_http_client_test.cc b/test/benchmark_http_client_test.cc index e1237d429..9921e36ad 100644 --- a/test/benchmark_http_client_test.cc +++ b/test/benchmark_http_client_test.cc @@ -27,6 +27,7 @@ #include "test/mocks/runtime/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/server/utility.h" +#include "test/test_common/test_time_system.h" #include "test/test_common/utility.h" #include "ares.h" @@ -37,37 +38,81 @@ using namespace testing; namespace Nighthawk { -class BenchmarkClientTestBase : public Envoy::BaseIntegrationTest, - public TestWithParam { +class PythonIntegrationTestBase : public TestWithParam { public: - BenchmarkClientTestBase() - : Envoy::BaseIntegrationTest(GetParam(), realTime(), BenchmarkClientTestBase::envoy_config), - api_(thread_factory_, store_, timeSystem(), file_system_), - dispatcher_(api_.allocateDispatcher()) {} + PythonIntegrationTestBase(const Envoy::Network::Address::IpVersion version) + : version_(version), pipe_(nullptr){}; + + void startPythonIntegrationWrapper(const bool use_https) { + std::string args; - static void SetUpTestCase() { - Envoy::Filesystem::InstanceImplPosix file_system; - envoy_config = file_system.fileReadToEnd(Envoy::TestEnvironment::runfilesPath( - "test/test_data/benchmark_http_client_test_envoy.yaml")); - envoy_config = Envoy::TestEnvironment::substitute(envoy_config); + if (GetParam() == Envoy::Network::Address::IpVersion::v4) { + args.append(" ipv4"); + } else { + args.append(" ipv6"); + } + args.append(" http"); + if (use_https) { + args.append("s"); + } + pipe_ = popen(Envoy::TestEnvironment::runfilesPath("integration/cpp_benchmark_client_server") + .append(args) + .c_str(), + "r"); + RELEASE_ASSERT(pipe_ != nullptr, "Failed to open pipe"); + RELEASE_ASSERT(fgets(buffer_.data(), buffer_.max_size(), pipe_) != nullptr, + "Expected more data"); + RELEASE_ASSERT(absl::SimpleAtoi(buffer_.data(), &server_port_), + "couldn't understand server_pid"); + RELEASE_ASSERT(fgets(buffer_.data(), buffer_.max_size(), pipe_) != nullptr, + "Expected more data"); + RELEASE_ASSERT(absl::SimpleAtoi(buffer_.data(), &server_pid_), + "couldn't understand server_pid"); + } + + void TearDown() override { + if (server_pid_ != 0) { + kill(server_pid_, SIGTERM); + } + if (pipe_ != nullptr) { + // We don't expect any output, lets print it when that happens + while (fgets(buffer_.data(), buffer_.max_size(), pipe_) != nullptr) { + std::cerr << "python stdout: " << buffer_.data() << std::endl; + } + RELEASE_ASSERT(!pclose(pipe_), "Failure closing pipe"); + } } + Envoy::Event::RealTimeSystem time_system_; // NO_CHECK_FORMAT(real_time) + const Envoy::Network::Address::IpVersion version_; + int server_port_{0}; + int server_pid_{0}; + std::array buffer_; + FILE* pipe_; +}; + +class BenchmarkClientTestBase : public PythonIntegrationTestBase { +public: + BenchmarkClientTestBase() + : PythonIntegrationTestBase(GetParam()), + api_(thread_factory_, store_, time_system_, file_system_), + dispatcher_(api_.allocateDispatcher()) {} + void SetUp() override { ares_library_init(ARES_LIB_INIT_ALL); Envoy::Event::Libevent::Global::initialize(); } void TearDown() override { + tls_.shutdownGlobalThreading(); + ares_library_cleanup(); if (client_ != nullptr) { client_->terminate(); } - test_server_.reset(); - fake_upstreams_.clear(); - tls_.shutdownGlobalThreading(); - ares_library_cleanup(); + PythonIntegrationTestBase::TearDown(); } - uint32_t getTestServerHostAndPort() { return lookupPort("listener_0"); } + uint32_t getTestServerHostAndPort() { return server_port_; } void testBasicFunctionality(absl::string_view uriPath, const uint64_t max_pending, const uint64_t connection_limit, const bool use_h2, @@ -77,7 +122,7 @@ class BenchmarkClientTestBase : public Envoy::BaseIntegrationTest, client_->setConnectionTimeout(10s); client_->setMaxPendingRequests(max_pending); client_->setConnectionLimit(connection_limit); - client_->initialize(runtime_); + client_->initialize(runtime_, tls_); const uint64_t amount = amount_of_request; uint64_t inflight_response_count = 0; @@ -138,12 +183,14 @@ class BenchmarkClientTestBase : public Envoy::BaseIntegrationTest, NiceMock runtime_; std::unique_ptr client_; Envoy::Filesystem::InstanceImplPosix file_system_; - static std::string envoy_config; }; class BenchmarkClientHttpTest : public BenchmarkClientTestBase { public: - void SetUp() override { BenchmarkClientHttpTest::initialize(); } + void SetUp() override { + BenchmarkClientTestBase::SetUp(); + startPythonIntegrationWrapper(false); + } void setupBenchmarkClient(absl::string_view uriPath, bool use_h2, bool prefetch_connections) override { @@ -153,45 +200,17 @@ class BenchmarkClientHttpTest : public BenchmarkClientTestBase { class BenchmarkClientHttpsTest : public BenchmarkClientTestBase { public: - void SetUp() override { BenchmarkClientHttpsTest::initialize(); } + void SetUp() override { + BenchmarkClientTestBase::SetUp(); + startPythonIntegrationWrapper(true); + } void setupBenchmarkClient(absl::string_view uriPath, bool use_h2, bool prefetch_connections) override { doSetupBenchmarkClient(uriPath, true, use_h2, prefetch_connections); }; - - void initialize() override { - config_helper_.addConfigModifier([](envoy::config::bootstrap::v2::Bootstrap& bootstrap) { - auto* common_tls_context = bootstrap.mutable_static_resources() - ->mutable_listeners(0) - ->mutable_filter_chains(0) - ->mutable_tls_context() - ->mutable_common_tls_context(); - common_tls_context->mutable_validation_context_sds_secret_config()->set_name( - "validation_context"); - common_tls_context->add_tls_certificate_sds_secret_configs()->set_name("server_cert"); - - auto* secret = bootstrap.mutable_static_resources()->add_secrets(); - secret->set_name("validation_context"); - auto* validation_context = secret->mutable_validation_context(); - validation_context->mutable_trusted_ca()->set_filename(Envoy::TestEnvironment::runfilesPath( - "external/envoy/test/config/integration/certs/cacert.pem")); - secret = bootstrap.mutable_static_resources()->add_secrets(); - secret->set_name("server_cert"); - auto* tls_certificate = secret->mutable_tls_certificate(); - tls_certificate->mutable_certificate_chain()->set_filename( - Envoy::TestEnvironment::runfilesPath( - "external/envoy/test/config/integration/certs/servercert.pem")); - tls_certificate->mutable_private_key()->set_filename(Envoy::TestEnvironment::runfilesPath( - "external/envoy/test/config/integration/certs/serverkey.pem")); - }); - - BenchmarkClientTestBase::initialize(); - } }; -std::string BenchmarkClientTestBase::envoy_config; - INSTANTIATE_TEST_SUITE_P(IpVersions, BenchmarkClientHttpTest, ValuesIn(Envoy::TestEnvironment::getIpVersionsForTest()), Envoy::TestUtility::ipTestParamsToString); @@ -290,10 +309,19 @@ TEST_P(BenchmarkClientHttpTest, DISABLED_WeirdStatus) { EXPECT_EQ(7, nonZeroValuedCounterCount()); } -TEST_P(BenchmarkClientHttpTest, H1ConnectionFailure) { - // Kill the test server, so we can't connect. +class BenchmarkClientNoServerTest : public BenchmarkClientTestBase { +public: + void SetUp() override {} + void TearDown() override {} + + void setupBenchmarkClient(absl::string_view uriPath, bool use_h2, + bool prefetch_connections) override { + doSetupBenchmarkClient(uriPath, false, use_h2, prefetch_connections); + }; +}; + +TEST_P(BenchmarkClientNoServerTest, H1ConnectionFailure) { // We allow a single connection and no pending. We expect one connection failure. - test_server_.reset(); testBasicFunctionality("/lorem-ipsum-status-200", 1, 1, false, 10); EXPECT_EQ(1, getCounter("upstream_cx_connect_fail")); @@ -306,10 +334,8 @@ TEST_P(BenchmarkClientHttpTest, H1ConnectionFailure) { EXPECT_EQ(8, nonZeroValuedCounterCount()); } -TEST_P(BenchmarkClientHttpTest, H1MultiConnectionFailure) { - // Kill the test server, so we can't connect. +TEST_P(BenchmarkClientNoServerTest, H1MultiConnectionFailure) { // We allow ten connections and ten pending requests. We expect ten connection failures. - test_server_.reset(); testBasicFunctionality("/lorem-ipsum-status-200", 10, 10, false, 10); EXPECT_EQ(10, getCounter("upstream_cx_connect_fail")); @@ -325,7 +351,7 @@ TEST_P(BenchmarkClientHttpTest, H1MultiConnectionFailure) { TEST_P(BenchmarkClientHttpTest, EnableLatencyMeasurement) { setupBenchmarkClient("/", false, false); int callback_count = 0; - client_->initialize(runtime_); + client_->initialize(runtime_, tls_); EXPECT_EQ(false, client_->measureLatencies()); EXPECT_EQ(true, client_->tryStartOne([&]() { @@ -392,7 +418,7 @@ TEST_P(BenchmarkClientHttpTest, StatusTrackingInOnComplete) { TEST_P(BenchmarkClientHttpTest, ConnectionPrefetching) { setupBenchmarkClient("/", false, true); client_->setConnectionLimit(50); - client_->initialize(runtime_); + client_->initialize(runtime_, tls_); EXPECT_EQ(true, client_->tryStartOne([&]() { dispatcher_->exit(); })); dispatcher_->run(Envoy::Event::Dispatcher::RunType::Block); EXPECT_EQ(50, getCounter("upstream_cx_total")); @@ -410,7 +436,7 @@ TEST_P(BenchmarkClientHttpTest, CapRequestConcurrency) { client_->setMaxPendingRequests(requests); client_->setConnectionLimit(requests); client_->setMaxActiveRequests(1); - client_->initialize(runtime_); + client_->initialize(runtime_, tls_); std::function f = [this, &inflight_response_count]() { --inflight_response_count; @@ -438,7 +464,7 @@ TEST_P(BenchmarkClientHttpsTest, MaxRequestsPerConnection) { client_->setConnectionLimit(requests); client_->setMaxActiveRequests(1024); client_->setMaxRequestsPerConnection(1); - client_->initialize(runtime_); + client_->initialize(runtime_, tls_); std::function f = [this, &inflight_response_count]() { --inflight_response_count; @@ -471,7 +497,7 @@ TEST_P(BenchmarkClientHttpTest, RequestMethodPost) { "d", client_->requestHeaders().get(Envoy::Http::LowerCaseString("c"))->value().getStringView()); - client_->initialize(runtime_); + client_->initialize(runtime_, tls_); EXPECT_EQ(true, client_->tryStartOne([&]() { dispatcher_->exit(); })); dispatcher_->run(Envoy::Event::Dispatcher::RunType::Block); diff --git a/test/client_worker_test.cc b/test/client_worker_test.cc index 6f02b2177..8ff59c572 100644 --- a/test/client_worker_test.cc +++ b/test/client_worker_test.cc @@ -11,6 +11,9 @@ #include "client/client_worker_impl.h" #include "test/mocks.h" +#include "test/mocks/init/mocks.h" +#include "test/mocks/local_info/mocks.h" +#include "test/mocks/protobuf/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/test_common/thread_factory_for_test.h" @@ -25,9 +28,10 @@ class ClientWorkerTest : public Test { public: ClientWorkerTest() : api_(Envoy::Thread::threadFactoryForTest(), store_, time_system_, file_system_), - thread_id_(std::this_thread::get_id()), - loader_(Envoy::Runtime::LoaderPtr{new Envoy::Runtime::LoaderImpl( - dispatcher_, tls_, {}, "test-cluster", store_, rand_, api_)}) { + thread_id_(std::this_thread::get_id()) { + loader_ = std::make_unique(Envoy::Runtime::LoaderPtr{ + new Envoy::Runtime::LoaderImpl(dispatcher_, tls_, {}, local_info_, init_manager_, store_, + rand_, validation_visitor_, api_)}); benchmark_client_ = new MockBenchmarkClient(); sequencer_ = new MockSequencer(); @@ -65,8 +69,11 @@ class ClientWorkerTest : public Test { MockSequencer* sequencer_; Envoy::Runtime::RandomGeneratorImpl rand_; NiceMock dispatcher_; - Envoy::Runtime::ScopedLoaderSingleton loader_; Envoy::Filesystem::InstanceImplPosix file_system_; + std::unique_ptr loader_; + NiceMock local_info_; + Envoy::Init::MockManager init_manager_; + NiceMock validation_visitor_; }; TEST_F(ClientWorkerTest, BasicTest) { diff --git a/test/coverage/gen_build.sh b/test/coverage/gen_build.sh new file mode 100755 index 000000000..80d29af08 --- /dev/null +++ b/test/coverage/gen_build.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# Generate test/coverage/BUILD, which contains a single envoy_cc_test target +# that contains all C++ based tests suitable for performing the coverage run. A +# single binary (as opposed to multiple test targets) is require to work around +# the crazy in https://github.com/bazelbuild/bazel/issues/1118. This is used by +# the coverage runner script. + +set -e +set -x + +[ -z "${BAZEL_BIN}" ] && BAZEL_BIN=bazel +[ -z "${BUILDIFIER_BIN}" ] && BUILDIFIER_BIN=buildifier + +# Path to the generated BUILD file for the coverage target. +[ -z "${BUILD_PATH}" ] && BUILD_PATH="$(dirname "$0")"/BUILD + +# Extra repository information to include when generating coverage targets. This is useful for +# consuming projects. E.g., "@envoy". +[ -z "${REPOSITORY}" ] && REPOSITORY="" + +# This is an extra bazel path to query for additional targets. This is useful for consuming projects +# that want to run coverage over the public envoy code as well as private extensions. +# E.g., "//envoy-lyft/test/..." +[ -z "${EXTRA_QUERY_PATHS}" ] && EXTRA_QUERY_PATHS="" + +rm -f "${BUILD_PATH}" + +if [[ $# -gt 0 ]]; then + COVERAGE_TARGETS=$* +else + COVERAGE_TARGETS=//test/... +fi + +for target in ${COVERAGE_TARGETS}; do + TARGETS="$TARGETS $("${BAZEL_BIN}" query ${BAZEL_QUERY_OPTIONS} "attr('tags', 'coverage_test_lib', ${REPOSITORY}${target})" | grep "^//")" +done + +( + cat << EOF +# This file is generated by test/coverage/gen_build.sh automatically prior to +# coverage runs. It is under .gitignore. DO NOT EDIT, DO NOT CHECK IN. +load( + "@envoy//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +envoy_package() + +envoy_cc_test( + name = "coverage_tests", + repository = "@envoy", + deps = [ +EOF + for t in ${TARGETS} + do + echo " \"$t\"," + done + cat << EOF + ], + # no-remote due to https://github.com/bazelbuild/bazel/issues/4685 + tags = ["manual", "no-remote"], + coverage = False, + # Due to the nature of coverage_tests, the shard of coverage_tests are very uneven, some of + # shard can take 100s and some takes only 10s, so we use the maximum sharding to here to let + # Bazel scheduling them across CPU cores. + # Sharding can be disabled by --test_sharding_strategy=disabled. + shard_count = 50, +) +EOF + +) > "${BUILD_PATH}" + +echo "Generated coverage BUILD file at: ${BUILD_PATH}" +"${BUILDIFIER_BIN}" "${BUILD_PATH}" \ No newline at end of file diff --git a/test/mocks.h b/test/mocks.h index c850ab111..9e4efbdef 100644 --- a/test/mocks.h +++ b/test/mocks.h @@ -7,6 +7,7 @@ #include "envoy/common/time.h" #include "envoy/event/dispatcher.h" #include "envoy/stats/store.h" +#include "envoy/thread_local/thread_local.h" #include "nighthawk/client/benchmark_client.h" #include "nighthawk/client/factories.h" @@ -133,7 +134,7 @@ class MockBenchmarkClient : public Client::BenchmarkClient { public: MockBenchmarkClient(); - MOCK_METHOD1(initialize, void(Envoy::Runtime::Loader&)); + MOCK_METHOD2(initialize, void(Envoy::Runtime::Loader&, Envoy::ThreadLocal::Instance&)); MOCK_METHOD0(terminate, void()); MOCK_METHOD1(setMeasureLatencies, void(bool)); MOCK_CONST_METHOD0(statistics, StatisticPtrMap()); diff --git a/test/rate_limiter_test.cc b/test/rate_limiter_test.cc index 042fd9884..e45ad427f 100644 --- a/test/rate_limiter_test.cc +++ b/test/rate_limiter_test.cc @@ -37,7 +37,7 @@ TEST_F(RateLimiterTest, LinearRateLimiterTest) { TEST_F(RateLimiterTest, LinearRateLimiterInvalidArgumentTest) { Envoy::Event::SimulatedTimeSystem time_system; - ASSERT_DEATH(LinearRateLimiter rate_limiter(time_system, 0_Hz), "Frequency must be > 0"); + EXPECT_THROW(LinearRateLimiter rate_limiter(time_system, 0_Hz), NighthawkException); } TEST_F(RateLimiterTest, BurstingRateLimiterTest) { diff --git a/test/run_envoy_bazel_coverage.sh b/test/run_envoy_bazel_coverage.sh new file mode 100755 index 000000000..a14194dd0 --- /dev/null +++ b/test/run_envoy_bazel_coverage.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -e +set -x + +[[ -z "${SRCDIR}" ]] && SRCDIR="${PWD}" +[[ -z "${VALIDATE_COVERAGE}" ]] && VALIDATE_COVERAGE=true + +echo "Starting run_envoy_bazel_coverage.sh..." +echo " PWD=$(pwd)" +echo " SRCDIR=${SRCDIR}" +echo " VALIDATE_COVERAGE=${VALIDATE_COVERAGE}" + +# This is the target that will be run to generate coverage data. It can be overridden by consumer +# projects that want to run coverage on a different/combined target. +# Command-line arguments take precedence over ${COVERAGE_TARGET}. +if [[ $# -gt 0 ]]; then + COVERAGE_TARGETS=$* +elif [[ -n "${COVERAGE_TARGET}" ]]; then + COVERAGE_TARGETS=${COVERAGE_TARGET} +else + COVERAGE_TARGETS=//test/... +fi + +# Make sure //test/coverage:coverage_tests is up-to-date. +SCRIPT_DIR="$(realpath "$(dirname "$0")")" +"${SCRIPT_DIR}"/coverage/gen_build.sh ${COVERAGE_TARGETS} + +BAZEL_USE_LLVM_NATIVE_COVERAGE=1 GCOV=llvm-profdata bazel coverage ${BAZEL_BUILD_OPTIONS} \ + -c fastbuild --copt=-DNDEBUG --instrumentation_filter=//source/...,//include/... \ + --test_timeout=2000 --cxxopt="-DENVOY_CONFIG_COVERAGE=1" --test_output=errors \ + --test_arg="--log-path /dev/null" --test_arg="-l trace" --test_env=HEAPCHECK= \ + --test_env=ENVOY_IP_TEST_VERSIONS=v4only //test/coverage:coverage_tests + +COVERAGE_DIR="${SRCDIR}"/generated/coverage +mkdir -p "${COVERAGE_DIR}" + +COVERAGE_IGNORE_REGEX="(/external/|pb\.(validate\.)?(h|cc)|/chromium_url/|/test/|/tmp)" +COVERAGE_BINARY="bazel-bin/test/coverage/coverage_tests" +COVERAGE_DATA="${COVERAGE_DIR}/coverage.dat" + +echo "Merging coverage data..." +llvm-profdata merge -sparse -o ${COVERAGE_DATA} $(find -L bazel-out/k8-fastbuild/testlogs/test/coverage/coverage_tests/ -name coverage.dat) + +echo "Generating report..." +llvm-cov show "${COVERAGE_BINARY}" -instr-profile="${COVERAGE_DATA}" -Xdemangler=c++filt \ + -ignore-filename-regex="${COVERAGE_IGNORE_REGEX}" -output-dir=${COVERAGE_DIR} -format=html +sed -i -e 's|>proc/self/cwd/|>|g' "${COVERAGE_DIR}/index.html" +sed -i -e 's|>bazel-out/[^/]*/bin/\([^/]*\)/[^<]*/_virtual_includes/[^/]*|>\1|g' "${COVERAGE_DIR}/index.html" + +[[ -z "${ENVOY_COVERAGE_DIR}" ]] || rsync -av "${COVERAGE_DIR}"/ "${ENVOY_COVERAGE_DIR}" + +if [ "$VALIDATE_COVERAGE" == "true" ] +then + COVERAGE_VALUE=$(llvm-cov export "${COVERAGE_BINARY}" -instr-profile="${COVERAGE_DATA}" \ + -ignore-filename-regex="${COVERAGE_IGNORE_REGEX}" -summary-only | \ + python3 -c "import sys, json; print(json.load(sys.stdin)['data'][0]['totals']['lines']['percent'])") + COVERAGE_THRESHOLD=97.0 + COVERAGE_FAILED=$(echo "${COVERAGE_VALUE}<${COVERAGE_THRESHOLD}" | bc) + if test ${COVERAGE_FAILED} -eq 1; then + echo Code coverage ${COVERAGE_VALUE} is lower than limit of ${COVERAGE_THRESHOLD} + exit 1 + else + echo Code coverage ${COVERAGE_VALUE} is good and higher than limit of ${COVERAGE_THRESHOLD} + fi +fi +echo "HTML coverage report is in ${COVERAGE_DIR}/index.html" \ No newline at end of file diff --git a/test/server/http_test_server_filter_integration_test.cc b/test/server/http_test_server_filter_integration_test.cc index afac4c987..a1c41145f 100644 --- a/test/server/http_test_server_filter_integration_test.cc +++ b/test/server/http_test_server_filter_integration_test.cc @@ -142,8 +142,8 @@ name: test-server } }; -INSTANTIATE_TEST_CASE_P(IpVersions, HttpTestServerIntegrationTest, - ValuesIn(Envoy::TestEnvironment::getIpVersionsForTest())); +INSTANTIATE_TEST_SUITE_P(IpVersions, HttpTestServerIntegrationTest, + ValuesIn(Envoy::TestEnvironment::getIpVersionsForTest())); TEST_P(HttpTestServerIntegrationTest, TestNoHeaderConfig) { Envoy::BufferingStreamDecoderPtr response = @@ -211,8 +211,8 @@ name: test-server } }; -INSTANTIATE_TEST_CASE_P(IpVersions, HttpTestServerIntegrationNoConfigTest, - ValuesIn(Envoy::TestEnvironment::getIpVersionsForTest())); +INSTANTIATE_TEST_SUITE_P(IpVersions, HttpTestServerIntegrationNoConfigTest, + ValuesIn(Envoy::TestEnvironment::getIpVersionsForTest())); TEST_P(HttpTestServerIntegrationNoConfigTest, TestNoHeaderConfig) { Envoy::BufferingStreamDecoderPtr response = diff --git a/test/ssl_test.cc b/test/ssl_test.cc new file mode 100644 index 000000000..482db865f --- /dev/null +++ b/test/ssl_test.cc @@ -0,0 +1,90 @@ +#include + +#include "common/http/header_map_impl.h" +#include "common/ssl.h" + +#include "test/mocks/api/mocks.h" +#include "test/mocks/event/mocks.h" +#include "test/mocks/filesystem/mocks.h" +#include "test/mocks/thread_local/mocks.h" +#include "test/mocks/upstream/mocks.h" + +#include "gtest/gtest.h" + +using namespace testing; + +namespace Nighthawk { +namespace Ssl { + +class SslTest : public Test {}; + +TEST_F(SslTest, FakeAdminCoverage) { + FakeAdmin admin; + Envoy::Server::Admin::HandlerCb cb; + EXPECT_NO_FATAL_FAILURE(admin.addHandler("", "", cb, false, false)); + EXPECT_NO_FATAL_FAILURE(admin.removeHandler("")); + EXPECT_DEATH(admin.socket(), ""); + EXPECT_DEATH(admin.getConfigTracker(), ""); + EXPECT_NO_FATAL_FAILURE(admin.startHttpListener("", "", {}, {}, {})); + Envoy::Http::HeaderMapImpl map; + std::string foo; + EXPECT_NO_FATAL_FAILURE(admin.request("", "", map, foo)); + EXPECT_NO_FATAL_FAILURE(admin.addListenerToHandler(nullptr)); +} + +TEST_F(SslTest, FakeClusterManager) { + FakeClusterManager manager; + EXPECT_NO_FATAL_FAILURE(manager.addOrUpdateCluster({}, {})); + EXPECT_NO_FATAL_FAILURE(manager.setInitializedCb([]() {})); + EXPECT_DEATH(manager.clusters(), ""); + EXPECT_NO_FATAL_FAILURE(manager.get("")); + EXPECT_NO_FATAL_FAILURE(manager.httpConnPoolForCluster("", {}, {}, {})); + EXPECT_NO_FATAL_FAILURE(manager.tcpConnPoolForCluster("", {}, {}, {})); + EXPECT_DEATH(manager.tcpConnForCluster("", {}, {}), ""); + EXPECT_DEATH(manager.httpAsyncClientForCluster(""), ""); + EXPECT_NO_FATAL_FAILURE(manager.removeCluster("")); + EXPECT_NO_FATAL_FAILURE(manager.shutdown()); + EXPECT_DEATH(manager.bindConfig(), ""); + EXPECT_DEATH(manager.adsMux(), ""); + EXPECT_DEATH(manager.grpcAsyncClientManager(), ""); + EXPECT_NO_FATAL_FAILURE(manager.localClusterName()); + Envoy::Upstream::MockClusterUpdateCallbacks cb; + EXPECT_NO_FATAL_FAILURE(manager.addThreadLocalClusterUpdateCallbacks(cb)); + EXPECT_DEATH(manager.clusterManagerFactory(), ""); + EXPECT_DEATH(manager.subscriptionFactory(), ""); +} + +TEST_F(SslTest, MinimalTransportSocketFactoryContextTest) { + Envoy::Event::MockDispatcher dispatcher; + Envoy::Runtime::MockRandomGenerator random; + Envoy::Stats::IsolatedStoreImpl stats; + Envoy::Api::MockApi api; + Envoy::Extensions::TransportSockets::Tls::ContextManagerImpl ssl_context_manager( + api.timeSource()); + Envoy::ProtobufMessage::NullValidationVisitorImpl validation_visitor; + Envoy::ThreadLocal::MockInstance tls; + EXPECT_CALL(api, threadFactory()).WillOnce(ReturnRef(Envoy::Thread::threadFactoryForTest())); + + MinimalTransportSocketFactoryContext mtsfc(stats.createScope(""), dispatcher, random, stats, api, + ssl_context_manager, validation_visitor, tls); + + EXPECT_NO_FATAL_FAILURE(mtsfc.admin()); + EXPECT_EQ(&mtsfc.sslContextManager(), &ssl_context_manager); + EXPECT_NO_FATAL_FAILURE(mtsfc.statsScope()); + EXPECT_NO_FATAL_FAILURE(mtsfc.secretManager()); + EXPECT_NO_FATAL_FAILURE(mtsfc.clusterManager()); + EXPECT_NO_FATAL_FAILURE(mtsfc.localInfo()); + EXPECT_NO_FATAL_FAILURE(mtsfc.dispatcher()); + EXPECT_NO_FATAL_FAILURE(mtsfc.random()); + EXPECT_NO_FATAL_FAILURE(mtsfc.stats()); + Envoy::Init::ManagerImpl manager("test"); + EXPECT_NO_FATAL_FAILURE(mtsfc.setInitManager(manager)); + EXPECT_NO_FATAL_FAILURE(mtsfc.initManager()); + EXPECT_NO_FATAL_FAILURE(mtsfc.singletonManager()); + EXPECT_NO_FATAL_FAILURE(mtsfc.threadLocal()); + EXPECT_NO_FATAL_FAILURE(mtsfc.api()); + EXPECT_NO_FATAL_FAILURE(mtsfc.messageValidationVisitor()); +} + +} // namespace Ssl +} // namespace Nighthawk diff --git a/test/test_data/benchmark_http_client_test_envoy.yaml b/test/test_data/benchmark_http_client_test_envoy.yaml index bab05ffc9..1e777a824 100644 --- a/test/test_data/benchmark_http_client_test_envoy.yaml +++ b/test/test_data/benchmark_http_client_test_envoy.yaml @@ -2,21 +2,15 @@ admin: access_log_path: /dev/null address: socket_address: - address: {{ ip_loopback_address }} - port_value: 0 + address: $server_ip + port_value: $admin_port static_resources: - clusters: - name: cluster_0 - hosts: - socket_address: - address: {{ ip_loopback_address }} - port_value: 0 listeners: - name: listener_0 address: socket_address: - address: {{ ip_loopback_address }} - port_value: 0 + address: $server_ip + port_value: $server_port filter_chains: - filters: - name: envoy.http_connection_manager @@ -36,13 +30,13 @@ static_resources: direct_response: status: 200 body: - filename: {{ test_rundir }}/test/test_data/lorem_ipsum.txt + filename: $test_rundir/test/test_data/lorem_ipsum.txt - match: prefix: /404 direct_response: status: 404 body: - filename: {{ test_rundir }}/test/test_data/lorem_ipsum.txt + filename: $test_rundir/test/test_data/lorem_ipsum.txt http_filters: - name: envoy.router config: diff --git a/test/test_data/benchmark_https_client_test_envoy.yaml b/test/test_data/benchmark_https_client_test_envoy.yaml new file mode 100644 index 000000000..7ae59065b --- /dev/null +++ b/test/test_data/benchmark_https_client_test_envoy.yaml @@ -0,0 +1,50 @@ +admin: + access_log_path: /dev/null + address: + socket_address: + address: $server_ip + port_value: $admin_port +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + address: $server_ip + port_value: $server_port + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + generate_request_id: false + codec_type: auto + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: service + domains: + - "*" + routes: + - match: + prefix: /lorem-ipsum-status-200 + direct_response: + status: 200 + body: + filename: $test_rundir/test/test_data/lorem_ipsum.txt + - match: + prefix: /404 + direct_response: + status: 404 + body: + filename: $test_rundir/test/test_data/lorem_ipsum.txt + http_filters: + - name: envoy.router + config: + dynamic_stats: false + tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: + filename: $ssl_cert_path + private_key: + filename: $ssl_key_path \ No newline at end of file diff --git a/test/worker_test.cc b/test/worker_test.cc index 4da9b12e2..a7d8fe63f 100644 --- a/test/worker_test.cc +++ b/test/worker_test.cc @@ -7,6 +7,9 @@ #include "common/worker_impl.h" #include "test/mocks.h" +#include "test/mocks/init/mocks.h" +#include "test/mocks/local_info/mocks.h" +#include "test/mocks/protobuf/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/test_common/thread_factory_for_test.h" @@ -40,22 +43,24 @@ class WorkerTest : public Test { Envoy::Stats::IsolatedStoreImpl store_; Envoy::Event::TestRealTimeSystem time_system_; Envoy::Runtime::RandomGeneratorImpl rand_; + NiceMock local_info_; + Envoy::Init::MockManager init_manager_; + NiceMock validation_visitor_; }; TEST_F(WorkerTest, WorkerExecutesOnThread) { InSequence in_sequence; - EXPECT_CALL(tls_, registerThread(_, false)).Times(1); EXPECT_CALL(tls_, allocateSlot()).Times(1); TestWorker worker(api_, tls_); NiceMock dispatcher; - Envoy::Runtime::ScopedLoaderSingleton loader(Envoy::Runtime::LoaderPtr{ - new Envoy::Runtime::LoaderImpl(dispatcher, tls_, {}, "test-cluster", store_, rand_, api_)}); - + std::unique_ptr loader = + std::make_unique(Envoy::Runtime::LoaderPtr{ + new Envoy::Runtime::LoaderImpl(dispatcher, tls_, {}, local_info_, init_manager_, store_, + rand_, validation_visitor_, api_)}); worker.start(); worker.waitForCompletion(); - EXPECT_CALL(tls_, shutdownThread()).Times(1); ASSERT_TRUE(worker.ran_); }