Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: remove static config from subset lb integration test #8203

Merged
merged 1 commit into from
Sep 11, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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