From fc254365e122e6715ac46512f15db91f3b04767d Mon Sep 17 00:00:00 2001 From: Stephan Zuercher Date: Tue, 10 Sep 2019 16:29:02 -0700 Subject: [PATCH] test: remove static config from subset lb integration test 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 --- .../http_subset_lb_integration_test.cc | 236 ++++++++---------- 1 file changed, 102 insertions(+), 134 deletions(-) diff --git a/test/integration/http_subset_lb_integration_test.cc b/test/integration/http_subset_lb_integration_test.cc index 427f3f5a3c64..10b882feef95 100644 --- a/test/integration/http_subset_lb_integration_test.cc +++ b/test/integration/http_subset_lb_integration_test.cc @@ -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, public HttpIntegrationTest { public: @@ -156,29 +43,101 @@ class HttpSubsetLbIntegrationTest : public testing::TestWithParamclusters_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 hosts; for (int i = 0; i < n; i++) { Http::TestHeaderMapImpl response_headers{{":status", "200"}}; @@ -189,24 +148,36 @@ class HttpSubsetLbIntegrationTest : public testing::TestWithParamheaders() - .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"}}; @@ -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