Skip to content

Commit

Permalink
test: remove static config from subset lb integration test (#8203)
Browse files Browse the repository at this point in the history
Build the config programmatically to make future API changes less
onerous.

Risk Level: low (test change only)
Testing: n/a
Doc Changes: n/a
Release Notes: n/a

Signed-off-by: Stephan Zuercher <zuercher@gmail.com>
  • Loading branch information
zuercher authored Sep 11, 2019
1 parent c5ffdda commit da38e73
Showing 1 changed file with 102 additions and 134 deletions.
236 changes: 102 additions & 134 deletions test/integration/http_subset_lb_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,120 +4,7 @@
#include "gtest/gtest.h"

namespace Envoy {
namespace {

const std::string SUBSET_CONFIG = R"EOF(
admin:
access_log_path: /dev/null
address:
socket_address:
address: 127.0.0.1
port_value: 0
static_resources:
clusters:
name: cluster_0
lb_policy: round_robin
lb_subset_config:
subset_selectors:
- keys: [ "type" ]
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 0
metadata:
filter_metadata:
"envoy.lb": { "type": "a" }
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 0
metadata:
filter_metadata:
"envoy.lb": { "type": "a" }
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 0
metadata:
filter_metadata:
"envoy.lb": { "type": "b" }
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 0
metadata:
filter_metadata:
"envoy.lb": { "type": "b" }
listeners:
name: listener_0
address:
socket_address:
address: 127.0.0.1
port_value: 0
filter_chains:
filters:
name: envoy.http_connection_manager
config:
stat_prefix: config_test
http_filters:
name: envoy.router
codec_type: HTTP1
access_log:
name: envoy.file_access_log
filter:
not_health_check_filter: {}
config:
path: /dev/null
route_config:
name: route_config_0
virtual_hosts:
name: integration
domains: "*"
routes:
- match:
prefix: "/"
headers:
- name: "x-type"
exact_match: "a"
route:
cluster: cluster_0
metadata_match:
filter_metadata:
"envoy.lb": { "type": "a" }
hash_policy:
- header:
header_name: "x-hash"
- match:
prefix: "/"
headers:
- name: "x-type"
exact_match: "b"
route:
cluster: cluster_0
metadata_match:
filter_metadata:
"envoy.lb": { "type": "b" }
hash_policy:
- header:
header_name: "x-hash"
response_headers_to_add:
- header:
key: "x-host-type"
value: '%UPSTREAM_METADATA(["envoy.lb", "type"])%'
- header:
key: "x-host"
value: '%UPSTREAM_REMOTE_ADDRESS%'
)EOF";

} // namespace

class HttpSubsetLbIntegrationTest : public testing::TestWithParam<envoy::api::v2::Cluster_LbPolicy>,
public HttpIntegrationTest {
public:
Expand Down Expand Up @@ -156,29 +43,101 @@ class HttpSubsetLbIntegrationTest : public testing::TestWithParam<envoy::api::v2

HttpSubsetLbIntegrationTest()
: HttpIntegrationTest(Http::CodecClient::Type::HTTP1, Network::Address::IpVersion::v4,
SUBSET_CONFIG) {
ConfigHelper::HTTP_PROXY_CONFIG),
num_hosts_{4}, is_hash_lb_(GetParam() == envoy::api::v2::Cluster_LbPolicy_RING_HASH ||
GetParam() == envoy::api::v2::Cluster_LbPolicy_MAGLEV) {
autonomous_upstream_ = true;
setUpstreamCount(4);
config_helper_.addConfigModifier([](envoy::config::bootstrap::v2::Bootstrap& bootstrap) {
setUpstreamCount(num_hosts_);

config_helper_.addConfigModifier([&](envoy::config::bootstrap::v2::Bootstrap& bootstrap) {
auto* static_resources = bootstrap.mutable_static_resources();
for (int i = 0; i < static_resources->clusters_size(); ++i) {
auto* cluster = static_resources->mutable_clusters(i);
cluster->set_lb_policy(GetParam());
auto* cluster = static_resources->mutable_clusters(0);

cluster->set_lb_policy(GetParam());

// Create subsets based on type value of the "type" metadata.
cluster->mutable_lb_subset_config()->add_subset_selectors()->add_keys(type_key_);

cluster->clear_hosts();

// Create a load assignment with num_hosts_ entries with metadata split evenly between type=a
// and type=b.
auto* load_assignment = cluster->mutable_load_assignment();
load_assignment->set_cluster_name(cluster->name());
auto* endpoints = load_assignment->add_endpoints();
for (uint32_t i = 0; i < num_hosts_; i++) {
auto* lb_endpoint = endpoints->add_lb_endpoints();

// ConfigHelper will fill in ports later.
auto* endpoint = lb_endpoint->mutable_endpoint();
auto* addr = endpoint->mutable_address()->mutable_socket_address();
addr->set_address("127.0.0.1");
addr->set_port_value(0);

// Assign type metadata based on i.
auto* metadata = lb_endpoint->mutable_metadata();
Envoy::Config::Metadata::mutableMetadataValue(*metadata, "envoy.lb", type_key_)
.set_string_value((i % 2 == 0) ? "a" : "b");
}
});

config_helper_.addConfigModifier(
[&](envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager&
hcm) {
auto* vhost = hcm.mutable_route_config()->mutable_virtual_hosts(0);

// Report the host's type metadata and remote address on every response.
auto* resp_header = vhost->add_response_headers_to_add();
auto* header = resp_header->mutable_header();
header->set_key(host_type_header_);
header->set_value(
fmt::format(R"EOF(%UPSTREAM_METADATA(["envoy.lb", "{}"])%)EOF", type_key_));

resp_header = vhost->add_response_headers_to_add();
header = resp_header->mutable_header();
header->set_key(host_header_);
header->set_value("%UPSTREAM_REMOTE_ADDRESS%");

// Create routes for x-type=a and x-type=b headers.
vhost->clear_routes();
configureRoute(vhost->add_routes(), "a");
configureRoute(vhost->add_routes(), "b");
});
}

void configureRoute(envoy::api::v2::route::Route* route, const std::string& host_type) {
auto* match = route->mutable_match();
match->set_prefix("/");

// Match the x-type header against the given host_type (a/b).
auto* match_header = match->add_headers();
match_header->set_name(type_header_);
match_header->set_exact_match(host_type);

// Route to cluster_0, selecting metadata type=a or type=b.
auto* action = route->mutable_route();
action->set_cluster("cluster_0");
auto* metadata_match = action->mutable_metadata_match();
Envoy::Config::Metadata::mutableMetadataValue(*metadata_match, "envoy.lb", type_key_)
.set_string_value(host_type);

// Set a hash policy for hashing load balancers.
if (is_hash_lb_) {
action->add_hash_policy()->mutable_header()->set_header_name(hash_header_);
}
};

void SetUp() override {
setDownstreamProtocol(Http::CodecClient::Type::HTTP1);
setUpstreamProtocol(FakeHttpConnection::Type::HTTP1);
}

// Runs a subset lb test with the given request headers, expecting the x-host-type header to
// the given type ("a" or "b"). If expect_unique_host, verifies that a single host is selected
// over n iterations (e.g. for maglev/hash-ring policies). Otherwise, expected more than one
// host to be selected over n iterations.
// the given type ("a" or "b"). If is_hash_lb_, verifies that a single host is selected over n
// iterations (e.g. for maglev/hash-ring policies). Otherwise, expected more than one host to be
// selected over n iterations.
void runTest(Http::TestHeaderMapImpl& request_headers, const std::string expected_host_type,
const bool expect_unique_host, const int n = 10) {
const int n = 10) {
std::set<std::string> hosts;
for (int i = 0; i < n; i++) {
Http::TestHeaderMapImpl response_headers{{":status", "200"}};
Expand All @@ -189,24 +148,36 @@ class HttpSubsetLbIntegrationTest : public testing::TestWithParam<envoy::api::v2

// Expect a response from a host in the correct subset.
EXPECT_EQ(response->headers()
.get(Envoy::Http::LowerCaseString{"x-host-type"})
.get(Envoy::Http::LowerCaseString{host_type_header_})
->value()
.getStringView(),
expected_host_type);

hosts.emplace(
response->headers().get(Envoy::Http::LowerCaseString{"x-host"})->value().getStringView());
// Record the upstream address.
hosts.emplace(response->headers()
.get(Envoy::Http::LowerCaseString{host_header_})
->value()
.getStringView());
}

if (expect_unique_host) {
if (is_hash_lb_) {
EXPECT_EQ(hosts.size(), 1) << "Expected a single unique host to be selected for "
<< envoy::api::v2::Cluster_LbPolicy_Name(GetParam());
} else {
EXPECT_GT(hosts.size(), 1) << "Expected multiple hosts to be selected"
EXPECT_GT(hosts.size(), 1) << "Expected multiple hosts to be selected for "
<< envoy::api::v2::Cluster_LbPolicy_Name(GetParam());
}
}

const uint32_t num_hosts_;
const bool is_hash_lb_;

const std::string hash_header_{"x-hash"};
const std::string host_type_header_{"x-host-type"};
const std::string host_header_{"x-host"};
const std::string type_header_{"x-type"};
const std::string type_key_{"type"};

Http::TestHeaderMapImpl type_a_request_headers_{{":method", "GET"}, {":path", "/test"},
{":scheme", "http"}, {":authority", "host"},
{"x-type", "a"}, {"x-hash", "hash-a"}};
Expand All @@ -224,11 +195,8 @@ TEST_P(HttpSubsetLbIntegrationTest, SubsetLoadBalancer) {
initialize();
codec_client_ = makeHttpConnection(lookupPort("http"));

const bool expect_unique_host = (GetParam() == envoy::api::v2::Cluster_LbPolicy_RING_HASH ||
GetParam() == envoy::api::v2::Cluster_LbPolicy_MAGLEV);

runTest(type_a_request_headers_, "a", expect_unique_host);
runTest(type_b_request_headers_, "b", expect_unique_host);
runTest(type_a_request_headers_, "a");
runTest(type_b_request_headers_, "b");
}

} // namespace Envoy

0 comments on commit da38e73

Please sign in to comment.