Skip to content

Commit

Permalink
Enable proto schema for router_check_tool (#6992)
Browse files Browse the repository at this point in the history
Signed-off-by: Jyoti Mahapatra <jmahapatra@lyft.com>
  • Loading branch information
jyotima authored and mattklein123 committed May 22, 2019
1 parent f78295b commit cab4ce6
Show file tree
Hide file tree
Showing 20 changed files with 1,184 additions and 4 deletions.
15 changes: 14 additions & 1 deletion docs/root/install/tools/route_table_check_tool.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ Input
:ref:`config <config_tools_router_check_tool>`.
The tool config input file specifies urls (composed of authorities and paths)
and expected route parameter values. Additional parameters such as additional headers are optional.
Schema: All internal schemas in the tool are based on :repo:`proto3 <test/tools/router_check/validation.proto>`.
This is enabled by an extra optional parameter ``--useproto``. This parameter will become the default in the future releases and enables more validation features in the tool.
Any new feature addition in validations will be added behind this parameter.
Migration: If you are currently using the tool and plan to migrate to use ``--useproto``, change the yaml/json test's schema based on the :repo:`proto <test/tools/router_check/validation.proto>`.
Few known changes necessary are:
``:authority`` input is now ``authority``.
``:path`` input is now ``path``.
``:method`` input is now ``method``. This is a required property.
``additional_headers`` in the input along with ``header_fields`` and ``custom_header_fields`` contain ``key`` instead of ``field``.
``tests`` is a root level field in the yaml/json.

Output
The program exits with status EXIT_FAILURE if any test case does not match the expected route parameter
Expand Down Expand Up @@ -52,12 +62,15 @@ Running
expected order of command line arguments is:
1. The router configuration file.
2. The tool configuration json file.
3. The optional details flag. ::
3. ``--useproto`` to use any new features in the tool.
4. The optional details flag. ::

bazel-bin/test/tools/router_check/router_check_tool router_config.(yaml|json) tool_config.json

bazel-bin/test/tools/router_check/router_check_tool router_config.(yaml|json) tool_config.json --details

bazel-bin/test/tools/router_check/router_check_tool router_config.(yaml|json) tool_config.json --details --useproto

Testing
A bash shell script test can be run with bazel. The test compares routes using different router and
tool configuration files. The configuration files can be found in
Expand Down
1 change: 1 addition & 0 deletions docs/root/intro/deprecated.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Version 1.11.0 (Pending)
========================
* The --max-stats and --max-obj-name-len flags no longer has any effect.
* Use of :ref:`cluster <envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.cluster>` in :ref:`redis_proxy.proto <envoy_api_file_envoy/config/filter/network/redis_proxy/v2/redis_proxy.proto>` is deprecated. Set a :ref:`catch_all_cluster <envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.PrefixRoutes.catch_all_cluster>` instead.
* Use of json based schema in router check tool tests. The tests should follow validation :repo:`schema<test/tools/router_check/validation.proto>`.

Version 1.10.0 (Apr 5, 2019)
============================
Expand Down
1 change: 1 addition & 0 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Version history
* sandbox: added :ref:`CSRF sandbox <install_sandboxes_csrf>`.
* server: ``--define manual_stamp=manual_stamp`` was added to allow server stamping outside of binary rules.
more info in the `bazel docs <https://github.com/envoyproxy/envoy/blob/master/bazel/README.md#enabling-optional-features>`_.
* tool: added :repo:`proto <test/tools/router_check/validation.proto>` support for :ref:`router check tool <install_tools_route_table_check_tool>` tests.
* upstream: added :ref:`upstream_cx_pool_overflow <config_cluster_manager_cluster_stats>` for the connection pool circuit breaker.
* upstream: an EDS management server can now force removal of a host that is still passing active
health checking by first marking the host as failed via EDS health check and subsequently removing
Expand Down
8 changes: 8 additions & 0 deletions test/tools/router_check/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ load(
"envoy_cc_test_binary",
"envoy_cc_test_library",
"envoy_package",
"envoy_proto_library",
)

envoy_package()
Expand All @@ -22,6 +23,7 @@ envoy_cc_test_library(
"router.h",
],
deps = [
":validation_proto_cc",
"//source/common/config:rds_json_lib",
"//source/common/event:dispatcher_lib",
"//source/common/http:header_map_lib",
Expand All @@ -35,3 +37,9 @@ envoy_cc_test_library(
"//test/tools/router_check/json:tool_config_schemas_lib",
],
)

envoy_proto_library(
name = "validation_proto",
srcs = ["validation.proto"],
deps = ["@envoy_api//envoy/api/v2/core:base_export"],
)
158 changes: 158 additions & 0 deletions test/tools/router_check/router.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,28 @@ ToolConfig ToolConfig::create(const Json::ObjectSharedPtr check_config) {
return ToolConfig(std::move(headers), random_value);
}

ToolConfig ToolConfig::create(const envoy::RouterCheckToolSchema::ValidationItem& check_config) {
// Add header field values
std::unique_ptr<Http::TestHeaderMapImpl> headers(new Http::TestHeaderMapImpl());
headers->addCopy(":authority", check_config.input().authority());
headers->addCopy(":path", check_config.input().path());
headers->addCopy(":method", check_config.input().method());
headers->addCopy("x-forwarded-proto", check_config.input().ssl() ? "https" : "http");

if (check_config.input().internal()) {
headers->addCopy("x-envoy-internal", "true");
}

if (check_config.input().additional_headers().data()) {
for (const envoy::api::v2::core::HeaderValue& header_config :
check_config.input().additional_headers()) {
headers->addCopy(header_config.key(), header_config.value());
}
}

return ToolConfig(std::move(headers), check_config.input().random_value());
}

ToolConfig::ToolConfig(std::unique_ptr<Http::TestHeaderMapImpl> headers, int random_value)
: headers_(std::move(headers)), random_value_(random_value) {}

Expand Down Expand Up @@ -130,6 +152,50 @@ bool RouterCheckTool::compareEntriesInJson(const std::string& expected_route_jso
return no_failures;
}

bool RouterCheckTool::compareEntries(const std::string& expected_routes) {
envoy::RouterCheckToolSchema::Validation validation_config;
auto stats = std::make_unique<Stats::IsolatedStoreImpl>();
auto api = Api::createApiForTest(*stats);
const std::string contents = api->fileSystem().fileReadToEnd(expected_routes);
MessageUtil::loadFromFile(expected_routes, validation_config, *api);
MessageUtil::validate(validation_config);

bool no_failures = true;
for (const envoy::RouterCheckToolSchema::ValidationItem& check_config :
validation_config.tests()) {
ToolConfig tool_config = ToolConfig::create(check_config);
tool_config.route_ = config_->route(*tool_config.headers_, tool_config.random_value_);

std::string test_name = check_config.test_name();
if (details_) {
std::cout << test_name << std::endl;
}
envoy::RouterCheckToolSchema::ValidationAssert validate = check_config.validate();

using checkerFunc =
std::function<bool(ToolConfig&, const envoy::RouterCheckToolSchema::ValidationAssert&)>;
checkerFunc checkers[] = {
[this](auto&... params) -> bool { return this->compareCluster(params...); },
[this](auto&... params) -> bool { return this->compareVirtualCluster(params...); },
[this](auto&... params) -> bool { return this->compareVirtualHost(params...); },
[this](auto&... params) -> bool { return this->compareRewritePath(params...); },
[this](auto&... params) -> bool { return this->compareRewriteHost(params...); },
[this](auto&... params) -> bool { return this->compareRedirectPath(params...); },
[this](auto&... params) -> bool { return this->compareHeaderField(params...); },
[this](auto&... params) -> bool { return this->compareCustomHeaderField(params...); },
};

// Call appropriate function for each match case.
for (const auto& test : checkers) {
if (!test(tool_config, validate)) {
no_failures = false;
}
}
}

return no_failures;
}

bool RouterCheckTool::compareCluster(ToolConfig& tool_config, const std::string& expected) {
std::string actual = "";

Expand All @@ -139,6 +205,17 @@ bool RouterCheckTool::compareCluster(ToolConfig& tool_config, const std::string&
return compareResults(actual, expected, "cluster_name");
}

bool RouterCheckTool::compareCluster(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
if (expected.cluster_name().empty()) {
return true;
}
if (tool_config.route_ == nullptr) {
return compareResults("", expected.cluster_name(), "cluster_name");
}
return compareCluster(tool_config, expected.cluster_name());
}

bool RouterCheckTool::compareVirtualCluster(ToolConfig& tool_config, const std::string& expected) {
std::string actual = "";

Expand All @@ -151,6 +228,17 @@ bool RouterCheckTool::compareVirtualCluster(ToolConfig& tool_config, const std::
return compareResults(actual, expected, "virtual_cluster_name");
}

bool RouterCheckTool::compareVirtualCluster(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
if (expected.virtual_cluster_name().empty()) {
return true;
}
if (tool_config.route_ == nullptr) {
return compareResults("", expected.virtual_cluster_name(), "virtual_cluster_name");
}
return compareVirtualCluster(tool_config, expected.virtual_cluster_name());
}

bool RouterCheckTool::compareVirtualHost(ToolConfig& tool_config, const std::string& expected) {
std::string actual = "";
if (tool_config.route_->routeEntry() != nullptr) {
Expand All @@ -160,6 +248,17 @@ bool RouterCheckTool::compareVirtualHost(ToolConfig& tool_config, const std::str
return compareResults(actual, expected, "virtual_host_name");
}

bool RouterCheckTool::compareVirtualHost(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
if (expected.virtual_host_name().empty()) {
return true;
}
if (tool_config.route_ == nullptr) {
return compareResults("", expected.virtual_host_name(), "virtual_host_name");
}
return compareVirtualHost(tool_config, expected.virtual_host_name());
}

bool RouterCheckTool::compareRewritePath(ToolConfig& tool_config, const std::string& expected) {
std::string actual = "";
Envoy::StreamInfo::StreamInfoImpl stream_info(Envoy::Http::Protocol::Http11,
Expand All @@ -172,6 +271,17 @@ bool RouterCheckTool::compareRewritePath(ToolConfig& tool_config, const std::str
return compareResults(actual, expected, "path_rewrite");
}

bool RouterCheckTool::compareRewritePath(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
if (expected.path_rewrite().empty()) {
return true;
}
if (tool_config.route_ == nullptr) {
return compareResults("", expected.path_rewrite(), "path_rewrite");
}
return compareRewritePath(tool_config, expected.path_rewrite());
}

bool RouterCheckTool::compareRewriteHost(ToolConfig& tool_config, const std::string& expected) {
std::string actual = "";
Envoy::StreamInfo::StreamInfoImpl stream_info(Envoy::Http::Protocol::Http11,
Expand All @@ -184,6 +294,17 @@ bool RouterCheckTool::compareRewriteHost(ToolConfig& tool_config, const std::str
return compareResults(actual, expected, "host_rewrite");
}

bool RouterCheckTool::compareRewriteHost(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
if (expected.host_rewrite().empty()) {
return true;
}
if (tool_config.route_ == nullptr) {
return compareResults("", expected.host_rewrite(), "host_rewrite");
}
return compareRewriteHost(tool_config, expected.host_rewrite());
}

bool RouterCheckTool::compareRedirectPath(ToolConfig& tool_config, const std::string& expected) {
std::string actual = "";
if (tool_config.route_->directResponseEntry() != nullptr) {
Expand All @@ -193,6 +314,30 @@ bool RouterCheckTool::compareRedirectPath(ToolConfig& tool_config, const std::st
return compareResults(actual, expected, "path_redirect");
}

bool RouterCheckTool::compareRedirectPath(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
if (expected.path_redirect().empty()) {
return true;
}
if (tool_config.route_ == nullptr) {
return compareResults("", expected.path_redirect(), "path_redirect");
}
return compareRedirectPath(tool_config, expected.path_redirect());
}

bool RouterCheckTool::compareHeaderField(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
bool no_failures = true;
if (expected.header_fields().data()) {
for (const envoy::api::v2::core::HeaderValue& header : expected.header_fields()) {
if (!compareHeaderField(tool_config, header.key(), header.value())) {
no_failures = false;
}
}
}
return no_failures;
}

bool RouterCheckTool::compareHeaderField(ToolConfig& tool_config, const std::string& field,
const std::string& expected) {
std::string actual = tool_config.headers_->get_(field);
Expand All @@ -213,6 +358,19 @@ bool RouterCheckTool::compareCustomHeaderField(ToolConfig& tool_config, const st
return compareResults(actual, expected, "custom_header");
}

bool RouterCheckTool::compareCustomHeaderField(
ToolConfig& tool_config, const envoy::RouterCheckToolSchema::ValidationAssert& expected) {
bool no_failures = true;
if (expected.custom_header_fields().data()) {
for (const envoy::api::v2::core::HeaderValue& header : expected.custom_header_fields()) {
if (!compareCustomHeaderField(tool_config, header.key(), header.value())) {
no_failures = false;
}
}
}
return no_failures;
}

bool RouterCheckTool::compareResults(const std::string& actual, const std::string& expected,
const std::string& test_type) {
if (expected == actual) {
Expand Down
33 changes: 33 additions & 0 deletions test/tools/router_check/router.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <memory>
#include <string>

#include "envoy/api/v2/core/base.pb.h"

#include "common/common/logger.h"
#include "common/common/utility.h"
#include "common/http/header_map_impl.h"
Expand All @@ -16,6 +18,8 @@
#include "test/test_common/printers.h"
#include "test/test_common/utility.h"
#include "test/tools/router_check/json/tool_config_schemas.h"
#include "test/tools/router_check/validation.pb.h"
#include "test/tools/router_check/validation.pb.validate.h"

namespace Envoy {
/**
Expand All @@ -32,6 +36,13 @@ struct ToolConfig {
*/
static ToolConfig create(const Json::ObjectSharedPtr check_config);

/**
* @param check_config tool config proto object.
* @return ToolConfig a ToolConfig instance with member variables set by the tool config json
* file.
*/
static ToolConfig create(const envoy::RouterCheckToolSchema::ValidationItem& check_config);

Stats::SymbolTable& symbolTable() { return *symbol_table_; }

std::unique_ptr<Http::TestHeaderMapImpl> headers_;
Expand Down Expand Up @@ -64,6 +75,12 @@ class RouterCheckTool : Logger::Loggable<Logger::Id::testing> {
*/
bool compareEntriesInJson(const std::string& expected_route_json);

/**
* @param expected_route_json tool config json file.
* @return bool if all routes match what is expected.
*/
bool compareEntries(const std::string& expected_routes);

/**
* Set whether to print out match case details.
*/
Expand All @@ -76,15 +93,31 @@ class RouterCheckTool : Logger::Loggable<Logger::Id::testing> {
Api::ApiPtr api);

bool compareCluster(ToolConfig& tool_config, const std::string& expected);
bool compareCluster(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expected);
bool compareVirtualCluster(ToolConfig& tool_config, const std::string& expected);
bool compareVirtualCluster(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expected);
bool compareVirtualHost(ToolConfig& tool_config, const std::string& expected);
bool compareVirtualHost(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expected);
bool compareRewriteHost(ToolConfig& tool_config, const std::string& expected);
bool compareRewriteHost(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expected);
bool compareRewritePath(ToolConfig& tool_config, const std::string& expected);
bool compareRewritePath(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expected);
bool compareRedirectPath(ToolConfig& tool_config, const std::string& expected);
bool compareRedirectPath(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expected);
bool compareHeaderField(ToolConfig& tool_config, const std::string& field,
const std::string& expected);
bool compareHeaderField(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expected);
bool compareCustomHeaderField(ToolConfig& tool_config, const std::string& field,
const std::string& expected);
bool compareCustomHeaderField(ToolConfig& tool_config,
const envoy::RouterCheckToolSchema::ValidationAssert& expecte);
/**
* Compare the expected and actual route parameter values. Print out match details if details_
* flag is set.
Expand Down
Loading

0 comments on commit cab4ce6

Please sign in to comment.