diff --git a/test/tools/router_check/router.cc b/test/tools/router_check/router.cc index 6cf08738cd399..2178a1772c29b 100644 --- a/test/tools/router_check/router.cc +++ b/test/tools/router_check/router.cc @@ -329,6 +329,7 @@ RouterCheckTool::compareEntries(const std::string& expected_routes) { return this->compareRedirectPath(params..., stream_info); }, [this](auto&... params) -> bool { return this->compareRedirectCode(params...); }, + [this](auto&... params) -> bool { return this->compareTimeout(params...); }, [this](auto&... params) -> bool { return this->compareRequestHeaderFields(params...); }, [this](auto&... params) -> bool { return this->compareResponseHeaderFields(params...); }, }; @@ -528,6 +529,25 @@ bool RouterCheckTool::compareRedirectCode( return matches; } +bool RouterCheckTool::compareTimeout(ToolConfig& tool_config, + const envoy::RouterCheckToolSchema::ValidationAssert& expected, + envoy::RouterCheckToolSchema::ValidationFailure& failure) { + if (!expected.has_timeout()) { + return true; + } + const bool has_route_entry = + tool_config.route_ != nullptr && tool_config.route_->routeEntry() != nullptr; + const uint64_t actual = has_route_entry ? tool_config.route_->routeEntry()->timeout().count() : 0; + const uint64_t expected_ms = DurationUtil::durationToMilliseconds(expected.timeout()); + const bool matches = compareResults(actual, expected_ms, "timeout"); + if (!matches) { + *failure.mutable_expected_timeout() = expected.timeout(); + failure.mutable_actual_timeout()->set_seconds(actual / 1000); + failure.mutable_actual_timeout()->set_nanos((actual % 1000) * 1000000); + } + return matches; +} + bool RouterCheckTool::compareRequestHeaderFields( ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected, envoy::RouterCheckToolSchema::ValidationFailure& failure) { diff --git a/test/tools/router_check/router.h b/test/tools/router_check/router.h index 0c30edf5a7aeb..81f294b812b18 100644 --- a/test/tools/router_check/router.h +++ b/test/tools/router_check/router.h @@ -154,6 +154,9 @@ class RouterCheckTool : Logger::Loggable { bool compareRedirectCode(ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected, envoy::RouterCheckToolSchema::ValidationFailure& failure); + bool compareTimeout(ToolConfig& tool_config, + const envoy::RouterCheckToolSchema::ValidationAssert& expected, + envoy::RouterCheckToolSchema::ValidationFailure& failure); bool compareRequestHeaderFields(ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected, envoy::RouterCheckToolSchema::ValidationFailure& failure); diff --git a/test/tools/router_check/test/config/Timeout.golden.proto.json b/test/tools/router_check/test/config/Timeout.golden.proto.json new file mode 100644 index 0000000000000..2dfdb98ecc797 --- /dev/null +++ b/test/tools/router_check/test/config/Timeout.golden.proto.json @@ -0,0 +1,14 @@ +{ + "tests": [ + { + "test_name": "Test_1", + "input": {"authority": "www.example.com", "path": "/api/v1/resource", "method": "GET"}, + "validate": {"cluster_name": "service", "timeout": "120s"} + }, + { + "test_name": "Test_2", + "input": {"authority": "www.example.com", "path": "/other", "method": "GET"}, + "validate": {"cluster_name": "service", "timeout": "30s"} + } + ] +} diff --git a/test/tools/router_check/test/config/Timeout.yaml b/test/tools/router_check/test/config/Timeout.yaml new file mode 100644 index 0000000000000..deb59b84a4b58 --- /dev/null +++ b/test/tools/router_check/test/config/Timeout.yaml @@ -0,0 +1,17 @@ +virtual_hosts: +- name: www + domains: + - www.example.com + routes: + # Both routes use the same cluster; per-route timeouts are the only distinction. + - match: + safe_regex: + regex: "^/api/v[0-9]/.*" + route: + cluster: service + timeout: 120s + - match: + prefix: / + route: + cluster: service + timeout: 30s diff --git a/test/tools/router_check/test/config/TimeoutFailures.golden.proto.json b/test/tools/router_check/test/config/TimeoutFailures.golden.proto.json new file mode 100644 index 0000000000000..bef5f8866682b --- /dev/null +++ b/test/tools/router_check/test/config/TimeoutFailures.golden.proto.json @@ -0,0 +1,9 @@ +{ + "tests": [ + { + "test_name": "Test_1", + "input": {"authority": "www.example.com", "path": "/api/v10/resource", "method": "GET"}, + "validate": {"cluster_name": "service", "timeout": "120s"} + } + ] +} diff --git a/test/tools/router_check/test/route_tests.sh b/test/tools/router_check/test/route_tests.sh index c7eb2bee40190..e8628f7e9ffa2 100755 --- a/test/tools/router_check/test/route_tests.sh +++ b/test/tools/router_check/test/route_tests.sh @@ -8,7 +8,7 @@ PATH_BIN="${TEST_SRCDIR}/envoy"/test/tools/router_check/router_check_tool # Config json path PATH_CONFIG="${TEST_SRCDIR}/envoy"/test/tools/router_check/test/config -TESTS=("ContentType" "ClusterHeader" "DirectResponse" "HeaderMatchedRouting" "Redirect" "Redirect2" "Redirect3" "Redirect4" "Runtime" "TestRoutes" "Weighted") +TESTS=("ContentType" "ClusterHeader" "DirectResponse" "HeaderMatchedRouting" "Redirect" "Redirect2" "Redirect3" "Redirect4" "Runtime" "TestRoutes" "Timeout" "Weighted") # Testing expected matches for t in "${TESTS[@]}" @@ -104,6 +104,15 @@ if ! echo "${FAILURE_OUTPUT}" | grep -Fxq "expected: [has(x-pong-response):true] exit 1 fi +# Failure test case for timeout mismatch strings. +# The API regex matches only single-digit versions, so /api/v10/resource selects the fallback. +echo "testing timeout mismatch failure output" +TIMEOUT_FAILURE_OUTPUT=$("${PATH_BIN}" "-c" "${PATH_CONFIG}/Timeout.yaml" "-t" "${PATH_CONFIG}/TimeoutFailures.golden.proto.json" "--only-show-failures" 2>&1) || + echo "${TIMEOUT_FAILURE_OUTPUT:-no-output}" +if ! echo "${TIMEOUT_FAILURE_OUTPUT}" | grep -Fxq "expected: [120000], actual: [30000], test type: timeout"; then + exit 1 +fi + # Missing test results echo "testing missing tests output test cases" MISSING_OUTPUT=$("${PATH_BIN}" "-c" "${PATH_CONFIG}/TestRoutes.yaml" "-t" "${PATH_CONFIG}/TestRoutes.golden.proto.json" "--details" "--covall" 2>&1) || diff --git a/test/tools/router_check/validation.proto b/test/tools/router_check/validation.proto index e7fb0704607be..7cf5bbc8e1676 100644 --- a/test/tools/router_check/validation.proto +++ b/test/tools/router_check/validation.proto @@ -5,6 +5,7 @@ package envoy.RouterCheckToolSchema; import "envoy/config/core/v3/base.proto"; import "envoy/config/route/v3/route_components.proto"; import "envoy/extensions/filters/http/set_metadata/v3/set_metadata.proto"; +import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; @@ -118,6 +119,9 @@ message ValidationAssert { // Match the redirect response code google.protobuf.UInt32Value code_redirect = 13; + + // Match the matched route's per-route request timeout (RouteEntry::timeout()). + google.protobuf.Duration timeout = 14; } // The ValidationResult schema contains test results of the envoy router check tool. @@ -172,6 +176,10 @@ message ValidationFailure { google.protobuf.UInt32Value expected_code_redirect = 13; google.protobuf.UInt32Value actual_code_redirect = 14; + // Match the route timeout result. + google.protobuf.Duration expected_timeout = 17; + google.protobuf.Duration actual_timeout = 18; + // Match the request headers results. repeated HeaderMatchFailure request_header_match_failures = 15; // Match the response headers results.