From b4bb682a8dd1025f5b2d5a4e531898650bc0317d Mon Sep 17 00:00:00 2001 From: Zach Date: Thu, 1 Oct 2020 22:24:49 +0000 Subject: [PATCH 01/34] Save progress Signed-off-by: Zach --- test/common/upstream/BUILD | 44 ++++++ test/common/upstream/load_balancer_fuzz.cc | 42 ++++++ test/common/upstream/load_balancer_fuzz.h | 37 +++++ test/common/upstream/load_balancer_fuzz.proto | 29 ++++ .../upstream/load_balancer_fuzz_test.cc | 1 + .../upstream/load_balancer_impl_test.cc | 15 ++- .../upstream/load_balancer_impl_test_utils.cc | 127 ++++++++++++++++++ .../upstream/load_balancer_impl_test_utils.h | 52 +++++++ 8 files changed, 340 insertions(+), 7 deletions(-) create mode 100644 test/common/upstream/load_balancer_fuzz.cc create mode 100644 test/common/upstream/load_balancer_fuzz.h create mode 100644 test/common/upstream/load_balancer_fuzz.proto create mode 100644 test/common/upstream/load_balancer_fuzz_test.cc create mode 100644 test/common/upstream/load_balancer_impl_test_utils.cc create mode 100644 test/common/upstream/load_balancer_impl_test_utils.h diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index b6b19139a7b5..5f4927bf26bb 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -242,6 +242,50 @@ envoy_cc_test( ], ) +envoy_cc_test_library( + name = "load_balancer_impl_test_lib", + srcs = [ + "load_balancer_impl_test_utils.cc", + ], + hdrs = [ + "load_balancer_impl_test_utils.h", + ], + deps = [ + + ], +) + +envoy_cc_test_library( + name = "load_balancer_fuzz_lib", + srcs = ["load_balancer_fuzz.cc"], + hdrs = ["load_balancer_fuzz.h"], + deps = [ + ":health_check_fuzz_proto_cc_proto", + ":load_balancer_impl_test_lib", + ], +) + +envoy_proto_library( + name = "load_balancer_fuzz_proto", + srcs = ["load_balancer_fuzz.proto"], + deps = [ + "//test/fuzz:common_proto", + "@envoy_api//envoy/config/core/v3:pkg", + ], +) + +envoy_cc_fuzz_test( + name = "health_check_fuzz_test", + srcs = ["health_check_fuzz_test.cc"], + corpus = "//test/common/upstream:health_check_corpus", + deps = [ + ":health_check_fuzz_lib", + ":health_check_fuzz_proto_cc_proto", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) + + envoy_cc_test( name = "load_balancer_simulation_test", srcs = ["load_balancer_simulation_test.cc"], diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc new file mode 100644 index 000000000000..c2844ff834ee --- /dev/null +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -0,0 +1,42 @@ +#include "load_balancer_fuzz.h" + + +namespace Envoy { +namespace Upstream { + +void LoadBalancerFuzzBase::initializeAndReplay(test::common::upstream::LoadBalancerTestCase input) { + //will call initialize, which will all be specific to that + initialize(input); + replay(input); +} + +void LoadBalancerFuzzBase::addHostSet() { + +} + +void LoadBalancerFuzzBase::updateHealthFlags() { + +} + +void LoadBalancerFuzzBase::prefetch() { + //TODO: specifics to each one? + load_balancer_->peekAnotherHost(nullptr); +} + +void LoadBalancerFuzzBase::chooseHost() { + load_balancer_->chooseHost(nullptr); +} + +void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase input) { + +} + +void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { + load_balancer_ = RandomLoadBalancer(priority_set_, nullptr, stats_, runtime_, random_, + input.common_config_); +} + + + +} //namespace Upstream +} //namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz.h new file mode 100644 index 000000000000..b26cb8c113c7 --- /dev/null +++ b/test/common/upstream/load_balancer_fuzz.h @@ -0,0 +1,37 @@ + + + + + +namespace Envoy { +namespace Upstream { + + +//TODO: Perhaps switch this class to a base class +class LoadBalancerFuzzBase { +public: + //Intialize lb here? + LoadBalancerFuzzBase() = default; + virtual void initialize(); + void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); + void addHostSet(uint64_t number_of_hosts_in_host_set); + void updateHealthFlags(Hostset host_set, ); //Hostset or int, or mod the int with number of host sets + void prefetch(); + void chooseHost(); + +private: + void replay(test::common::upstream::LoadBalancerTestCase input); + LoadBalancer load_balancer_; //Will be overriden with specific implementations +} + +class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { + void initialize() override; +} + + + + + + +} //namespace Upstream +} //namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto new file mode 100644 index 000000000000..f045f96f7a8d --- /dev/null +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -0,0 +1,29 @@ + + + +message ChooseHost { + +} + +message PreFetch { + +} + +message Action { + oneof action_selector { + option (validate.required) = true; + AddHostSet = 1; + UpdateHealthFlags = 2; + Prefetch = 3; + ChooseHost = 4; + } +} + +message LoadBalancerTestCase { + //Link in proto config for load balancing here + envoy.config.core.v3.HealthCheck health_check_config = 1 + [(validate.rules).message.required = true]; + //Repeated actions here + repeated Action actions = 2; + +} diff --git a/test/common/upstream/load_balancer_fuzz_test.cc b/test/common/upstream/load_balancer_fuzz_test.cc new file mode 100644 index 000000000000..78de03cae905 --- /dev/null +++ b/test/common/upstream/load_balancer_fuzz_test.cc @@ -0,0 +1 @@ +//Mod it across host sets to determine which one to use diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index 81603a608a65..e55fcfd0f041 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -1687,27 +1687,28 @@ TEST_P(LeastRequestLoadBalancerTest, WeightImbalanceCallbacks) { INSTANTIATE_TEST_SUITE_P(PrimaryOrFailover, LeastRequestLoadBalancerTest, ::testing::Values(true, false)); +//Literally all this class does is make a load balancer class RandomLoadBalancerTest : public LoadBalancerTestBase { public: void init() { lb_ = std::make_shared(priority_set_, nullptr, stats_, runtime_, random_, - common_config_); + common_config_); //Priority set gets added here } std::shared_ptr lb_; }; TEST_P(RandomLoadBalancerTest, NoHosts) { - init(); + init(); //Create the load balancer - EXPECT_EQ(nullptr, lb_->peekAnotherHost(nullptr)); - EXPECT_EQ(nullptr, lb_->chooseHost(nullptr)); + EXPECT_EQ(nullptr, lb_->peekAnotherHost(nullptr)); //Peek into a host + EXPECT_EQ(nullptr, lb_->chooseHost(nullptr)); //Chooose a host into a host } TEST_P(RandomLoadBalancerTest, Normal) { - init(); - hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80"), + init(); //Create the load balancer + hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80"), //These are healthy hosts makeTestHost(info_, "tcp://127.0.0.1:81")}; - hostSet().hosts_ = hostSet().healthy_hosts_; + hostSet().hosts_ = hostSet().healthy_hosts_; //Sets the healthy hosts to this hostSet().runCallbacks({}, {}); // Trigger callbacks. The added/removed lists are not relevant. EXPECT_CALL(random_, random()).WillOnce(Return(2)); diff --git a/test/common/upstream/load_balancer_impl_test_utils.cc b/test/common/upstream/load_balancer_impl_test_utils.cc new file mode 100644 index 000000000000..ea8bb3913548 --- /dev/null +++ b/test/common/upstream/load_balancer_impl_test_utils.cc @@ -0,0 +1,127 @@ +//class LoadBalancerTestBase + +//hostSet() returns a host_set_, constructor generates stats and puts it into a stats variable + +//class TestLb: public LoadBalancerBase, essentiallly an override of the sources load balancer +//This is essentially overriding the source code load balancer, bringing in some methods from it, and overriding methods that wont be used + +//class LoadBalancerBaseTest: public LoadBalancerTestBase + +//Util function for updating host sets, config, uses test load balancer, and common config + +//class RoundRobinLoadBalancerTest: public LoadBalancerTestBase + +//init, updateHosts, shared_ptr localPriority sets etc., this might take a while + +//class LeastRequestLoadBalancerTest: public LoadBalancerTestBase + +//all this has is a public load balancer that is typed as a "LeastRequestLoadBalancer" + +//class RandomLoadBalancerTest: public LoadBalancerTestBase + +//Same thing as least request load balancer, except this one is a random load balancer + +//TODO today, scope out how long you think each part of the fuzzer is going to take you, Address techincal debt from Adi's comments + +namespace Envoy { +namespace Upstream { +namespace { + +class LoadBalancerTestBase : public testing::TestWithParam { +protected: + // Run all tests against both priority 0 and priority 1 host sets, to ensure + // all the load balancers have equivalent functionality for failover host sets. + MockHostSet& hostSet() { return GetParam() ? host_set_ : failover_host_set_; } + + LoadBalancerTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) { + least_request_lb_config_.mutable_choice_count()->set_value(2); + } + + Stats::IsolatedStoreImpl stats_store_; + ClusterStats stats_; + NiceMock runtime_; + NiceMock random_; + NiceMock priority_set_; + MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); + MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); + std::shared_ptr info_{new NiceMock()}; + envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; + envoy::config::cluster::v3::Cluster::LeastRequestLbConfig least_request_lb_config_; +}; + +class TestLb : public LoadBalancerBase { +public: + TestLb(const PrioritySet& priority_set, ClusterStats& stats, Runtime::Loader& runtime, + Random::RandomGenerator& random, + const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) + : LoadBalancerBase(priority_set, stats, runtime, random, common_config) {} + using LoadBalancerBase::chooseHostSet; + using LoadBalancerBase::isInPanic; + using LoadBalancerBase::percentageDegradedLoad; + using LoadBalancerBase::percentageLoad; + + HostConstSharedPtr chooseHostOnce(LoadBalancerContext*) override { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + } + HostConstSharedPtr peekAnotherHost(LoadBalancerContext*) override { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + } +}; + +class LoadBalancerBaseTest : public LoadBalancerTestBase { +public: + void updateHostSet(MockHostSet& host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, + uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0) { + ASSERT(num_healthy_hosts + num_degraded_hosts + num_excluded_hosts <= num_hosts); + + host_set.hosts_.clear(); + host_set.healthy_hosts_.clear(); + host_set.degraded_hosts_.clear(); + host_set.excluded_hosts_.clear(); + for (uint32_t i = 0; i < num_hosts; ++i) { + host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:80")); + } + uint32_t i = 0; + for (; i < num_healthy_hosts; ++i) { + host_set.healthy_hosts_.push_back(host_set.hosts_[i]); + } + for (; i < (num_healthy_hosts + num_degraded_hosts); ++i) { + host_set.degraded_hosts_.push_back(host_set.hosts_[i]); + } + + for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts); ++i) { + host_set.excluded_hosts_.push_back(host_set.hosts_[i]); + } + host_set.runCallbacks({}, {}); + } + + template + std::vector aggregatePrioritySetsValues(TestLb& lb, FUNC func) { + std::vector ret; + + for (size_t i = 0; i < priority_set_.host_sets_.size(); ++i) { + ret.push_back((lb.*func)(i)); + } + + return ret; + } + + std::vector getLoadPercentage() { + return aggregatePrioritySetsValues(lb_, &TestLb::percentageLoad); + } + + std::vector getDegradedLoadPercentage() { + return aggregatePrioritySetsValues(lb_, &TestLb::percentageDegradedLoad); + } + + std::vector getPanic() { + return aggregatePrioritySetsValues(lb_, &TestLb::isInPanic); + } + + envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; + TestLb lb_{priority_set_, stats_, runtime_, random_, common_config_}; +}; + +} // namespace +} // namespace Upstream +} // namespace Envoy diff --git a/test/common/upstream/load_balancer_impl_test_utils.h b/test/common/upstream/load_balancer_impl_test_utils.h new file mode 100644 index 000000000000..ef54c6f71d97 --- /dev/null +++ b/test/common/upstream/load_balancer_impl_test_utils.h @@ -0,0 +1,52 @@ + + + + + + + + +namespace Envoy { +namespace Upstream { +namespace { + +class LoadBalancerFuzzTestBase { +protected: + // Run all tests against both priority 0 and priority 1 host sets, to ensure + // all the load balancers have equivalent functionality for failover host sets. + //MockHostSet& hostSet() { return GetParam() ? host_set_ : failover_host_set_; } + + Stats::IsolatedStoreImpl stats_store_; + ClusterStats stats_; + NiceMock runtime_; + NiceMock random_; + NiceMock priority_set_; + MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); + MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); + std::shared_ptr info_{new NiceMock()}; + envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; +}; + +class TestLb : public LoadBalancerBase { +public: + TestLb(const PrioritySet& priority_set, ClusterStats& stats, Runtime::Loader& runtime, + Random::RandomGenerator& random, + const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) + : LoadBalancerBase(priority_set, stats, runtime, random, common_config) {} + using LoadBalancerBase::chooseHostSet; + using LoadBalancerBase::isInPanic; + using LoadBalancerBase::percentageDegradedLoad; + using LoadBalancerBase::percentageLoad; + + HostConstSharedPtr chooseHostOnce(LoadBalancerContext*) override { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + } + HostConstSharedPtr peekAnotherHost(LoadBalancerContext*) override { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + } +}; + + +} // namespace +} // namespace Upstream +} // namespace Envoy From 8df52a8513484b7e7a728b8fa5a63421b5cfa470 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 2 Oct 2020 04:33:36 +0000 Subject: [PATCH 02/34] Save progress Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.cc | 66 +++++++++++++++++-- test/common/upstream/load_balancer_fuzz.h | 17 +++-- test/common/upstream/load_balancer_fuzz.proto | 16 +++-- .../upstream/load_balancer_fuzz_test.cc | 21 ++++++ 4 files changed, 102 insertions(+), 18 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index c2844ff834ee..40d391fe6f10 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -10,33 +10,85 @@ void LoadBalancerFuzzBase::initializeAndReplay(test::common::upstream::LoadBalan replay(input); } -void LoadBalancerFuzzBase::addHostSet() { +//So, these should be shared amongst all of the types. Since logically, we're just setting the mock priority set to have certain values, we're +//doing the same thing across all of them here +/*void LoadBalancerFuzzBase::addHostSet() { //TODO: Do I even need this? It only seems to get to tertiary, 0, 1 in most of the cases -} +}*/ + +//Perhaps change host set to a vector of vectors +//This clears the host set and starts fresh +void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts) { + //if total hosts doesn't work perhaps make total hosts = to all 3 put together + MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); + host_set.hosts_.clear(); + host_set.healthy_hosts_.clear(); + host_set.degraded_hosts_.clear(); + host_set.excluded_hosts_.clear(); + for (uint32_t i = 0; i < num_hosts; ++i) { + int port = 80 + i; + host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); + } + uint32_t i = 0; + for (; i < num_healthy_hosts; ++i) { + host_set.healthy_hosts_.push_back(host_set.hosts_[i]); + } + for (; i < (num_healthy_hosts + num_degraded_hosts); ++i) { + host_set.degraded_hosts_.push_back(host_set.hosts_[i]); + } -void LoadBalancerFuzzBase::updateHealthFlags() { + for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts); ++i) { + host_set.excluded_hosts_.push_back(host_set.hosts_[i]); + } + //host_set is a placeholder for however the fuzzer will determine which host set to use + host_set.runCallbacks({}, {}); } -void LoadBalancerFuzzBase::prefetch() { +//These two have a lot of logic attached to them such as mocks, so you need to delegate these to specific logic per each specific load balancer. +//What needs to be taken as an argument here? +/*void LoadBalancerFuzzBase::prefetch() { //TODO: specifics to each one? load_balancer_->peekAnotherHost(nullptr); } void LoadBalancerFuzzBase::chooseHost() { load_balancer_->chooseHost(nullptr); -} +}*/ void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase input) { - + constexpr auto max_actions = 64; + for (int i = 0; i < std::min(max_actions, input.actions().size()); ++i) { + const auto& event = input.actions(i); + const bool last_action = i == std::min(max_actions, input.actions().size()) - 1; + ENVOY_LOG_MISC(trace, "Action: {}", event.DebugString()); + switch (event.action_selector_case()) { + case test::common::upstream::Action::kUpdateHealthFlags: { + updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), event.update_health_flags().num_healthy_hosts(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts()); + break; + } + case test::common::upstream::Action::kPrefetch: { + prefetch(); + break; + } + case test::common::upstream::Action::ChooseHost: { + chooseHost(); + break; + } } void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { load_balancer_ = RandomLoadBalancer(priority_set_, nullptr, stats_, runtime_, random_, - input.common_config_); + input.common_lb_config()); } +void RandomLoadBalancerFuzzTest::prefetch() { + load_balancer_->peekAnotherHost(nullptr); +} +void RandomLoadBalancerFuzzTest::chooseHost() { + load_balancer_->chooseHost(nullptr); +} } //namespace Upstream } //namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz.h index b26cb8c113c7..eaed234cafba 100644 --- a/test/common/upstream/load_balancer_fuzz.h +++ b/test/common/upstream/load_balancer_fuzz.h @@ -12,12 +12,14 @@ class LoadBalancerFuzzBase { public: //Intialize lb here? LoadBalancerFuzzBase() = default; - virtual void initialize(); + virtual void initialize(test::common::upstream::LoadBalancerTestCase input); void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); - void addHostSet(uint64_t number_of_hosts_in_host_set); - void updateHealthFlags(Hostset host_set, ); //Hostset or int, or mod the int with number of host sets - void prefetch(); - void chooseHost(); + //void addHostSet(uint64_t number_of_hosts_in_host_set); + void updateHealthFlags(bool failover_host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0); //Hostset or int, or mod the int with number of host sets + //These two actions have a lot of logic attached to them such as mocks, so you need to delegate these to specific logic per each specific load balancer. + //This makes sense, as the load balancing algorithms sometimes use other components which are coupled into the algorithm logically. + virtual void prefetch(); + virtual void chooseHost(); private: void replay(test::common::upstream::LoadBalancerTestCase input); @@ -25,7 +27,10 @@ class LoadBalancerFuzzBase { } class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { - void initialize() override; + void initialize(test::common::upstream::LoadBalancerTestCase input) override; + //Has interesting mock logic + void prefetch() override; + void chooseHost() override; } diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index f045f96f7a8d..282bb0cd6312 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -1,5 +1,12 @@ +message UpdateHealthFlags { + bool failover_host_set = 1; + uint32 num_hosts = 2; + uint32 num_healthy_hosts = 3; + uint32 num_degraded_hosts = 4; + uint32 num_excluded_hosts = 5; +} message ChooseHost { @@ -12,16 +19,15 @@ message PreFetch { message Action { oneof action_selector { option (validate.required) = true; - AddHostSet = 1; - UpdateHealthFlags = 2; - Prefetch = 3; - ChooseHost = 4; + UpdateHealthFlags update_health_flags = 1; + Prefetch = 2; + ChooseHost = 3; } } message LoadBalancerTestCase { //Link in proto config for load balancing here - envoy.config.core.v3.HealthCheck health_check_config = 1 + envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; //Repeated actions here repeated Action actions = 2; diff --git a/test/common/upstream/load_balancer_fuzz_test.cc b/test/common/upstream/load_balancer_fuzz_test.cc index 78de03cae905..4588435211be 100644 --- a/test/common/upstream/load_balancer_fuzz_test.cc +++ b/test/common/upstream/load_balancer_fuzz_test.cc @@ -1 +1,22 @@ //Mod it across host sets to determine which one to use + + +#include "test/common/upstream/load_balancer_fuzz.h" +#include "test/common/upstream/load_balancer_fuzz.pb.validate.h" +#include "test/fuzz/fuzz_runner.h" + + +DEFINE_PROTO_FUZZER(const test::common::upstream::LoadBalancerTestCase input) { + try { + TestUtility::validate(input); + } catch (const ProtoValidationException& e) { + ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); + return; + } + LoadBalancerFuzzBase load_balancer_fuzz + + //TODO: Switch across type, etc.? + load_balancer_fuzz = RandomLoadBalancerFuzzTest; + + load_balancer_fuzz.initializeAndReplay(input); +} From 7ee7b14bee7284cff68772b27533c6fe438bf922 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 2 Oct 2020 05:14:57 +0000 Subject: [PATCH 03/34] Save progress, can almost build Signed-off-by: Zach --- test/common/upstream/BUILD | 31 +++++++++++++------ .../upstream/load_balancer_corpus/empty | 0 test/common/upstream/load_balancer_fuzz.cc | 11 ++++--- test/common/upstream/load_balancer_fuzz.h | 15 +++++---- test/common/upstream/load_balancer_fuzz.proto | 17 +++++++--- .../upstream/load_balancer_fuzz_test.cc | 11 ++++++- .../upstream/load_balancer_impl_test_utils.cc | 3 +- .../upstream/load_balancer_impl_test_utils.h | 22 ++++++++++++- 8 files changed, 83 insertions(+), 27 deletions(-) create mode 100644 test/common/upstream/load_balancer_corpus/empty diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 5f4927bf26bb..77a7ae355004 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -251,7 +251,20 @@ envoy_cc_test_library( "load_balancer_impl_test_utils.h", ], deps = [ - + ":utility_lib", + "//source/common/network:utility_lib", + "//source/common/upstream:load_balancer_lib", + "//source/common/upstream:upstream_includes", + "//source/common/upstream:upstream_lib", + "//test/mocks:common_lib", + "//test/mocks/runtime:runtime_mocks", + "//test/mocks/upstream:cluster_info_mocks", + "//test/mocks/upstream:host_set_mocks", + "//test/mocks/upstream:load_balancer_context_mock", + "//test/mocks/upstream:priority_set_mocks", + "//test/test_common:logging_lib", + "//test/test_common:test_runtime_lib", + "@envoy_api//envoy/config/cluster/v3:pkg_cc_proto", ], ) @@ -260,7 +273,8 @@ envoy_cc_test_library( srcs = ["load_balancer_fuzz.cc"], hdrs = ["load_balancer_fuzz.h"], deps = [ - ":health_check_fuzz_proto_cc_proto", + "//source/common/upstream:load_balancer_lib", + ":load_balancer_fuzz_proto_cc_proto", ":load_balancer_impl_test_lib", ], ) @@ -270,18 +284,17 @@ envoy_proto_library( srcs = ["load_balancer_fuzz.proto"], deps = [ "//test/fuzz:common_proto", - "@envoy_api//envoy/config/core/v3:pkg", + "@envoy_api//envoy/config/cluster/v3:pkg", ], ) envoy_cc_fuzz_test( - name = "health_check_fuzz_test", - srcs = ["health_check_fuzz_test.cc"], - corpus = "//test/common/upstream:health_check_corpus", + name = "load_balancer_fuzz_test", + srcs = ["load_balancer_fuzz_test.cc"], + corpus = "//test/common/upstream:load_balancer_corpus", deps = [ - ":health_check_fuzz_lib", - ":health_check_fuzz_proto_cc_proto", - "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ":load_balancer_fuzz_lib", + ":load_balancer_fuzz_proto_cc_proto", ], ) diff --git a/test/common/upstream/load_balancer_corpus/empty b/test/common/upstream/load_balancer_corpus/empty new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index 40d391fe6f10..a8e5ca5d1a71 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -60,21 +60,24 @@ void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase i constexpr auto max_actions = 64; for (int i = 0; i < std::min(max_actions, input.actions().size()); ++i) { const auto& event = input.actions(i); - const bool last_action = i == std::min(max_actions, input.actions().size()) - 1; ENVOY_LOG_MISC(trace, "Action: {}", event.DebugString()); switch (event.action_selector_case()) { - case test::common::upstream::Action::kUpdateHealthFlags: { + case test::common::upstream::LbAction::kUpdateHealthFlags: { updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), event.update_health_flags().num_healthy_hosts(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts()); break; } - case test::common::upstream::Action::kPrefetch: { + case test::common::upstream::LbAction::kPrefetch: { prefetch(); break; } - case test::common::upstream::Action::ChooseHost: { + case test::common::upstream::LbAction::kChooseHost: { chooseHost(); break; } + default: + break; + } +} } void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz.h index eaed234cafba..d2bfc60ddf73 100644 --- a/test/common/upstream/load_balancer_fuzz.h +++ b/test/common/upstream/load_balancer_fuzz.h @@ -1,6 +1,8 @@ +#include "common/upstream/load_balancer_impl.h" - +#include "test/common/upstream/load_balancer_fuzz.pb.validate.h" +#include "test/common/upstream/load_balancer_impl_test_utils.h" namespace Envoy { @@ -8,14 +10,14 @@ namespace Upstream { //TODO: Perhaps switch this class to a base class -class LoadBalancerFuzzBase { +class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { public: //Intialize lb here? LoadBalancerFuzzBase() = default; virtual void initialize(test::common::upstream::LoadBalancerTestCase input); void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); //void addHostSet(uint64_t number_of_hosts_in_host_set); - void updateHealthFlags(bool failover_host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0); //Hostset or int, or mod the int with number of host sets + void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0); //Hostset or int, or mod the int with number of host sets //These two actions have a lot of logic attached to them such as mocks, so you need to delegate these to specific logic per each specific load balancer. //This makes sense, as the load balancing algorithms sometimes use other components which are coupled into the algorithm logically. virtual void prefetch(); @@ -23,15 +25,16 @@ class LoadBalancerFuzzBase { private: void replay(test::common::upstream::LoadBalancerTestCase input); - LoadBalancer load_balancer_; //Will be overriden with specific implementations -} + //LoadBalancer load_balancer_; //Will be overriden with specific implementations +}; class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { void initialize(test::common::upstream::LoadBalancerTestCase input) override; //Has interesting mock logic void prefetch() override; void chooseHost() override; -} + RandomLoadBalancer load_balancer_; +}; diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 282bb0cd6312..a062e2e73c5a 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -1,4 +1,11 @@ +syntax = "proto3"; +package test.common.upstream; + +import "validate/validate.proto"; +import "test/fuzz/common.proto"; +import "envoy/config/cluster/v3/cluster.proto"; +import "google/protobuf/empty.proto"; message UpdateHealthFlags { bool failover_host_set = 1; @@ -12,16 +19,16 @@ message ChooseHost { } -message PreFetch { +message Prefetch { } -message Action { +message LbAction { oneof action_selector { option (validate.required) = true; UpdateHealthFlags update_health_flags = 1; - Prefetch = 2; - ChooseHost = 3; + Prefetch prefetch = 2; + ChooseHost choose_host = 3; } } @@ -30,6 +37,6 @@ message LoadBalancerTestCase { envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; //Repeated actions here - repeated Action actions = 2; + repeated LbAction actions = 2; } diff --git a/test/common/upstream/load_balancer_fuzz_test.cc b/test/common/upstream/load_balancer_fuzz_test.cc index 4588435211be..e1cfe9030dba 100644 --- a/test/common/upstream/load_balancer_fuzz_test.cc +++ b/test/common/upstream/load_balancer_fuzz_test.cc @@ -5,6 +5,10 @@ #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" #include "test/fuzz/fuzz_runner.h" +namespace Envoy { +namespace Upstream { + + DEFINE_PROTO_FUZZER(const test::common::upstream::LoadBalancerTestCase input) { try { @@ -13,10 +17,15 @@ DEFINE_PROTO_FUZZER(const test::common::upstream::LoadBalancerTestCase input) { ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); return; } - LoadBalancerFuzzBase load_balancer_fuzz + LoadBalancerFuzzBase load_balancer_fuzz; //TODO: Switch across type, etc.? load_balancer_fuzz = RandomLoadBalancerFuzzTest; load_balancer_fuzz.initializeAndReplay(input); } + + + +} //namespace Envoy +} //namespace Upstream diff --git a/test/common/upstream/load_balancer_impl_test_utils.cc b/test/common/upstream/load_balancer_impl_test_utils.cc index ea8bb3913548..8e5174e80833 100644 --- a/test/common/upstream/load_balancer_impl_test_utils.cc +++ b/test/common/upstream/load_balancer_impl_test_utils.cc @@ -26,7 +26,7 @@ namespace Envoy { namespace Upstream { namespace { - +/* class LoadBalancerTestBase : public testing::TestWithParam { protected: // Run all tests against both priority 0 and priority 1 host sets, to ensure @@ -121,6 +121,7 @@ class LoadBalancerBaseTest : public LoadBalancerTestBase { envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; TestLb lb_{priority_set_, stats_, runtime_, random_, common_config_}; }; +*/ } // namespace } // namespace Upstream diff --git a/test/common/upstream/load_balancer_impl_test_utils.h b/test/common/upstream/load_balancer_impl_test_utils.h index ef54c6f71d97..771b80139bc1 100644 --- a/test/common/upstream/load_balancer_impl_test_utils.h +++ b/test/common/upstream/load_balancer_impl_test_utils.h @@ -1,8 +1,28 @@ +#include +#include +#include +#include +#include +#include "envoy/config/cluster/v3/cluster.pb.h" +#include "common/network/utility.h" +#include "common/upstream/load_balancer_impl.h" +#include "common/upstream/upstream_impl.h" +#include "test/common/upstream/utility.h" +#include "test/mocks/common.h" +#include "test/mocks/runtime/mocks.h" +#include "test/mocks/upstream/cluster_info.h" +#include "test/mocks/upstream/host_set.h" +#include "test/mocks/upstream/load_balancer_context.h" +#include "test/mocks/upstream/priority_set.h" +#include "test/test_common/logging.h" +#include "test/test_common/test_runtime.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" +//TODO: ^^ get rid of unused headers From 9e8d6787c4a83a578f923a8ab349b3918db39ced Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 2 Oct 2020 22:09:31 +0000 Subject: [PATCH 04/34] Almost builds Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.cc | 61 ++++++++++--------- test/common/upstream/load_balancer_fuzz.h | 22 ++++--- test/common/upstream/load_balancer_fuzz.proto | 10 +-- .../upstream/load_balancer_fuzz_test.cc | 4 +- .../upstream/load_balancer_impl_test_utils.h | 3 + 5 files changed, 57 insertions(+), 43 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index a8e5ca5d1a71..6ae9fa48ebdf 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -1,13 +1,32 @@ -#include "load_balancer_fuzz.h" +#include "test/common/upstream/load_balancer_fuzz.h" namespace Envoy { namespace Upstream { +LoadBalancerFuzzBase::LoadBalancerFuzzBase() : LoadBalancerFuzzTestBase() { + +} + +void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, uint32_t num_hosts_in_failover_set) { + //TODO: Cap on ports? + int port = 80; + for (uint32_t i = 0; i < num_hosts_in_priority_set; ++i) { + host_set_.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); + ++port; + } + for (uint32_t i = 0; i < num_hosts_in_failover_set; ++i) { + failover_host_set_.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); + ++port; + } + //TODO: More than two hosts? +} + void LoadBalancerFuzzBase::initializeAndReplay(test::common::upstream::LoadBalancerTestCase input) { //will call initialize, which will all be specific to that - initialize(input); - replay(input); + initialize(input); //Initializes specific load balancers + initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); + replay(input); //Action stream } //So, these should be shared amongst all of the types. Since logically, we're just setting the mock priority set to have certain values, we're @@ -15,20 +34,9 @@ void LoadBalancerFuzzBase::initializeAndReplay(test::common::upstream::LoadBalan /*void LoadBalancerFuzzBase::addHostSet() { //TODO: Do I even need this? It only seems to get to tertiary, 0, 1 in most of the cases }*/ - -//Perhaps change host set to a vector of vectors -//This clears the host set and starts fresh -void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts) { - //if total hosts doesn't work perhaps make total hosts = to all 3 put together +void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts) { + //TODO: add logic here for how to calculate those three numbers, perhaps a proportion? MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); - host_set.hosts_.clear(); - host_set.healthy_hosts_.clear(); - host_set.degraded_hosts_.clear(); - host_set.excluded_hosts_.clear(); - for (uint32_t i = 0; i < num_hosts; ++i) { - int port = 80 + i; - host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); - } uint32_t i = 0; for (; i < num_healthy_hosts; ++i) { host_set.healthy_hosts_.push_back(host_set.hosts_[i]); @@ -45,17 +53,6 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, host_set.runCallbacks({}, {}); } -//These two have a lot of logic attached to them such as mocks, so you need to delegate these to specific logic per each specific load balancer. -//What needs to be taken as an argument here? -/*void LoadBalancerFuzzBase::prefetch() { - //TODO: specifics to each one? - load_balancer_->peekAnotherHost(nullptr); -} - -void LoadBalancerFuzzBase::chooseHost() { - load_balancer_->chooseHost(nullptr); -}*/ - void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase input) { constexpr auto max_actions = 64; for (int i = 0; i < std::min(max_actions, input.actions().size()); ++i) { @@ -63,7 +60,7 @@ void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase i ENVOY_LOG_MISC(trace, "Action: {}", event.DebugString()); switch (event.action_selector_case()) { case test::common::upstream::LbAction::kUpdateHealthFlags: { - updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), event.update_health_flags().num_healthy_hosts(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts()); + updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts()); break; } case test::common::upstream::LbAction::kPrefetch: { @@ -80,12 +77,18 @@ void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase i } } +RandomLoadBalancerFuzzTest::RandomLoadBalancerFuzzTest() : LoadBalancerFuzzBase() { + +} + void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { - load_balancer_ = RandomLoadBalancer(priority_set_, nullptr, stats_, runtime_, random_, + load_balancer_ = std::make_unique(priority_set_, nullptr, stats_, runtime_, random_, input.common_lb_config()); } +//Logic specific for random load balancers void RandomLoadBalancerFuzzTest::prefetch() { + //TODO: For random calls, persist state in a mock class load_balancer_->peekAnotherHost(nullptr); } diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz.h index d2bfc60ddf73..33ac3b381ee0 100644 --- a/test/common/upstream/load_balancer_fuzz.h +++ b/test/common/upstream/load_balancer_fuzz.h @@ -12,16 +12,20 @@ namespace Upstream { //TODO: Perhaps switch this class to a base class class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { public: - //Intialize lb here? - LoadBalancerFuzzBase() = default; - virtual void initialize(test::common::upstream::LoadBalancerTestCase input); + LoadBalancerFuzzBase(); + + //Untrusted upstreams don't have the ability to change the host set size, so keep it constant over the fuzz iteration. + void initializeFixedHostSets(uint32_t num_hosts_in_priority_set, uint32_t num_hosts_in_failover_set); + + virtual void initialize(test::common::upstream::LoadBalancerTestCase input) PURE; void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); //void addHostSet(uint64_t number_of_hosts_in_host_set); - void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0); //Hostset or int, or mod the int with number of host sets + void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0); //Hostset or int, or mod the int with number of host sets //These two actions have a lot of logic attached to them such as mocks, so you need to delegate these to specific logic per each specific load balancer. //This makes sense, as the load balancing algorithms sometimes use other components which are coupled into the algorithm logically. - virtual void prefetch(); - virtual void chooseHost(); + virtual void prefetch() PURE; + virtual void chooseHost() PURE; + virtual ~LoadBalancerFuzzBase() = default; private: void replay(test::common::upstream::LoadBalancerTestCase input); @@ -29,11 +33,15 @@ class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { }; class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { +public: + RandomLoadBalancerFuzzTest(); void initialize(test::common::upstream::LoadBalancerTestCase input) override; //Has interesting mock logic void prefetch() override; void chooseHost() override; - RandomLoadBalancer load_balancer_; + ~RandomLoadBalancerFuzzTest() = default; + + std::unique_ptr load_balancer_; }; diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index a062e2e73c5a..ed1eabd1e88b 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -9,10 +9,9 @@ import "google/protobuf/empty.proto"; message UpdateHealthFlags { bool failover_host_set = 1; - uint32 num_hosts = 2; - uint32 num_healthy_hosts = 3; - uint32 num_degraded_hosts = 4; - uint32 num_excluded_hosts = 5; + uint32 num_healthy_hosts = 2; + uint32 num_degraded_hosts = 3; + uint32 num_excluded_hosts = 4; } message ChooseHost { @@ -38,5 +37,6 @@ message LoadBalancerTestCase { [(validate.rules).message.required = true]; //Repeated actions here repeated LbAction actions = 2; - + int64 num_hosts_in_priority_set = 3; //Require this and cap it at something + int64 num_hosts_in_failover_set = 4; } diff --git a/test/common/upstream/load_balancer_fuzz_test.cc b/test/common/upstream/load_balancer_fuzz_test.cc index e1cfe9030dba..3aeec8be6583 100644 --- a/test/common/upstream/load_balancer_fuzz_test.cc +++ b/test/common/upstream/load_balancer_fuzz_test.cc @@ -17,10 +17,10 @@ DEFINE_PROTO_FUZZER(const test::common::upstream::LoadBalancerTestCase input) { ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); return; } - LoadBalancerFuzzBase load_balancer_fuzz; + RandomLoadBalancerFuzzTest load_balancer_fuzz; //TODO: Switch across type, etc.? - load_balancer_fuzz = RandomLoadBalancerFuzzTest; + //load_balancer_fuzz = RandomLoadBalancerFuzzTest(); load_balancer_fuzz.initializeAndReplay(input); } diff --git a/test/common/upstream/load_balancer_impl_test_utils.h b/test/common/upstream/load_balancer_impl_test_utils.h index 771b80139bc1..d73790ab096a 100644 --- a/test/common/upstream/load_balancer_impl_test_utils.h +++ b/test/common/upstream/load_balancer_impl_test_utils.h @@ -35,6 +35,9 @@ class LoadBalancerFuzzTestBase { // Run all tests against both priority 0 and priority 1 host sets, to ensure // all the load balancers have equivalent functionality for failover host sets. //MockHostSet& hostSet() { return GetParam() ? host_set_ : failover_host_set_; } + LoadBalancerFuzzTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) { + + } Stats::IsolatedStoreImpl stats_store_; ClusterStats stats_; From 1cfaa5d3644cbe92066b91f26ec369275acd2e8b Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 2 Oct 2020 22:37:24 +0000 Subject: [PATCH 05/34] Builds correctly Signed-off-by: Zach --- test/common/upstream/BUILD | 5 +- test/common/upstream/load_balancer_fuzz.cc | 143 +++++++++--------- test/common/upstream/load_balancer_fuzz.h | 68 ++++----- test/common/upstream/load_balancer_fuzz.proto | 34 ++--- .../upstream/load_balancer_fuzz_test.cc | 36 ++--- .../upstream/load_balancer_impl_test.cc | 16 +- .../upstream/load_balancer_impl_test_utils.cc | 28 ++-- .../upstream/load_balancer_impl_test_utils.h | 35 ++--- 8 files changed, 179 insertions(+), 186 deletions(-) diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 77a7ae355004..c731b3a33ccb 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -273,9 +273,9 @@ envoy_cc_test_library( srcs = ["load_balancer_fuzz.cc"], hdrs = ["load_balancer_fuzz.h"], deps = [ - "//source/common/upstream:load_balancer_lib", ":load_balancer_fuzz_proto_cc_proto", ":load_balancer_impl_test_lib", + "//source/common/upstream:load_balancer_lib", ], ) @@ -295,10 +295,11 @@ envoy_cc_fuzz_test( deps = [ ":load_balancer_fuzz_lib", ":load_balancer_fuzz_proto_cc_proto", + ":utility_lib", + "//test/fuzz:utility_lib", ], ) - envoy_cc_test( name = "load_balancer_simulation_test", srcs = ["load_balancer_simulation_test.cc"], diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index 6ae9fa48ebdf..77413de0756a 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -1,100 +1,103 @@ #include "test/common/upstream/load_balancer_fuzz.h" +#include "test/common/upstream/utility.h" namespace Envoy { namespace Upstream { -LoadBalancerFuzzBase::LoadBalancerFuzzBase() : LoadBalancerFuzzTestBase() { - -} - -void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, uint32_t num_hosts_in_failover_set) { - //TODO: Cap on ports? - int port = 80; - for (uint32_t i = 0; i < num_hosts_in_priority_set; ++i) { - host_set_.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); - ++port; - } - for (uint32_t i = 0; i < num_hosts_in_failover_set; ++i) { - failover_host_set_.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); - ++port; - } - //TODO: More than two hosts? +LoadBalancerFuzzBase::LoadBalancerFuzzBase() : LoadBalancerFuzzTestBase() {} + +void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, + uint32_t num_hosts_in_failover_set) { + // TODO: Cap on ports? + int port = 80; + for (uint32_t i = 0; i < num_hosts_in_priority_set; ++i) { + host_set_.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); + ++port; + } + for (uint32_t i = 0; i < num_hosts_in_failover_set; ++i) { + failover_host_set_.hosts_.push_back( + makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); + ++port; + } + // TODO: More than two hosts? } void LoadBalancerFuzzBase::initializeAndReplay(test::common::upstream::LoadBalancerTestCase input) { - //will call initialize, which will all be specific to that - initialize(input); //Initializes specific load balancers - initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); - replay(input); //Action stream + // will call initialize, which will all be specific to that + initialize(input); // Initializes specific load balancers + initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); + replay(input); // Action stream } -//So, these should be shared amongst all of the types. Since logically, we're just setting the mock priority set to have certain values, we're -//doing the same thing across all of them here -/*void LoadBalancerFuzzBase::addHostSet() { //TODO: Do I even need this? It only seems to get to tertiary, 0, 1 in most of the cases - -}*/ -void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts) { - //TODO: add logic here for how to calculate those three numbers, perhaps a proportion? - MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); - uint32_t i = 0; - for (; i < num_healthy_hosts; ++i) { - host_set.healthy_hosts_.push_back(host_set.hosts_[i]); - } - for (; i < (num_healthy_hosts + num_degraded_hosts); ++i) { - host_set.degraded_hosts_.push_back(host_set.hosts_[i]); - } - - for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts); ++i) { - host_set.excluded_hosts_.push_back(host_set.hosts_[i]); - } +// So, these should be shared amongst all of the types. Since logically, we're just setting the mock +// priority set to have certain values, we're doing the same thing across all of them here +/*void LoadBalancerFuzzBase::addHostSet() { //TODO: Do I even need this? It only seems to get to +tertiary, 0, 1 in most of the cases - //host_set is a placeholder for however the fuzzer will determine which host set to use - host_set.runCallbacks({}, {}); +}*/ +void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, + uint32_t num_healthy_hosts, + uint32_t num_degraded_hosts, + uint32_t num_excluded_hosts) { + // TODO: add logic here for how to calculate those three numbers, perhaps a proportion? + MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); + uint32_t i = 0; + for (; i < num_healthy_hosts; ++i) { + host_set.healthy_hosts_.push_back(host_set.hosts_[i]); + } + for (; i < (num_healthy_hosts + num_degraded_hosts); ++i) { + host_set.degraded_hosts_.push_back(host_set.hosts_[i]); + } + + for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts); ++i) { + host_set.excluded_hosts_.push_back(host_set.hosts_[i]); + } + + // host_set is a placeholder for however the fuzzer will determine which host set to use + host_set.runCallbacks({}, {}); } void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase input) { - constexpr auto max_actions = 64; + constexpr auto max_actions = 64; for (int i = 0; i < std::min(max_actions, input.actions().size()); ++i) { const auto& event = input.actions(i); ENVOY_LOG_MISC(trace, "Action: {}", event.DebugString()); switch (event.action_selector_case()) { - case test::common::upstream::LbAction::kUpdateHealthFlags: { - updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts()); - break; - } - case test::common::upstream::LbAction::kPrefetch: { - prefetch(); - break; - } - case test::common::upstream::LbAction::kChooseHost: { - chooseHost(); - break; - } - default: - break; + case test::common::upstream::LbAction::kUpdateHealthFlags: { + updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), + event.update_health_flags().num_degraded_hosts(), + event.update_health_flags().num_excluded_hosts()); + break; } + case test::common::upstream::LbAction::kPrefetch: { + prefetch(); + break; + } + case test::common::upstream::LbAction::kChooseHost: { + chooseHost(); + break; + } + default: + break; + } + } } -} - -RandomLoadBalancerFuzzTest::RandomLoadBalancerFuzzTest() : LoadBalancerFuzzBase() { -} +RandomLoadBalancerFuzzTest::RandomLoadBalancerFuzzTest() : LoadBalancerFuzzBase() {} void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { - load_balancer_ = std::make_unique(priority_set_, nullptr, stats_, runtime_, random_, - input.common_lb_config()); + load_balancer_ = std::make_unique(priority_set_, nullptr, stats_, runtime_, + random_, input.common_lb_config()); } -//Logic specific for random load balancers +// Logic specific for random load balancers void RandomLoadBalancerFuzzTest::prefetch() { - //TODO: For random calls, persist state in a mock class - load_balancer_->peekAnotherHost(nullptr); + // TODO: For random calls, persist state in a mock class + load_balancer_->peekAnotherHost(nullptr); } -void RandomLoadBalancerFuzzTest::chooseHost() { - load_balancer_->chooseHost(nullptr); -} +void RandomLoadBalancerFuzzTest::chooseHost() { load_balancer_->chooseHost(nullptr); } -} //namespace Upstream -} //namespace Envoy +} // namespace Upstream +} // namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz.h index 33ac3b381ee0..c68931e3edbb 100644 --- a/test/common/upstream/load_balancer_fuzz.h +++ b/test/common/upstream/load_balancer_fuzz.h @@ -1,53 +1,51 @@ - #include "common/upstream/load_balancer_impl.h" #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" #include "test/common/upstream/load_balancer_impl_test_utils.h" - namespace Envoy { namespace Upstream { - -//TODO: Perhaps switch this class to a base class +// TODO: Perhaps switch this class to a base class class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { public: - LoadBalancerFuzzBase(); - - //Untrusted upstreams don't have the ability to change the host set size, so keep it constant over the fuzz iteration. - void initializeFixedHostSets(uint32_t num_hosts_in_priority_set, uint32_t num_hosts_in_failover_set); - - virtual void initialize(test::common::upstream::LoadBalancerTestCase input) PURE; - void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); - //void addHostSet(uint64_t number_of_hosts_in_host_set); - void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0); //Hostset or int, or mod the int with number of host sets - //These two actions have a lot of logic attached to them such as mocks, so you need to delegate these to specific logic per each specific load balancer. - //This makes sense, as the load balancing algorithms sometimes use other components which are coupled into the algorithm logically. - virtual void prefetch() PURE; - virtual void chooseHost() PURE; - virtual ~LoadBalancerFuzzBase() = default; + LoadBalancerFuzzBase(); + + // Untrusted upstreams don't have the ability to change the host set size, so keep it constant + // over the fuzz iteration. + void initializeFixedHostSets(uint32_t num_hosts_in_priority_set, + uint32_t num_hosts_in_failover_set); + + virtual void initialize(test::common::upstream::LoadBalancerTestCase input) PURE; + void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); + // void addHostSet(uint64_t number_of_hosts_in_host_set); + void updateHealthFlagsForAHostSet( + bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, + uint32_t num_excluded_hosts = 0); // Hostset or int, or mod the int with number of host sets + // These two actions have a lot of logic attached to them such as mocks, so you need to delegate + // these to specific logic per each specific load balancer. This makes sense, as the load + // balancing algorithms sometimes use other components which are coupled into the algorithm + // logically. + virtual void prefetch() PURE; + virtual void chooseHost() PURE; + virtual ~LoadBalancerFuzzBase() = default; private: - void replay(test::common::upstream::LoadBalancerTestCase input); - //LoadBalancer load_balancer_; //Will be overriden with specific implementations + void replay(test::common::upstream::LoadBalancerTestCase input); + // LoadBalancer load_balancer_; //Will be overriden with specific implementations }; class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { public: - RandomLoadBalancerFuzzTest(); - void initialize(test::common::upstream::LoadBalancerTestCase input) override; - //Has interesting mock logic - void prefetch() override; - void chooseHost() override; - ~RandomLoadBalancerFuzzTest() = default; - - std::unique_ptr load_balancer_; + RandomLoadBalancerFuzzTest(); + void initialize(test::common::upstream::LoadBalancerTestCase input) override; + // Has interesting mock logic + void prefetch() override; + void chooseHost() override; + ~RandomLoadBalancerFuzzTest() = default; + + std::unique_ptr load_balancer_; }; - - - - - -} //namespace Upstream -} //namespace Envoy +} // namespace Upstream +} // namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index ed1eabd1e88b..c21462af469e 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -8,35 +8,33 @@ import "envoy/config/cluster/v3/cluster.proto"; import "google/protobuf/empty.proto"; message UpdateHealthFlags { - bool failover_host_set = 1; - uint32 num_healthy_hosts = 2; - uint32 num_degraded_hosts = 3; - uint32 num_excluded_hosts = 4; + bool failover_host_set = 1; + uint32 num_healthy_hosts = 2; + uint32 num_degraded_hosts = 3; + uint32 num_excluded_hosts = 4; } message ChooseHost { - } message Prefetch { - } message LbAction { - oneof action_selector { - option (validate.required) = true; - UpdateHealthFlags update_health_flags = 1; - Prefetch prefetch = 2; - ChooseHost choose_host = 3; - } + oneof action_selector { + option (validate.required) = true; + UpdateHealthFlags update_health_flags = 1; + Prefetch prefetch = 2; + ChooseHost choose_host = 3; + } } message LoadBalancerTestCase { - //Link in proto config for load balancing here - envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 + //Link in proto config for load balancing here + envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; - //Repeated actions here - repeated LbAction actions = 2; - int64 num_hosts_in_priority_set = 3; //Require this and cap it at something - int64 num_hosts_in_failover_set = 4; + //Repeated actions here + repeated LbAction actions = 2; + int64 num_hosts_in_priority_set = 3; //Require this and cap it at something + int64 num_hosts_in_failover_set = 4; } diff --git a/test/common/upstream/load_balancer_fuzz_test.cc b/test/common/upstream/load_balancer_fuzz_test.cc index 3aeec8be6583..188430c2b2db 100644 --- a/test/common/upstream/load_balancer_fuzz_test.cc +++ b/test/common/upstream/load_balancer_fuzz_test.cc @@ -1,31 +1,27 @@ -//Mod it across host sets to determine which one to use - +// Mod it across host sets to determine which one to use #include "test/common/upstream/load_balancer_fuzz.h" #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" #include "test/fuzz/fuzz_runner.h" +#include "test/test_common/utility.h" namespace Envoy { namespace Upstream { - - DEFINE_PROTO_FUZZER(const test::common::upstream::LoadBalancerTestCase input) { - try { - TestUtility::validate(input); - } catch (const ProtoValidationException& e) { - ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); - return; - } - RandomLoadBalancerFuzzTest load_balancer_fuzz; - - //TODO: Switch across type, etc.? - //load_balancer_fuzz = RandomLoadBalancerFuzzTest(); - - load_balancer_fuzz.initializeAndReplay(input); + try { + TestUtility::validate(input); + } catch (const ProtoValidationException& e) { + ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); + return; + } + RandomLoadBalancerFuzzTest load_balancer_fuzz; + + // TODO: Switch across type, etc.? + // load_balancer_fuzz = RandomLoadBalancerFuzzTest(); + + load_balancer_fuzz.initializeAndReplay(input); } - - -} //namespace Envoy -} //namespace Upstream +} // namespace Upstream +} // namespace Envoy diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index e55fcfd0f041..9a836b896d97 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -1687,28 +1687,28 @@ TEST_P(LeastRequestLoadBalancerTest, WeightImbalanceCallbacks) { INSTANTIATE_TEST_SUITE_P(PrimaryOrFailover, LeastRequestLoadBalancerTest, ::testing::Values(true, false)); -//Literally all this class does is make a load balancer +// Literally all this class does is make a load balancer class RandomLoadBalancerTest : public LoadBalancerTestBase { public: void init() { lb_ = std::make_shared(priority_set_, nullptr, stats_, runtime_, random_, - common_config_); //Priority set gets added here + common_config_); // Priority set gets added here } std::shared_ptr lb_; }; TEST_P(RandomLoadBalancerTest, NoHosts) { - init(); //Create the load balancer + init(); // Create the load balancer - EXPECT_EQ(nullptr, lb_->peekAnotherHost(nullptr)); //Peek into a host - EXPECT_EQ(nullptr, lb_->chooseHost(nullptr)); //Chooose a host into a host + EXPECT_EQ(nullptr, lb_->peekAnotherHost(nullptr)); // Peek into a host + EXPECT_EQ(nullptr, lb_->chooseHost(nullptr)); // Chooose a host into a host } TEST_P(RandomLoadBalancerTest, Normal) { - init(); //Create the load balancer - hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80"), //These are healthy hosts + init(); // Create the load balancer + hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80"), // These are healthy hosts makeTestHost(info_, "tcp://127.0.0.1:81")}; - hostSet().hosts_ = hostSet().healthy_hosts_; //Sets the healthy hosts to this + hostSet().hosts_ = hostSet().healthy_hosts_; // Sets the healthy hosts to this hostSet().runCallbacks({}, {}); // Trigger callbacks. The added/removed lists are not relevant. EXPECT_CALL(random_, random()).WillOnce(Return(2)); diff --git a/test/common/upstream/load_balancer_impl_test_utils.cc b/test/common/upstream/load_balancer_impl_test_utils.cc index 8e5174e80833..c7880101fcb8 100644 --- a/test/common/upstream/load_balancer_impl_test_utils.cc +++ b/test/common/upstream/load_balancer_impl_test_utils.cc @@ -1,27 +1,29 @@ -//class LoadBalancerTestBase +// class LoadBalancerTestBase -//hostSet() returns a host_set_, constructor generates stats and puts it into a stats variable +// hostSet() returns a host_set_, constructor generates stats and puts it into a stats variable -//class TestLb: public LoadBalancerBase, essentiallly an override of the sources load balancer -//This is essentially overriding the source code load balancer, bringing in some methods from it, and overriding methods that wont be used +// class TestLb: public LoadBalancerBase, essentiallly an override of the sources load balancer +// This is essentially overriding the source code load balancer, bringing in some methods from it, +// and overriding methods that wont be used -//class LoadBalancerBaseTest: public LoadBalancerTestBase +// class LoadBalancerBaseTest: public LoadBalancerTestBase -//Util function for updating host sets, config, uses test load balancer, and common config +// Util function for updating host sets, config, uses test load balancer, and common config -//class RoundRobinLoadBalancerTest: public LoadBalancerTestBase +// class RoundRobinLoadBalancerTest: public LoadBalancerTestBase -//init, updateHosts, shared_ptr localPriority sets etc., this might take a while +// init, updateHosts, shared_ptr localPriority sets etc., this might take a while -//class LeastRequestLoadBalancerTest: public LoadBalancerTestBase +// class LeastRequestLoadBalancerTest: public LoadBalancerTestBase -//all this has is a public load balancer that is typed as a "LeastRequestLoadBalancer" +// all this has is a public load balancer that is typed as a "LeastRequestLoadBalancer" -//class RandomLoadBalancerTest: public LoadBalancerTestBase +// class RandomLoadBalancerTest: public LoadBalancerTestBase -//Same thing as least request load balancer, except this one is a random load balancer +// Same thing as least request load balancer, except this one is a random load balancer -//TODO today, scope out how long you think each part of the fuzzer is going to take you, Address techincal debt from Adi's comments +// TODO today, scope out how long you think each part of the fuzzer is going to take you, Address +// techincal debt from Adi's comments namespace Envoy { namespace Upstream { diff --git a/test/common/upstream/load_balancer_impl_test_utils.h b/test/common/upstream/load_balancer_impl_test_utils.h index d73790ab096a..990310e46201 100644 --- a/test/common/upstream/load_balancer_impl_test_utils.h +++ b/test/common/upstream/load_balancer_impl_test_utils.h @@ -1,30 +1,28 @@ -#include -#include -#include -#include -#include +//#include +//#include +//#include +//#include +//#include #include "envoy/config/cluster/v3/cluster.pb.h" -#include "common/network/utility.h" +//#include "common/network/utility.h" #include "common/upstream/load_balancer_impl.h" -#include "common/upstream/upstream_impl.h" +//#include "common/upstream/upstream_impl.h" -#include "test/common/upstream/utility.h" +//#include "test/common/upstream/utility.h" #include "test/mocks/common.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/upstream/cluster_info.h" #include "test/mocks/upstream/host_set.h" #include "test/mocks/upstream/load_balancer_context.h" #include "test/mocks/upstream/priority_set.h" -#include "test/test_common/logging.h" -#include "test/test_common/test_runtime.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -//TODO: ^^ get rid of unused headers - +//#include "test/test_common/logging.h" +//#include "test/test_common/test_runtime.h" +//#include "gmock/gmock.h" +//#include "gtest/gtest.h" +// TODO: ^^ get rid of unused headers namespace Envoy { namespace Upstream { @@ -34,10 +32,8 @@ class LoadBalancerFuzzTestBase { protected: // Run all tests against both priority 0 and priority 1 host sets, to ensure // all the load balancers have equivalent functionality for failover host sets. - //MockHostSet& hostSet() { return GetParam() ? host_set_ : failover_host_set_; } - LoadBalancerFuzzTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) { - - } + // MockHostSet& hostSet() { return GetParam() ? host_set_ : failover_host_set_; } + LoadBalancerFuzzTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) {} Stats::IsolatedStoreImpl stats_store_; ClusterStats stats_; @@ -69,7 +65,6 @@ class TestLb : public LoadBalancerBase { } }; - } // namespace } // namespace Upstream } // namespace Envoy From 73c24edf6e7079331e918a453cd50df380b87ce5 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 2 Oct 2020 23:00:57 +0000 Subject: [PATCH 06/34] Got rid of unused imports Signed-off-by: Zach --- test/common/upstream/BUILD | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index c731b3a33ccb..b4601112d739 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -252,18 +252,13 @@ envoy_cc_test_library( ], deps = [ ":utility_lib", - "//source/common/network:utility_lib", "//source/common/upstream:load_balancer_lib", - "//source/common/upstream:upstream_includes", - "//source/common/upstream:upstream_lib", "//test/mocks:common_lib", "//test/mocks/runtime:runtime_mocks", "//test/mocks/upstream:cluster_info_mocks", "//test/mocks/upstream:host_set_mocks", "//test/mocks/upstream:load_balancer_context_mock", "//test/mocks/upstream:priority_set_mocks", - "//test/test_common:logging_lib", - "//test/test_common:test_runtime_lib", "@envoy_api//envoy/config/cluster/v3:pkg_cc_proto", ], ) From 54d5b67290309e5a472f54717c27c2db9f4b72bb Mon Sep 17 00:00:00 2001 From: Zach Date: Mon, 5 Oct 2020 21:37:44 +0000 Subject: [PATCH 07/34] Save progress Signed-off-by: Zach --- .../load_balancer_corpus/random_NoHosts | 15 +++ .../load_balancer_corpus/random_Normal | 21 ++++ test/common/upstream/load_balancer_fuzz.cc | 18 ++- test/common/upstream/load_balancer_fuzz.proto | 2 + .../upstream/load_balancer_impl_test_utils.cc | 103 ++---------------- .../upstream/load_balancer_impl_test_utils.h | 41 +++---- 6 files changed, 84 insertions(+), 116 deletions(-) create mode 100644 test/common/upstream/load_balancer_corpus/random_NoHosts create mode 100644 test/common/upstream/load_balancer_corpus/random_Normal diff --git a/test/common/upstream/load_balancer_corpus/random_NoHosts b/test/common/upstream/load_balancer_corpus/random_NoHosts new file mode 100644 index 000000000000..8111dd2d7528 --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_NoHosts @@ -0,0 +1,15 @@ +common_lb_config { + +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +num_hosts_in_priority_set: 0 +num_hosts_in_failover_set: 0 diff --git a/test/common/upstream/load_balancer_corpus/random_Normal b/test/common/upstream/load_balancer_corpus/random_Normal new file mode 100644 index 000000000000..31bfaa98aed0 --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_Normal @@ -0,0 +1,21 @@ +common_lb_config { + +} +actions { + update_health_flags { + failover_host_set: false + num_healthy_hosts: 2 + } +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +num_hosts_in_priority_set: 2 +num_hosts_in_failover_set: 0 diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index 77413de0756a..ea51da1bddbc 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -5,6 +5,17 @@ namespace Envoy { namespace Upstream { +//Anonymous namespace for helper functions +namespace { + std::vector ConstructByteVectorForRandom(test::common::upstream::LoadBalancerTestCase input) { + std::vector byteVector; + for (int i = 0; i < input.bytestring_for_random_calls().size(); ++i) { + byteVector.push_back(input.bytestring_for_random_calls(i)); + } + return byteVector; + } +} + LoadBalancerFuzzBase::LoadBalancerFuzzBase() : LoadBalancerFuzzTestBase() {} void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, @@ -54,7 +65,6 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, host_set.excluded_hosts_.push_back(host_set.hosts_[i]); } - // host_set is a placeholder for however the fuzzer will determine which host set to use host_set.runCallbacks({}, {}); } @@ -84,6 +94,8 @@ void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase i } } +void LoadBalancerFuzzBase + RandomLoadBalancerFuzzTest::RandomLoadBalancerFuzzTest() : LoadBalancerFuzzBase() {} void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { @@ -91,6 +103,10 @@ void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancer random_, input.common_lb_config()); } +//For random load balancing, a randomly generated uint64 gets moded against the hosts to choose from. +//This is not something an untrusted upstream can affect, and fuzzing must be deterministic, so the fuzzer +//just iterates it by one every call (done in an overriden mock random class) + // Logic specific for random load balancers void RandomLoadBalancerFuzzTest::prefetch() { // TODO: For random calls, persist state in a mock class diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index c21462af469e..fd2ade3ac1c4 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -37,4 +37,6 @@ message LoadBalancerTestCase { repeated LbAction actions = 2; int64 num_hosts_in_priority_set = 3; //Require this and cap it at something int64 num_hosts_in_failover_set = 4; + //TODO: Any validations on this? + repeated int64 bytestring_for_random_calls = 5; } diff --git a/test/common/upstream/load_balancer_impl_test_utils.cc b/test/common/upstream/load_balancer_impl_test_utils.cc index c7880101fcb8..e13819f7985a 100644 --- a/test/common/upstream/load_balancer_impl_test_utils.cc +++ b/test/common/upstream/load_balancer_impl_test_utils.cc @@ -27,104 +27,17 @@ namespace Envoy { namespace Upstream { -namespace { -/* -class LoadBalancerTestBase : public testing::TestWithParam { -protected: - // Run all tests against both priority 0 and priority 1 host sets, to ensure - // all the load balancers have equivalent functionality for failover host sets. - MockHostSet& hostSet() { return GetParam() ? host_set_ : failover_host_set_; } - - LoadBalancerTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) { - least_request_lb_config_.mutable_choice_count()->set_value(2); - } - - Stats::IsolatedStoreImpl stats_store_; - ClusterStats stats_; - NiceMock runtime_; - NiceMock random_; - NiceMock priority_set_; - MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); - MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); - std::shared_ptr info_{new NiceMock()}; - envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; - envoy::config::cluster::v3::Cluster::LeastRequestLbConfig least_request_lb_config_; -}; - -class TestLb : public LoadBalancerBase { -public: - TestLb(const PrioritySet& priority_set, ClusterStats& stats, Runtime::Loader& runtime, - Random::RandomGenerator& random, - const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) - : LoadBalancerBase(priority_set, stats, runtime, random, common_config) {} - using LoadBalancerBase::chooseHostSet; - using LoadBalancerBase::isInPanic; - using LoadBalancerBase::percentageDegradedLoad; - using LoadBalancerBase::percentageLoad; - - HostConstSharedPtr chooseHostOnce(LoadBalancerContext*) override { - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; - } - HostConstSharedPtr peekAnotherHost(LoadBalancerContext*) override { - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; - } -}; - -class LoadBalancerBaseTest : public LoadBalancerTestBase { -public: - void updateHostSet(MockHostSet& host_set, uint32_t num_hosts, uint32_t num_healthy_hosts, - uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0) { - ASSERT(num_healthy_hosts + num_degraded_hosts + num_excluded_hosts <= num_hosts); - - host_set.hosts_.clear(); - host_set.healthy_hosts_.clear(); - host_set.degraded_hosts_.clear(); - host_set.excluded_hosts_.clear(); - for (uint32_t i = 0; i < num_hosts; ++i) { - host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:80")); - } - uint32_t i = 0; - for (; i < num_healthy_hosts; ++i) { - host_set.healthy_hosts_.push_back(host_set.hosts_[i]); - } - for (; i < (num_healthy_hosts + num_degraded_hosts); ++i) { - host_set.degraded_hosts_.push_back(host_set.hosts_[i]); - } - - for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts); ++i) { - host_set.excluded_hosts_.push_back(host_set.hosts_[i]); - } - host_set.runCallbacks({}, {}); +namespace Random { + FakeRandomGenerator::FakeRandomGenerator() { + } - - template - std::vector aggregatePrioritySetsValues(TestLb& lb, FUNC func) { - std::vector ret; - - for (size_t i = 0; i < priority_set_.host_sets_.size(); ++i) { - ret.push_back((lb.*func)(i)); - } - - return ret; - } - - std::vector getLoadPercentage() { - return aggregatePrioritySetsValues(lb_, &TestLb::percentageLoad); + uint64_t FakeRandomGenerator::random() { + uint8_t index_of_data = counter % bytestring_.size(); + ++counter; + return bytestring.at(index_of_data); } - std::vector getDegradedLoadPercentage() { - return aggregatePrioritySetsValues(lb_, &TestLb::percentageDegradedLoad); - } - - std::vector getPanic() { - return aggregatePrioritySetsValues(lb_, &TestLb::isInPanic); - } - - envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; - TestLb lb_{priority_set_, stats_, runtime_, random_, common_config_}; -}; -*/ - +} } // namespace } // namespace Upstream } // namespace Envoy diff --git a/test/common/upstream/load_balancer_impl_test_utils.h b/test/common/upstream/load_balancer_impl_test_utils.h index 990310e46201..615025839267 100644 --- a/test/common/upstream/load_balancer_impl_test_utils.h +++ b/test/common/upstream/load_balancer_impl_test_utils.h @@ -1,28 +1,12 @@ -//#include -//#include -//#include -//#include -//#include - #include "envoy/config/cluster/v3/cluster.pb.h" -//#include "common/network/utility.h" #include "common/upstream/load_balancer_impl.h" -//#include "common/upstream/upstream_impl.h" - -//#include "test/common/upstream/utility.h" #include "test/mocks/common.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/upstream/cluster_info.h" #include "test/mocks/upstream/host_set.h" #include "test/mocks/upstream/load_balancer_context.h" #include "test/mocks/upstream/priority_set.h" -//#include "test/test_common/logging.h" -//#include "test/test_common/test_runtime.h" - -//#include "gmock/gmock.h" -//#include "gtest/gtest.h" -// TODO: ^^ get rid of unused headers namespace Envoy { namespace Upstream { @@ -30,15 +14,12 @@ namespace { class LoadBalancerFuzzTestBase { protected: - // Run all tests against both priority 0 and priority 1 host sets, to ensure - // all the load balancers have equivalent functionality for failover host sets. - // MockHostSet& hostSet() { return GetParam() ? host_set_ : failover_host_set_; } LoadBalancerFuzzTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) {} Stats::IsolatedStoreImpl stats_store_; ClusterStats stats_; NiceMock runtime_; - NiceMock random_; + NiceMock random_; //TODO: override this Random class to persist state and return a number NiceMock priority_set_; MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); @@ -67,4 +48,24 @@ class TestLb : public LoadBalancerBase { } // namespace } // namespace Upstream + + +//repeated uint64t exactly 50 times, if it goes over (persist a counter state variable), use % to get rid of it overflowing +namespace Random { + class FakeRandomGenerator : public RandomGenerator { + public: + FakeRandomGenerator(); //construct it with a long string of bytes that it slowly pulls off of + ~FakeRandomGenerator() override; + + uint64_t random() override; //returns first few parts of the generated bytestring + private: + uint32_t counter = 0; //Will get modded against 50 for byte string index + std::vector bytestring_; + } +} + } // namespace Envoy + + +//Since each load balancer has a specific config, this will need to be addressed in their specific base classes +//We can do this with an extended proto, which also will contain specific logic for mocks From d5f072f7ebd84dc491caa92f3e1cc067a54a2c1e Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 6 Oct 2020 01:19:31 +0000 Subject: [PATCH 08/34] Ready for PR, working with Asan-fuzzer Signed-off-by: Zach --- test/common/upstream/BUILD | 4 +- .../upstream/load_balancer_corpus/empty | 0 .../load_balancer_corpus/random_NoHosts | 1 + .../load_balancer_corpus/random_Normal | 12 ++++ ...h-ba5efdfd9c412a8507087120783fe6529b1ac0cb | 31 ++++++++ .../random_largest-port-value | 27 +++++++ test/common/upstream/load_balancer_fuzz.cc | 52 +++++++------- test/common/upstream/load_balancer_fuzz.h | 22 +++--- test/common/upstream/load_balancer_fuzz.proto | 13 ++-- .../upstream/load_balancer_fuzz_test.cc | 8 +-- .../upstream/load_balancer_fuzz_test_utils.cc | 12 ++++ .../upstream/load_balancer_fuzz_test_utils.h | 48 +++++++++++++ .../upstream/load_balancer_impl_test_utils.cc | 43 ----------- .../upstream/load_balancer_impl_test_utils.h | 71 ------------------- 14 files changed, 183 insertions(+), 161 deletions(-) delete mode 100644 test/common/upstream/load_balancer_corpus/empty create mode 100644 test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb create mode 100644 test/common/upstream/load_balancer_corpus/random_largest-port-value create mode 100644 test/common/upstream/load_balancer_fuzz_test_utils.cc create mode 100644 test/common/upstream/load_balancer_fuzz_test_utils.h delete mode 100644 test/common/upstream/load_balancer_impl_test_utils.cc delete mode 100644 test/common/upstream/load_balancer_impl_test_utils.h diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index b4601112d739..2b7b99d89c07 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -245,10 +245,10 @@ envoy_cc_test( envoy_cc_test_library( name = "load_balancer_impl_test_lib", srcs = [ - "load_balancer_impl_test_utils.cc", + "load_balancer_fuzz_test_utils.cc", ], hdrs = [ - "load_balancer_impl_test_utils.h", + "load_balancer_fuzz_test_utils.h", ], deps = [ ":utility_lib", diff --git a/test/common/upstream/load_balancer_corpus/empty b/test/common/upstream/load_balancer_corpus/empty deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/common/upstream/load_balancer_corpus/random_NoHosts b/test/common/upstream/load_balancer_corpus/random_NoHosts index 8111dd2d7528..d688810fc353 100644 --- a/test/common/upstream/load_balancer_corpus/random_NoHosts +++ b/test/common/upstream/load_balancer_corpus/random_NoHosts @@ -13,3 +13,4 @@ actions { } num_hosts_in_priority_set: 0 num_hosts_in_failover_set: 0 +bytestring_for_random_calls: 0 diff --git a/test/common/upstream/load_balancer_corpus/random_Normal b/test/common/upstream/load_balancer_corpus/random_Normal index 31bfaa98aed0..0486b87fe1d9 100644 --- a/test/common/upstream/load_balancer_corpus/random_Normal +++ b/test/common/upstream/load_balancer_corpus/random_Normal @@ -12,6 +12,16 @@ actions { } } +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} actions { choose_host { @@ -19,3 +29,5 @@ actions { } num_hosts_in_priority_set: 2 num_hosts_in_failover_set: 0 +bytestring_for_random_calls: 2 +bytestring_for_random_calls: 3 diff --git a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb new file mode 100644 index 000000000000..f57eab590595 --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb @@ -0,0 +1,31 @@ +common_lb_config { + healthy_panic_threshold { + value: 2.12199579096527e-314 + } + locality_weighted_lb_config { + } +} +actions { + choose_host { + } +} +actions { + prefetch { + } +} +actions { + prefetch { + } +} +actions { + choose_host { + } +} +actions { + choose_host { + } +} +num_hosts_in_priority_set: 2 +num_hosts_in_failover_set: 9007199258945536 +bytestring_for_random_calls: 2 +bytestring_for_random_calls: 3 diff --git a/test/common/upstream/load_balancer_corpus/random_largest-port-value b/test/common/upstream/load_balancer_corpus/random_largest-port-value new file mode 100644 index 000000000000..ce1c1de691e8 --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_largest-port-value @@ -0,0 +1,27 @@ +common_lb_config { + +} +actions { + choose_host { + } +} +actions { + prefetch { + } +} +actions { + prefetch { + } +} +actions { + choose_host { + } +} +actions { + choose_host { + } +} +num_hosts_in_priority_set: 65455 +num_hosts_in_failover_set: 65455 +bytestring_for_random_calls: 2 +bytestring_for_random_calls: 3 diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index ea51da1bddbc..123d7eb52c7b 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -5,17 +5,19 @@ namespace Envoy { namespace Upstream { -//Anonymous namespace for helper functions +// Anonymous namespace for helper functions namespace { - std::vector ConstructByteVectorForRandom(test::common::upstream::LoadBalancerTestCase input) { - std::vector byteVector; - for (int i = 0; i < input.bytestring_for_random_calls().size(); ++i) { - byteVector.push_back(input.bytestring_for_random_calls(i)); - } - return byteVector; +std::vector +constructByteVectorForRandom(test::common::upstream::LoadBalancerTestCase input) { + std::vector byteVector; + for (int i = 0; i < input.bytestring_for_random_calls().size(); ++i) { + byteVector.push_back(input.bytestring_for_random_calls(i)); } + return byteVector; } +} // namespace +// Required because super class constructor has logic LoadBalancerFuzzBase::LoadBalancerFuzzBase() : LoadBalancerFuzzTestBase() {} void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, @@ -35,33 +37,37 @@ void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priorit } void LoadBalancerFuzzBase::initializeAndReplay(test::common::upstream::LoadBalancerTestCase input) { - // will call initialize, which will all be specific to that - initialize(input); // Initializes specific load balancers + // TODO: Keep this random instantiation even in load balancers that don't call into it, or do they + // all? + random_.bytestring_ = constructByteVectorForRandom(input); + try { + initialize(input); // Initializes specific load balancers + } catch (EnvoyException& e) { + ENVOY_LOG_MISC(debug, "EnvoyException: {}", e.what()); + return; + } initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); - replay(input); // Action stream + replay(input); } // So, these should be shared amongst all of the types. Since logically, we're just setting the mock // priority set to have certain values, we're doing the same thing across all of them here -/*void LoadBalancerFuzzBase::addHostSet() { //TODO: Do I even need this? It only seems to get to -tertiary, 0, 1 in most of the cases - -}*/ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts) { - // TODO: add logic here for how to calculate those three numbers, perhaps a proportion? MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); uint32_t i = 0; - for (; i < num_healthy_hosts; ++i) { + for (; i < num_healthy_hosts && i < host_set.hosts_.size(); ++i) { host_set.healthy_hosts_.push_back(host_set.hosts_[i]); } - for (; i < (num_healthy_hosts + num_degraded_hosts); ++i) { + for (; i < (num_healthy_hosts + num_degraded_hosts) && i < host_set.hosts_.size(); ++i) { host_set.degraded_hosts_.push_back(host_set.hosts_[i]); } - for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts); ++i) { + for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts) && + i < host_set.hosts_.size(); + ++i) { host_set.excluded_hosts_.push_back(host_set.hosts_[i]); } @@ -94,8 +100,6 @@ void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase i } } -void LoadBalancerFuzzBase - RandomLoadBalancerFuzzTest::RandomLoadBalancerFuzzTest() : LoadBalancerFuzzBase() {} void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { @@ -103,13 +107,13 @@ void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancer random_, input.common_lb_config()); } -//For random load balancing, a randomly generated uint64 gets moded against the hosts to choose from. -//This is not something an untrusted upstream can affect, and fuzzing must be deterministic, so the fuzzer -//just iterates it by one every call (done in an overriden mock random class) +// For random load balancing, a randomly generated uint64 gets moded against the hosts to choose +// from. This is not something an untrusted upstream can affect, and fuzzing must be deterministic, +// so the fuzzer generates a bytestring which represents the random calls. // Logic specific for random load balancers void RandomLoadBalancerFuzzTest::prefetch() { - // TODO: For random calls, persist state in a mock class + // random() calls are handled by fake random load_balancer_->peekAnotherHost(nullptr); } diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz.h index c68931e3edbb..003e65c81670 100644 --- a/test/common/upstream/load_balancer_fuzz.h +++ b/test/common/upstream/load_balancer_fuzz.h @@ -1,12 +1,11 @@ #include "common/upstream/load_balancer_impl.h" #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" -#include "test/common/upstream/load_balancer_impl_test_utils.h" +#include "test/common/upstream/load_balancer_fuzz_test_utils.h" namespace Envoy { namespace Upstream { -// TODO: Perhaps switch this class to a base class class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { public: LoadBalancerFuzzBase(); @@ -18,28 +17,27 @@ class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { virtual void initialize(test::common::upstream::LoadBalancerTestCase input) PURE; void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); - // void addHostSet(uint64_t number_of_hosts_in_host_set); - void updateHealthFlagsForAHostSet( - bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, - uint32_t num_excluded_hosts = 0); // Hostset or int, or mod the int with number of host sets + void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, + uint32_t num_degraded_hosts = 0, + uint32_t num_excluded_hosts = 0); // These two actions have a lot of logic attached to them such as mocks, so you need to delegate // these to specific logic per each specific load balancer. This makes sense, as the load - // balancing algorithms sometimes use other components which are coupled into the algorithm - // logically. + // balancing algorithms sometimes use other components which are tightly coupled into the + // algorithm logically. virtual void prefetch() PURE; virtual void chooseHost() PURE; virtual ~LoadBalancerFuzzBase() = default; private: void replay(test::common::upstream::LoadBalancerTestCase input); - // LoadBalancer load_balancer_; //Will be overriden with specific implementations + // TODO: Move load balancer here? }; class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { public: RandomLoadBalancerFuzzTest(); void initialize(test::common::upstream::LoadBalancerTestCase input) override; - // Has interesting mock logic + // Has mock logic for random void prefetch() override; void chooseHost() override; ~RandomLoadBalancerFuzzTest() = default; @@ -47,5 +45,9 @@ class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { std::unique_ptr load_balancer_; }; +// TODO: Since each load balancer has a specific config, this will need to be addressed in their +// specific base classes. We can do this with an extended proto, which also will contain specific +// logic for mocks + } // namespace Upstream } // namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index fd2ade3ac1c4..346aae680798 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -3,7 +3,6 @@ syntax = "proto3"; package test.common.upstream; import "validate/validate.proto"; -import "test/fuzz/common.proto"; import "envoy/config/cluster/v3/cluster.proto"; import "google/protobuf/empty.proto"; @@ -14,6 +13,7 @@ message UpdateHealthFlags { uint32 num_excluded_hosts = 4; } +//Left as message in case specific load balancers need something generated for these actions message ChooseHost { } @@ -30,13 +30,12 @@ message LbAction { } message LoadBalancerTestCase { - //Link in proto config for load balancing here envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; - //Repeated actions here repeated LbAction actions = 2; - int64 num_hosts_in_priority_set = 3; //Require this and cap it at something - int64 num_hosts_in_failover_set = 4; - //TODO: Any validations on this? - repeated int64 bytestring_for_random_calls = 5; + //This is capped at the max port value on an ip address - 80 + int64 num_hosts_in_priority_set = 3 [(validate.rules).int64.lt = 65455]; + int64 num_hosts_in_failover_set = 4 [(validate.rules).int64.lt = 65455]; + repeated int64 bytestring_for_random_calls = 5 + [(validate.rules).repeated = {min_items: 1, max_items: 50}]; } diff --git a/test/common/upstream/load_balancer_fuzz_test.cc b/test/common/upstream/load_balancer_fuzz_test.cc index 188430c2b2db..8416263a029d 100644 --- a/test/common/upstream/load_balancer_fuzz_test.cc +++ b/test/common/upstream/load_balancer_fuzz_test.cc @@ -15,12 +15,12 @@ DEFINE_PROTO_FUZZER(const test::common::upstream::LoadBalancerTestCase input) { ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); return; } - RandomLoadBalancerFuzzTest load_balancer_fuzz; + std::unique_ptr load_balancer_fuzz; - // TODO: Switch across type, etc.? - // load_balancer_fuzz = RandomLoadBalancerFuzzTest(); + // TODO: Switch across type once added more + load_balancer_fuzz = std::make_unique(); - load_balancer_fuzz.initializeAndReplay(input); + load_balancer_fuzz->initializeAndReplay(input); } } // namespace Upstream diff --git a/test/common/upstream/load_balancer_fuzz_test_utils.cc b/test/common/upstream/load_balancer_fuzz_test_utils.cc new file mode 100644 index 000000000000..ea61c894e329 --- /dev/null +++ b/test/common/upstream/load_balancer_fuzz_test_utils.cc @@ -0,0 +1,12 @@ +#include "test/common/upstream/load_balancer_fuzz_test_utils.h" + +namespace Envoy { +namespace Random { +uint64_t FakeRandomGenerator::random() { + uint8_t index_of_data = counter % bytestring_.size(); + ++counter; + ENVOY_LOG_MISC(trace, "random() returned: {}", bytestring_.at(index_of_data)); + return bytestring_.at(index_of_data); +} +} // namespace Random +} // namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz_test_utils.h b/test/common/upstream/load_balancer_fuzz_test_utils.h new file mode 100644 index 000000000000..79ff1eef3488 --- /dev/null +++ b/test/common/upstream/load_balancer_fuzz_test_utils.h @@ -0,0 +1,48 @@ +#include "envoy/config/cluster/v3/cluster.pb.h" + +#include "common/upstream/load_balancer_impl.h" + +#include "test/mocks/common.h" +#include "test/mocks/runtime/mocks.h" +#include "test/mocks/upstream/cluster_info.h" +#include "test/mocks/upstream/host_set.h" +#include "test/mocks/upstream/load_balancer_context.h" +#include "test/mocks/upstream/priority_set.h" + +namespace Envoy { + +namespace Random { +class FakeRandomGenerator : public RandomGenerator { +public: + FakeRandomGenerator() = default; + ~FakeRandomGenerator() override = default; + + // RandomGenerator + uint64_t random() override; // returns a part of the generated bytestring + std::string uuid() override { return ""; } + uint32_t counter = 0; // Will get modded against byte string length for byte string index + std::vector bytestring_; // String of bytes that returns on random() calls +}; +} // namespace Random + +namespace Upstream { +namespace { + +class LoadBalancerFuzzTestBase { +protected: + LoadBalancerFuzzTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) {} + + Stats::IsolatedStoreImpl stats_store_; + ClusterStats stats_; + NiceMock runtime_; + Random::FakeRandomGenerator random_; + NiceMock priority_set_; + MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); + MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); + std::shared_ptr info_{new NiceMock()}; + envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; +}; + +} // namespace +} // namespace Upstream +} // namespace Envoy diff --git a/test/common/upstream/load_balancer_impl_test_utils.cc b/test/common/upstream/load_balancer_impl_test_utils.cc deleted file mode 100644 index e13819f7985a..000000000000 --- a/test/common/upstream/load_balancer_impl_test_utils.cc +++ /dev/null @@ -1,43 +0,0 @@ -// class LoadBalancerTestBase - -// hostSet() returns a host_set_, constructor generates stats and puts it into a stats variable - -// class TestLb: public LoadBalancerBase, essentiallly an override of the sources load balancer -// This is essentially overriding the source code load balancer, bringing in some methods from it, -// and overriding methods that wont be used - -// class LoadBalancerBaseTest: public LoadBalancerTestBase - -// Util function for updating host sets, config, uses test load balancer, and common config - -// class RoundRobinLoadBalancerTest: public LoadBalancerTestBase - -// init, updateHosts, shared_ptr localPriority sets etc., this might take a while - -// class LeastRequestLoadBalancerTest: public LoadBalancerTestBase - -// all this has is a public load balancer that is typed as a "LeastRequestLoadBalancer" - -// class RandomLoadBalancerTest: public LoadBalancerTestBase - -// Same thing as least request load balancer, except this one is a random load balancer - -// TODO today, scope out how long you think each part of the fuzzer is going to take you, Address -// techincal debt from Adi's comments - -namespace Envoy { -namespace Upstream { -namespace Random { - FakeRandomGenerator::FakeRandomGenerator() { - - } - uint64_t FakeRandomGenerator::random() { - uint8_t index_of_data = counter % bytestring_.size(); - ++counter; - return bytestring.at(index_of_data); - } - -} -} // namespace -} // namespace Upstream -} // namespace Envoy diff --git a/test/common/upstream/load_balancer_impl_test_utils.h b/test/common/upstream/load_balancer_impl_test_utils.h deleted file mode 100644 index 615025839267..000000000000 --- a/test/common/upstream/load_balancer_impl_test_utils.h +++ /dev/null @@ -1,71 +0,0 @@ -#include "envoy/config/cluster/v3/cluster.pb.h" - -#include "common/upstream/load_balancer_impl.h" -#include "test/mocks/common.h" -#include "test/mocks/runtime/mocks.h" -#include "test/mocks/upstream/cluster_info.h" -#include "test/mocks/upstream/host_set.h" -#include "test/mocks/upstream/load_balancer_context.h" -#include "test/mocks/upstream/priority_set.h" - -namespace Envoy { -namespace Upstream { -namespace { - -class LoadBalancerFuzzTestBase { -protected: - LoadBalancerFuzzTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) {} - - Stats::IsolatedStoreImpl stats_store_; - ClusterStats stats_; - NiceMock runtime_; - NiceMock random_; //TODO: override this Random class to persist state and return a number - NiceMock priority_set_; - MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); - MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); - std::shared_ptr info_{new NiceMock()}; - envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; -}; - -class TestLb : public LoadBalancerBase { -public: - TestLb(const PrioritySet& priority_set, ClusterStats& stats, Runtime::Loader& runtime, - Random::RandomGenerator& random, - const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) - : LoadBalancerBase(priority_set, stats, runtime, random, common_config) {} - using LoadBalancerBase::chooseHostSet; - using LoadBalancerBase::isInPanic; - using LoadBalancerBase::percentageDegradedLoad; - using LoadBalancerBase::percentageLoad; - - HostConstSharedPtr chooseHostOnce(LoadBalancerContext*) override { - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; - } - HostConstSharedPtr peekAnotherHost(LoadBalancerContext*) override { - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; - } -}; - -} // namespace -} // namespace Upstream - - -//repeated uint64t exactly 50 times, if it goes over (persist a counter state variable), use % to get rid of it overflowing -namespace Random { - class FakeRandomGenerator : public RandomGenerator { - public: - FakeRandomGenerator(); //construct it with a long string of bytes that it slowly pulls off of - ~FakeRandomGenerator() override; - - uint64_t random() override; //returns first few parts of the generated bytestring - private: - uint32_t counter = 0; //Will get modded against 50 for byte string index - std::vector bytestring_; - } -} - -} // namespace Envoy - - -//Since each load balancer has a specific config, this will need to be addressed in their specific base classes -//We can do this with an extended proto, which also will contain specific logic for mocks From 8c00f1419b8e5d2d2255dcdbcd43603da7a2e271 Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 6 Oct 2020 01:23:29 +0000 Subject: [PATCH 09/34] Got rid of logs Signed-off-by: Zach --- test/common/upstream/load_balancer_impl_test.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index 9a836b896d97..81603a608a65 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -1687,28 +1687,27 @@ TEST_P(LeastRequestLoadBalancerTest, WeightImbalanceCallbacks) { INSTANTIATE_TEST_SUITE_P(PrimaryOrFailover, LeastRequestLoadBalancerTest, ::testing::Values(true, false)); -// Literally all this class does is make a load balancer class RandomLoadBalancerTest : public LoadBalancerTestBase { public: void init() { lb_ = std::make_shared(priority_set_, nullptr, stats_, runtime_, random_, - common_config_); // Priority set gets added here + common_config_); } std::shared_ptr lb_; }; TEST_P(RandomLoadBalancerTest, NoHosts) { - init(); // Create the load balancer + init(); - EXPECT_EQ(nullptr, lb_->peekAnotherHost(nullptr)); // Peek into a host - EXPECT_EQ(nullptr, lb_->chooseHost(nullptr)); // Chooose a host into a host + EXPECT_EQ(nullptr, lb_->peekAnotherHost(nullptr)); + EXPECT_EQ(nullptr, lb_->chooseHost(nullptr)); } TEST_P(RandomLoadBalancerTest, Normal) { - init(); // Create the load balancer - hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80"), // These are healthy hosts + init(); + hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80"), makeTestHost(info_, "tcp://127.0.0.1:81")}; - hostSet().hosts_ = hostSet().healthy_hosts_; // Sets the healthy hosts to this + hostSet().hosts_ = hostSet().healthy_hosts_; hostSet().runCallbacks({}, {}); // Trigger callbacks. The added/removed lists are not relevant. EXPECT_CALL(random_, random()).WillOnce(Return(2)); From 810eb49aa3f6ae233c0f13dd00c2f6a7f49576c3 Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 6 Oct 2020 05:05:45 +0000 Subject: [PATCH 10/34] Spelling Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index 123d7eb52c7b..73797233414c 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -107,7 +107,7 @@ void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancer random_, input.common_lb_config()); } -// For random load balancing, a randomly generated uint64 gets moded against the hosts to choose +// For random load balancing, a randomly generated uint64 gets modded against the hosts to choose // from. This is not something an untrusted upstream can affect, and fuzzing must be deterministic, // so the fuzzer generates a bytestring which represents the random calls. From 413214cbe75331cb5233cb26d94bdcaa68e5c086 Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 6 Oct 2020 19:38:24 +0000 Subject: [PATCH 11/34] First round of comments, saving progress Signed-off-by: Zach --- test/common/upstream/BUILD | 22 ++------- test/common/upstream/load_balancer_fuzz.cc | 14 ++++-- test/common/upstream/load_balancer_fuzz.h | 41 ++++++++++++++-- test/common/upstream/load_balancer_fuzz.proto | 10 ++-- .../upstream/load_balancer_fuzz_test_utils.cc | 12 ----- .../upstream/load_balancer_fuzz_test_utils.h | 48 ------------------- 6 files changed, 57 insertions(+), 90 deletions(-) delete mode 100644 test/common/upstream/load_balancer_fuzz_test_utils.cc delete mode 100644 test/common/upstream/load_balancer_fuzz_test_utils.h diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 2b7b99d89c07..91b6bc8bc116 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -243,15 +243,12 @@ envoy_cc_test( ) envoy_cc_test_library( - name = "load_balancer_impl_test_lib", - srcs = [ - "load_balancer_fuzz_test_utils.cc", - ], - hdrs = [ - "load_balancer_fuzz_test_utils.h", - ], + name = "load_balancer_fuzz_lib", + srcs = ["load_balancer_fuzz.cc"], + hdrs = ["load_balancer_fuzz.h"], deps = [ ":utility_lib", + ":load_balancer_fuzz_proto_cc_proto", "//source/common/upstream:load_balancer_lib", "//test/mocks:common_lib", "//test/mocks/runtime:runtime_mocks", @@ -263,17 +260,6 @@ envoy_cc_test_library( ], ) -envoy_cc_test_library( - name = "load_balancer_fuzz_lib", - srcs = ["load_balancer_fuzz.cc"], - hdrs = ["load_balancer_fuzz.h"], - deps = [ - ":load_balancer_fuzz_proto_cc_proto", - ":load_balancer_impl_test_lib", - "//source/common/upstream:load_balancer_lib", - ], -) - envoy_proto_library( name = "load_balancer_fuzz_proto", srcs = ["load_balancer_fuzz.proto"], diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz.cc index 73797233414c..6ef776149ac6 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz.cc @@ -3,6 +3,16 @@ #include "test/common/upstream/utility.h" namespace Envoy { + +namespace Random { +uint64_t FakeRandomGenerator::random() { + uint8_t index_of_data = counter % bytestring_.size(); + ++counter; + ENVOY_LOG_MISC(trace, "random() returned: {}", bytestring_.at(index_of_data)); + return bytestring_.at(index_of_data); +} +} // namespace Random + namespace Upstream { // Anonymous namespace for helper functions @@ -17,12 +27,8 @@ constructByteVectorForRandom(test::common::upstream::LoadBalancerTestCase input) } } // namespace -// Required because super class constructor has logic -LoadBalancerFuzzBase::LoadBalancerFuzzBase() : LoadBalancerFuzzTestBase() {} - void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, uint32_t num_hosts_in_failover_set) { - // TODO: Cap on ports? int port = 80; for (uint32_t i = 0; i < num_hosts_in_priority_set; ++i) { host_set_.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz.h index 003e65c81670..97ba9cd20dab 100644 --- a/test/common/upstream/load_balancer_fuzz.h +++ b/test/common/upstream/load_balancer_fuzz.h @@ -1,14 +1,39 @@ +#include "envoy/config/cluster/v3/cluster.pb.h" #include "common/upstream/load_balancer_impl.h" +#include "test/mocks/common.h" +#include "test/mocks/runtime/mocks.h" +#include "test/mocks/upstream/cluster_info.h" +#include "test/mocks/upstream/host_set.h" +#include "test/mocks/upstream/load_balancer_context.h" +#include "test/mocks/upstream/priority_set.h" + #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" -#include "test/common/upstream/load_balancer_fuzz_test_utils.h" namespace Envoy { + +namespace Random { +class FakeRandomGenerator : public RandomGenerator { +public: + FakeRandomGenerator() = default; + ~FakeRandomGenerator() override = default; + + // RandomGenerator + uint64_t random() override; // returns a part of the generated bytestring + std::string uuid() override { return ""; } + uint32_t counter = 0; // Will get modded against byte string length for byte string index + std::vector bytestring_; // String of bytes that returns on random() calls +}; +} // namespace Random + namespace Upstream { -class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { +// This class implements replay logic, and also handles the initial setup of static host sets and the subsequent updates to those sets. +class LoadBalancerFuzzBase { public: - LoadBalancerFuzzBase(); + LoadBalancerFuzzBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) { + + }; // Untrusted upstreams don't have the ability to change the host set size, so keep it constant // over the fuzz iteration. @@ -27,9 +52,15 @@ class LoadBalancerFuzzBase : public LoadBalancerFuzzTestBase { virtual void prefetch() PURE; virtual void chooseHost() PURE; virtual ~LoadBalancerFuzzBase() = default; - -private: void replay(test::common::upstream::LoadBalancerTestCase input); + Stats::IsolatedStoreImpl stats_store_; + ClusterStats stats_; + NiceMock runtime_; + Random::FakeRandomGenerator random_; + NiceMock priority_set_; + MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); + MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); + std::shared_ptr info_{new NiceMock()}; // TODO: Move load balancer here? }; diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 346aae680798..ebe52a20aaba 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -29,13 +29,17 @@ message LbAction { } } +//This message represents what LoadBalancerFuzzBase will interact with, performing setup of host sets and calling into load balancers. +//The logic that this message represents and the base class for load balancing fuzzing will be logic that maps to all types of load balancing +//and can be modularly used at the highest level for each load balancer. message LoadBalancerTestCase { envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; repeated LbAction actions = 2; //This is capped at the max port value on an ip address - 80 - int64 num_hosts_in_priority_set = 3 [(validate.rules).int64.lt = 65455]; - int64 num_hosts_in_failover_set = 4 [(validate.rules).int64.lt = 65455]; - repeated int64 bytestring_for_random_calls = 5 + uint32 num_hosts_in_priority_set = 3 [(validate.rules).uint32.lt = 65455]; + uint32 num_hosts_in_failover_set = 4 [(validate.rules).uint32.lt = 65455]; + repeated uint64 bytestring_for_random_calls = 5 [(validate.rules).repeated = {min_items: 1, max_items: 50}]; } +//TODO: make this modular in only setting up static hosts, and running through action stream diff --git a/test/common/upstream/load_balancer_fuzz_test_utils.cc b/test/common/upstream/load_balancer_fuzz_test_utils.cc deleted file mode 100644 index ea61c894e329..000000000000 --- a/test/common/upstream/load_balancer_fuzz_test_utils.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include "test/common/upstream/load_balancer_fuzz_test_utils.h" - -namespace Envoy { -namespace Random { -uint64_t FakeRandomGenerator::random() { - uint8_t index_of_data = counter % bytestring_.size(); - ++counter; - ENVOY_LOG_MISC(trace, "random() returned: {}", bytestring_.at(index_of_data)); - return bytestring_.at(index_of_data); -} -} // namespace Random -} // namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz_test_utils.h b/test/common/upstream/load_balancer_fuzz_test_utils.h deleted file mode 100644 index 79ff1eef3488..000000000000 --- a/test/common/upstream/load_balancer_fuzz_test_utils.h +++ /dev/null @@ -1,48 +0,0 @@ -#include "envoy/config/cluster/v3/cluster.pb.h" - -#include "common/upstream/load_balancer_impl.h" - -#include "test/mocks/common.h" -#include "test/mocks/runtime/mocks.h" -#include "test/mocks/upstream/cluster_info.h" -#include "test/mocks/upstream/host_set.h" -#include "test/mocks/upstream/load_balancer_context.h" -#include "test/mocks/upstream/priority_set.h" - -namespace Envoy { - -namespace Random { -class FakeRandomGenerator : public RandomGenerator { -public: - FakeRandomGenerator() = default; - ~FakeRandomGenerator() override = default; - - // RandomGenerator - uint64_t random() override; // returns a part of the generated bytestring - std::string uuid() override { return ""; } - uint32_t counter = 0; // Will get modded against byte string length for byte string index - std::vector bytestring_; // String of bytes that returns on random() calls -}; -} // namespace Random - -namespace Upstream { -namespace { - -class LoadBalancerFuzzTestBase { -protected: - LoadBalancerFuzzTestBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) {} - - Stats::IsolatedStoreImpl stats_store_; - ClusterStats stats_; - NiceMock runtime_; - Random::FakeRandomGenerator random_; - NiceMock priority_set_; - MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); - MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); - std::shared_ptr info_{new NiceMock()}; - envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_; -}; - -} // namespace -} // namespace Upstream -} // namespace Envoy From b5619fedfce60742a2b84382d56fb6c512799104 Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 6 Oct 2020 23:08:13 +0000 Subject: [PATCH 12/34] Responded to comments and redesigned based on design discussion Signed-off-by: Zach --- test/common/upstream/BUILD | 19 ++++-- .../load_balancer_corpus/random_NoHosts | 2 + .../load_balancer_corpus/random_Normal | 2 + ...h-ba5efdfd9c412a8507087120783fe6529b1ac0cb | 2 + .../random_largest-port-value | 2 + ...cer_fuzz.cc => load_balancer_fuzz_base.cc} | 64 ++++++++----------- ...ancer_fuzz.h => load_balancer_fuzz_base.h} | 56 +++++++--------- .../upstream/load_balancer_fuzz_test.cc | 27 -------- .../upstream/random_load_balancer_fuzz.proto | 11 ++++ .../random_load_balancer_fuzz_test.cc | 37 +++++++++++ 10 files changed, 118 insertions(+), 104 deletions(-) rename test/common/upstream/{load_balancer_fuzz.cc => load_balancer_fuzz_base.cc} (58%) rename test/common/upstream/{load_balancer_fuzz.h => load_balancer_fuzz_base.h} (58%) delete mode 100644 test/common/upstream/load_balancer_fuzz_test.cc create mode 100644 test/common/upstream/random_load_balancer_fuzz.proto create mode 100644 test/common/upstream/random_load_balancer_fuzz_test.cc diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 91b6bc8bc116..d6edaae7e69d 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -244,11 +244,11 @@ envoy_cc_test( envoy_cc_test_library( name = "load_balancer_fuzz_lib", - srcs = ["load_balancer_fuzz.cc"], - hdrs = ["load_balancer_fuzz.h"], + srcs = ["load_balancer_fuzz_base.cc"], + hdrs = ["load_balancer_fuzz_base.h"], deps = [ - ":utility_lib", ":load_balancer_fuzz_proto_cc_proto", + ":utility_lib", "//source/common/upstream:load_balancer_lib", "//test/mocks:common_lib", "//test/mocks/runtime:runtime_mocks", @@ -269,13 +269,22 @@ envoy_proto_library( ], ) +envoy_proto_library( + name = "random_load_balancer_fuzz_proto", + srcs = ["random_load_balancer_fuzz.proto"], + deps = [ + "//test/common/upstream:load_balancer_fuzz_proto", + ], +) + envoy_cc_fuzz_test( - name = "load_balancer_fuzz_test", - srcs = ["load_balancer_fuzz_test.cc"], + name = "random_load_balancer_fuzz_test", + srcs = ["random_load_balancer_fuzz_test.cc"], corpus = "//test/common/upstream:load_balancer_corpus", deps = [ ":load_balancer_fuzz_lib", ":load_balancer_fuzz_proto_cc_proto", + ":random_load_balancer_fuzz_proto_cc_proto", ":utility_lib", "//test/fuzz:utility_lib", ], diff --git a/test/common/upstream/load_balancer_corpus/random_NoHosts b/test/common/upstream/load_balancer_corpus/random_NoHosts index d688810fc353..d75b02137df9 100644 --- a/test/common/upstream/load_balancer_corpus/random_NoHosts +++ b/test/common/upstream/load_balancer_corpus/random_NoHosts @@ -1,3 +1,4 @@ +load_balancer_test_case { common_lb_config { } @@ -14,3 +15,4 @@ actions { num_hosts_in_priority_set: 0 num_hosts_in_failover_set: 0 bytestring_for_random_calls: 0 +} diff --git a/test/common/upstream/load_balancer_corpus/random_Normal b/test/common/upstream/load_balancer_corpus/random_Normal index 0486b87fe1d9..725f4fc14a20 100644 --- a/test/common/upstream/load_balancer_corpus/random_Normal +++ b/test/common/upstream/load_balancer_corpus/random_Normal @@ -1,3 +1,4 @@ +load_balancer_test_case { common_lb_config { } @@ -31,3 +32,4 @@ num_hosts_in_priority_set: 2 num_hosts_in_failover_set: 0 bytestring_for_random_calls: 2 bytestring_for_random_calls: 3 +} diff --git a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb index f57eab590595..543b4422a730 100644 --- a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb +++ b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb @@ -1,3 +1,4 @@ +load_balancer_test_case { common_lb_config { healthy_panic_threshold { value: 2.12199579096527e-314 @@ -29,3 +30,4 @@ num_hosts_in_priority_set: 2 num_hosts_in_failover_set: 9007199258945536 bytestring_for_random_calls: 2 bytestring_for_random_calls: 3 +} diff --git a/test/common/upstream/load_balancer_corpus/random_largest-port-value b/test/common/upstream/load_balancer_corpus/random_largest-port-value index ce1c1de691e8..7df28b458063 100644 --- a/test/common/upstream/load_balancer_corpus/random_largest-port-value +++ b/test/common/upstream/load_balancer_corpus/random_largest-port-value @@ -1,3 +1,4 @@ +load_balancer_test_case { common_lb_config { } @@ -25,3 +26,4 @@ num_hosts_in_priority_set: 65455 num_hosts_in_failover_set: 65455 bytestring_for_random_calls: 2 bytestring_for_random_calls: 3 +} diff --git a/test/common/upstream/load_balancer_fuzz.cc b/test/common/upstream/load_balancer_fuzz_base.cc similarity index 58% rename from test/common/upstream/load_balancer_fuzz.cc rename to test/common/upstream/load_balancer_fuzz_base.cc index 6ef776149ac6..cef0e286aa50 100644 --- a/test/common/upstream/load_balancer_fuzz.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -1,4 +1,4 @@ -#include "test/common/upstream/load_balancer_fuzz.h" +#include "test/common/upstream/load_balancer_fuzz_base.h" #include "test/common/upstream/utility.h" @@ -18,10 +18,10 @@ namespace Upstream { // Anonymous namespace for helper functions namespace { std::vector -constructByteVectorForRandom(test::common::upstream::LoadBalancerTestCase input) { +constructByteVectorForRandom(const Protobuf::RepeatedField& byteString) { std::vector byteVector; - for (int i = 0; i < input.bytestring_for_random_calls().size(); ++i) { - byteVector.push_back(input.bytestring_for_random_calls(i)); + for (int i = 0; i < byteString.size(); ++i) { + byteVector.push_back(byteString.at(i)); } return byteVector; } @@ -42,22 +42,16 @@ void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priorit // TODO: More than two hosts? } -void LoadBalancerFuzzBase::initializeAndReplay(test::common::upstream::LoadBalancerTestCase input) { - // TODO: Keep this random instantiation even in load balancers that don't call into it, or do they - // all? - random_.bytestring_ = constructByteVectorForRandom(input); - try { - initialize(input); // Initializes specific load balancers - } catch (EnvoyException& e) { - ENVOY_LOG_MISC(debug, "EnvoyException: {}", e.what()); - return; - } +// Initializes random and fixed host sets +void LoadBalancerFuzzBase::initializeLbComponents( + test::common::upstream::LoadBalancerTestCase input) { + random_.bytestring_ = constructByteVectorForRandom(input.bytestring_for_random_calls()); initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); - replay(input); } -// So, these should be shared amongst all of the types. Since logically, we're just setting the mock -// priority set to have certain values, we're doing the same thing across all of them here +// Updating host sets is shared amongst all the load balancer tests. Since logically, we're just +// setting the mock priority set to have certain values, and all load balancers interface with host +// sets and their health statuses, this action maps to all load balancers. void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, @@ -80,10 +74,21 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, host_set.runCallbacks({}, {}); } -void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase input) { +void LoadBalancerFuzzBase::prefetch() { + // TODO: context, could generate it in proto action + lb_->peekAnotherHost(nullptr); +} + +void LoadBalancerFuzzBase::chooseHost() { + // TODO: context, could generate it in proto action + lb_->chooseHost(nullptr); +} + +void LoadBalancerFuzzBase::replay( + const Protobuf::RepeatedPtrField& actions) { constexpr auto max_actions = 64; - for (int i = 0; i < std::min(max_actions, input.actions().size()); ++i) { - const auto& event = input.actions(i); + for (int i = 0; i < std::min(max_actions, actions.size()); ++i) { + const auto& event = actions.at(i); ENVOY_LOG_MISC(trace, "Action: {}", event.DebugString()); switch (event.action_selector_case()) { case test::common::upstream::LbAction::kUpdateHealthFlags: { @@ -106,24 +111,5 @@ void LoadBalancerFuzzBase::replay(test::common::upstream::LoadBalancerTestCase i } } -RandomLoadBalancerFuzzTest::RandomLoadBalancerFuzzTest() : LoadBalancerFuzzBase() {} - -void RandomLoadBalancerFuzzTest::initialize(test::common::upstream::LoadBalancerTestCase input) { - load_balancer_ = std::make_unique(priority_set_, nullptr, stats_, runtime_, - random_, input.common_lb_config()); -} - -// For random load balancing, a randomly generated uint64 gets modded against the hosts to choose -// from. This is not something an untrusted upstream can affect, and fuzzing must be deterministic, -// so the fuzzer generates a bytestring which represents the random calls. - -// Logic specific for random load balancers -void RandomLoadBalancerFuzzTest::prefetch() { - // random() calls are handled by fake random - load_balancer_->peekAnotherHost(nullptr); -} - -void RandomLoadBalancerFuzzTest::chooseHost() { load_balancer_->chooseHost(nullptr); } - } // namespace Upstream } // namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz.h b/test/common/upstream/load_balancer_fuzz_base.h similarity index 58% rename from test/common/upstream/load_balancer_fuzz.h rename to test/common/upstream/load_balancer_fuzz_base.h index 97ba9cd20dab..5fba94c393cf 100644 --- a/test/common/upstream/load_balancer_fuzz.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -1,6 +1,8 @@ #include "envoy/config/cluster/v3/cluster.pb.h" + #include "common/upstream/load_balancer_impl.h" +#include "test/common/upstream/load_balancer_fuzz.pb.validate.h" #include "test/mocks/common.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/upstream/cluster_info.h" @@ -8,8 +10,6 @@ #include "test/mocks/upstream/load_balancer_context.h" #include "test/mocks/upstream/priority_set.h" -#include "test/common/upstream/load_balancer_fuzz.pb.validate.h" - namespace Envoy { namespace Random { @@ -28,31 +28,37 @@ class FakeRandomGenerator : public RandomGenerator { namespace Upstream { -// This class implements replay logic, and also handles the initial setup of static host sets and the subsequent updates to those sets. +// This class implements replay logic, and also handles the initial setup of static host sets and +// the subsequent updates to those sets. class LoadBalancerFuzzBase { public: - LoadBalancerFuzzBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)) { - - }; + LoadBalancerFuzzBase() + : stats_(ClusterInfoImpl::generateStats(stats_store_)){ + + }; // Untrusted upstreams don't have the ability to change the host set size, so keep it constant // over the fuzz iteration. void initializeFixedHostSets(uint32_t num_hosts_in_priority_set, uint32_t num_hosts_in_failover_set); - virtual void initialize(test::common::upstream::LoadBalancerTestCase input) PURE; - void initializeAndReplay(test::common::upstream::LoadBalancerTestCase input); + // Initializes load balancer components shared amongst every load balancer, random_, and + // priority_set_ + void initializeLbComponents(test::common::upstream::LoadBalancerTestCase input); void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts = 0, uint32_t num_excluded_hosts = 0); - // These two actions have a lot of logic attached to them such as mocks, so you need to delegate - // these to specific logic per each specific load balancer. This makes sense, as the load - // balancing algorithms sometimes use other components which are tightly coupled into the - // algorithm logically. - virtual void prefetch() PURE; - virtual void chooseHost() PURE; - virtual ~LoadBalancerFuzzBase() = default; - void replay(test::common::upstream::LoadBalancerTestCase input); + // These two actions have a lot of logic attached to them. However, all the logic that the load + // balancer needs to run its algorithm is already encapsulated within the load balancer. Thus, + // once the load balancer is constructed, all this class has to do is call lb_->peekAnotherHost() + // and lb_->chooseHost(). + void prefetch(); + void chooseHost(); + ~LoadBalancerFuzzBase() = default; + void replay(const Protobuf::RepeatedPtrField& actions); + + // These public objects shared amongst all types of load balancers will be used to construct load + // balancers in specific load balancer fuzz classes Stats::IsolatedStoreImpl stats_store_; ClusterStats stats_; NiceMock runtime_; @@ -61,24 +67,8 @@ class LoadBalancerFuzzBase { MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); std::shared_ptr info_{new NiceMock()}; - // TODO: Move load balancer here? + std::unique_ptr lb_; }; -class RandomLoadBalancerFuzzTest : public LoadBalancerFuzzBase { -public: - RandomLoadBalancerFuzzTest(); - void initialize(test::common::upstream::LoadBalancerTestCase input) override; - // Has mock logic for random - void prefetch() override; - void chooseHost() override; - ~RandomLoadBalancerFuzzTest() = default; - - std::unique_ptr load_balancer_; -}; - -// TODO: Since each load balancer has a specific config, this will need to be addressed in their -// specific base classes. We can do this with an extended proto, which also will contain specific -// logic for mocks - } // namespace Upstream } // namespace Envoy diff --git a/test/common/upstream/load_balancer_fuzz_test.cc b/test/common/upstream/load_balancer_fuzz_test.cc deleted file mode 100644 index 8416263a029d..000000000000 --- a/test/common/upstream/load_balancer_fuzz_test.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Mod it across host sets to determine which one to use - -#include "test/common/upstream/load_balancer_fuzz.h" -#include "test/common/upstream/load_balancer_fuzz.pb.validate.h" -#include "test/fuzz/fuzz_runner.h" -#include "test/test_common/utility.h" - -namespace Envoy { -namespace Upstream { - -DEFINE_PROTO_FUZZER(const test::common::upstream::LoadBalancerTestCase input) { - try { - TestUtility::validate(input); - } catch (const ProtoValidationException& e) { - ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); - return; - } - std::unique_ptr load_balancer_fuzz; - - // TODO: Switch across type once added more - load_balancer_fuzz = std::make_unique(); - - load_balancer_fuzz->initializeAndReplay(input); -} - -} // namespace Upstream -} // namespace Envoy diff --git a/test/common/upstream/random_load_balancer_fuzz.proto b/test/common/upstream/random_load_balancer_fuzz.proto new file mode 100644 index 000000000000..ba277976d0fe --- /dev/null +++ b/test/common/upstream/random_load_balancer_fuzz.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package test.common.upstream; + +import "validate/validate.proto"; +import "test/common/upstream/load_balancer_fuzz.proto"; + +//This has no specific logic needed for initialization +message RandomLoadBalancerTestCase { + LoadBalancerTestCase load_balancer_test_case = 1 [(validate.rules).message.required = true]; +} diff --git a/test/common/upstream/random_load_balancer_fuzz_test.cc b/test/common/upstream/random_load_balancer_fuzz_test.cc new file mode 100644 index 000000000000..8b0249daeee4 --- /dev/null +++ b/test/common/upstream/random_load_balancer_fuzz_test.cc @@ -0,0 +1,37 @@ +// Mod it across host sets to determine which one to use + +#include "test/common/upstream/load_balancer_fuzz_base.h" +#include "test/common/upstream/random_load_balancer_fuzz.pb.validate.h" +#include "test/fuzz/fuzz_runner.h" +#include "test/test_common/utility.h" +#include + +namespace Envoy { +namespace Upstream { + +DEFINE_PROTO_FUZZER(const test::common::upstream::RandomLoadBalancerTestCase input) { + try { + TestUtility::validate(input); + } catch (const ProtoValidationException& e) { + ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); + return; + } + + std::unique_ptr load_balancer_fuzz = std::make_unique(); + load_balancer_fuzz->initializeLbComponents(input.load_balancer_test_case()); + + try { + load_balancer_fuzz->lb_ = std::make_unique( + load_balancer_fuzz->priority_set_, nullptr, load_balancer_fuzz->stats_, + load_balancer_fuzz->runtime_, load_balancer_fuzz->random_, + input.load_balancer_test_case().common_lb_config()); + } catch (EnvoyException& e) { + ENVOY_LOG_MISC(debug, "EnvoyException; {}", e.what()); + return; + } + + load_balancer_fuzz->replay(input.load_balancer_test_case().actions()); +} + +} // namespace Upstream +} // namespace Envoy From c4a53c0d797f5fd52ba0732a13ea4a7d8693142a Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 6 Oct 2020 23:16:53 +0000 Subject: [PATCH 13/34] Clean up Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 12 ++---------- .../upstream/random_load_balancer_fuzz_test.cc | 6 +++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index ebe52a20aaba..84b53ab93fd0 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -13,19 +13,12 @@ message UpdateHealthFlags { uint32 num_excluded_hosts = 4; } -//Left as message in case specific load balancers need something generated for these actions -message ChooseHost { -} - -message Prefetch { -} - message LbAction { oneof action_selector { option (validate.required) = true; UpdateHealthFlags update_health_flags = 1; - Prefetch prefetch = 2; - ChooseHost choose_host = 3; + google.protobuf.Empty prefetch = 2; + google.protobuf.Empty choose_host = 3; } } @@ -42,4 +35,3 @@ message LoadBalancerTestCase { repeated uint64 bytestring_for_random_calls = 5 [(validate.rules).repeated = {min_items: 1, max_items: 50}]; } -//TODO: make this modular in only setting up static hosts, and running through action stream diff --git a/test/common/upstream/random_load_balancer_fuzz_test.cc b/test/common/upstream/random_load_balancer_fuzz_test.cc index 8b0249daeee4..b922d0862cd4 100644 --- a/test/common/upstream/random_load_balancer_fuzz_test.cc +++ b/test/common/upstream/random_load_balancer_fuzz_test.cc @@ -1,10 +1,9 @@ -// Mod it across host sets to determine which one to use +#include #include "test/common/upstream/load_balancer_fuzz_base.h" #include "test/common/upstream/random_load_balancer_fuzz.pb.validate.h" #include "test/fuzz/fuzz_runner.h" #include "test/test_common/utility.h" -#include namespace Envoy { namespace Upstream { @@ -17,7 +16,8 @@ DEFINE_PROTO_FUZZER(const test::common::upstream::RandomLoadBalancerTestCase inp return; } - std::unique_ptr load_balancer_fuzz = std::make_unique(); + std::unique_ptr load_balancer_fuzz = + std::make_unique(); load_balancer_fuzz->initializeLbComponents(input.load_balancer_test_case()); try { From 6bcb3946ac4799805f57d259c2b44f5b41de834b Mon Sep 17 00:00:00 2001 From: Zach Date: Wed, 7 Oct 2020 21:05:34 +0000 Subject: [PATCH 14/34] Responded to Asra's comments Signed-off-by: Zach --- test/common/upstream/BUILD | 1 - .../load_balancer_corpus/random_max_ports | 35 +++++++++++++++++++ .../random_overflowing_ports | 35 +++++++++++++++++++ test/common/upstream/load_balancer_fuzz.proto | 11 ++++-- .../upstream/load_balancer_fuzz_base.cc | 21 ++++++----- .../common/upstream/load_balancer_fuzz_base.h | 10 ++---- .../random_load_balancer_fuzz_test.cc | 2 +- 7 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 test/common/upstream/load_balancer_corpus/random_max_ports create mode 100644 test/common/upstream/load_balancer_corpus/random_overflowing_ports diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index d6edaae7e69d..55b6e92ba2ba 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -286,7 +286,6 @@ envoy_cc_fuzz_test( ":load_balancer_fuzz_proto_cc_proto", ":random_load_balancer_fuzz_proto_cc_proto", ":utility_lib", - "//test/fuzz:utility_lib", ], ) diff --git a/test/common/upstream/load_balancer_corpus/random_max_ports b/test/common/upstream/load_balancer_corpus/random_max_ports new file mode 100644 index 000000000000..48d1b7d8473a --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_max_ports @@ -0,0 +1,35 @@ +load_balancer_test_case { +common_lb_config { + +} +actions { + update_health_flags { + failover_host_set: false + num_healthy_hosts: 2 + } +} +actions { + prefetch { + + } +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +num_hosts_in_priority_set: 32726 +num_hosts_in_failover_set: 32726 +bytestring_for_random_calls: 2 +bytestring_for_random_calls: 3 +} diff --git a/test/common/upstream/load_balancer_corpus/random_overflowing_ports b/test/common/upstream/load_balancer_corpus/random_overflowing_ports new file mode 100644 index 000000000000..f036de0abcac --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_overflowing_ports @@ -0,0 +1,35 @@ +load_balancer_test_case { +common_lb_config { + +} +actions { + update_health_flags { + failover_host_set: false + num_healthy_hosts: 2 + } +} +actions { + prefetch { + + } +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +num_hosts_in_priority_set: 60000 +num_hosts_in_failover_set: 60000 +bytestring_for_random_calls: 2 +bytestring_for_random_calls: 3 +} diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 84b53ab93fd0..2f72b5726c81 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -7,6 +7,7 @@ import "envoy/config/cluster/v3/cluster.proto"; import "google/protobuf/empty.proto"; message UpdateHealthFlags { + //The boolean corresponds to whether this action updates the failover set or not bool failover_host_set = 1; uint32 num_healthy_hosts = 2; uint32 num_degraded_hosts = 3; @@ -29,9 +30,13 @@ message LoadBalancerTestCase { envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; repeated LbAction actions = 2; - //This is capped at the max port value on an ip address - 80 - uint32 num_hosts_in_priority_set = 3 [(validate.rules).uint32.lt = 65455]; - uint32 num_hosts_in_failover_set = 4 [(validate.rules).uint32.lt = 65455]; + //Ports of hosts constructed range from 80 - 65455, all on the same Ip Address + //These caps make sure that the port of the hosts constructed does not overflow + uint32 num_hosts_in_priority_set = 3 [(validate.rules).uint32.lt = 32727]; + uint32 num_hosts_in_failover_set = 4 [(validate.rules).uint32.lt = 32727]; + //Sequential uint64_t's that will return from random() calls in the random generator. + //Generating the data in the proto makes it deterministic and also makes it follow a + //true random distribution. Capped at 50 for space efficiency. repeated uint64 bytestring_for_random_calls = 5 [(validate.rules).repeated = {min_items: 1, max_items: 50}]; } diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index cef0e286aa50..0f1f6373353c 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -18,10 +18,11 @@ namespace Upstream { // Anonymous namespace for helper functions namespace { std::vector -constructByteVectorForRandom(const Protobuf::RepeatedField& byteString) { +constructByteVectorForRandom(const Protobuf::RepeatedField& byte_string) { std::vector byteVector; - for (int i = 0; i < byteString.size(); ++i) { - byteVector.push_back(byteString.at(i)); + byteVector.reserve(byte_string.size()); + for (const auto eightBytes : byte_string) { + byteVector.push_back(eightBytes); } return byteVector; } @@ -39,12 +40,12 @@ void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priorit makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); ++port; } - // TODO: More than two hosts? + // TODO(zasweq): More than two host sets? } // Initializes random and fixed host sets void LoadBalancerFuzzBase::initializeLbComponents( - test::common::upstream::LoadBalancerTestCase input) { + const test::common::upstream::LoadBalancerTestCase& input) { random_.bytestring_ = constructByteVectorForRandom(input.bytestring_for_random_calls()); initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); } @@ -57,16 +58,17 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts) { MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); + // Will not overflow because size is capped by port numbers + uint32_t host_set_size = host_set.hosts_.size(); uint32_t i = 0; - for (; i < num_healthy_hosts && i < host_set.hosts_.size(); ++i) { + for (; i < std::min(num_healthy_hosts, host_set_size); ++i) { host_set.healthy_hosts_.push_back(host_set.hosts_[i]); } - for (; i < (num_healthy_hosts + num_degraded_hosts) && i < host_set.hosts_.size(); ++i) { + for (; i < std::min(num_healthy_hosts + num_degraded_hosts, host_set_size); ++i) { host_set.degraded_hosts_.push_back(host_set.hosts_[i]); } - for (; i < (num_healthy_hosts + num_degraded_hosts + num_excluded_hosts) && - i < host_set.hosts_.size(); + for (; i < std::min(num_healthy_hosts + num_degraded_hosts + num_excluded_hosts, host_set_size); ++i) { host_set.excluded_hosts_.push_back(host_set.hosts_[i]); } @@ -93,6 +95,7 @@ void LoadBalancerFuzzBase::replay( switch (event.action_selector_case()) { case test::common::upstream::LbAction::kUpdateHealthFlags: { updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), + event.update_health_flags().num_healthy_hosts(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts()); break; diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 5fba94c393cf..6ecdbaf562ef 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -32,10 +32,7 @@ namespace Upstream { // the subsequent updates to those sets. class LoadBalancerFuzzBase { public: - LoadBalancerFuzzBase() - : stats_(ClusterInfoImpl::generateStats(stats_store_)){ - - }; + LoadBalancerFuzzBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)){}; // Untrusted upstreams don't have the ability to change the host set size, so keep it constant // over the fuzz iteration. @@ -44,10 +41,9 @@ class LoadBalancerFuzzBase { // Initializes load balancer components shared amongst every load balancer, random_, and // priority_set_ - void initializeLbComponents(test::common::upstream::LoadBalancerTestCase input); + void initializeLbComponents(const test::common::upstream::LoadBalancerTestCase& input); void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, - uint32_t num_degraded_hosts = 0, - uint32_t num_excluded_hosts = 0); + uint32_t num_degraded_hosts, uint32_t num_excluded_hosts); // These two actions have a lot of logic attached to them. However, all the logic that the load // balancer needs to run its algorithm is already encapsulated within the load balancer. Thus, // once the load balancer is constructed, all this class has to do is call lb_->peekAnotherHost() diff --git a/test/common/upstream/random_load_balancer_fuzz_test.cc b/test/common/upstream/random_load_balancer_fuzz_test.cc index b922d0862cd4..e3ab92bee76d 100644 --- a/test/common/upstream/random_load_balancer_fuzz_test.cc +++ b/test/common/upstream/random_load_balancer_fuzz_test.cc @@ -8,7 +8,7 @@ namespace Envoy { namespace Upstream { -DEFINE_PROTO_FUZZER(const test::common::upstream::RandomLoadBalancerTestCase input) { +DEFINE_PROTO_FUZZER(const test::common::upstream::RandomLoadBalancerTestCase& input) { try { TestUtility::validate(input); } catch (const ProtoValidationException& e) { From ea0264a9e774e1c56d9d17e3150434994d4c7ddf Mon Sep 17 00:00:00 2001 From: Zach Date: Thu, 8 Oct 2020 17:22:57 +0000 Subject: [PATCH 15/34] Save progress, responded to Alex's comments and some Harvey comments Signed-off-by: Zach --- .../load_balancer_corpus/random_NoHosts | 2 +- .../load_balancer_corpus/random_Normal | 3 +- ...h-ba5efdfd9c412a8507087120783fe6529b1ac0cb | 3 +- .../random_largest-port-value | 3 +- .../random_many_choose_hosts | 54 +++++++++++++ .../load_balancer_corpus/random_max_ports | 3 +- .../random_overflowing_ports | 3 +- test/common/upstream/load_balancer_fuzz.proto | 9 +-- .../upstream/load_balancer_fuzz_base.cc | 75 ++++++++++++------- .../common/upstream/load_balancer_fuzz_base.h | 15 +++- .../random_load_balancer_fuzz_test.cc | 13 ++-- 11 files changed, 127 insertions(+), 56 deletions(-) create mode 100644 test/common/upstream/load_balancer_corpus/random_many_choose_hosts diff --git a/test/common/upstream/load_balancer_corpus/random_NoHosts b/test/common/upstream/load_balancer_corpus/random_NoHosts index d75b02137df9..dd0182f379cb 100644 --- a/test/common/upstream/load_balancer_corpus/random_NoHosts +++ b/test/common/upstream/load_balancer_corpus/random_NoHosts @@ -14,5 +14,5 @@ actions { } num_hosts_in_priority_set: 0 num_hosts_in_failover_set: 0 -bytestring_for_random_calls: 0 +seed_for_prng: 2 } diff --git a/test/common/upstream/load_balancer_corpus/random_Normal b/test/common/upstream/load_balancer_corpus/random_Normal index 725f4fc14a20..66d10e480b7b 100644 --- a/test/common/upstream/load_balancer_corpus/random_Normal +++ b/test/common/upstream/load_balancer_corpus/random_Normal @@ -30,6 +30,5 @@ actions { } num_hosts_in_priority_set: 2 num_hosts_in_failover_set: 0 -bytestring_for_random_calls: 2 -bytestring_for_random_calls: 3 +seed_for_prng: 1 } diff --git a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb index 543b4422a730..15b484674c52 100644 --- a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb +++ b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb @@ -28,6 +28,5 @@ actions { } num_hosts_in_priority_set: 2 num_hosts_in_failover_set: 9007199258945536 -bytestring_for_random_calls: 2 -bytestring_for_random_calls: 3 +seed_for_prng: 6 } diff --git a/test/common/upstream/load_balancer_corpus/random_largest-port-value b/test/common/upstream/load_balancer_corpus/random_largest-port-value index 7df28b458063..5e29cff14ab6 100644 --- a/test/common/upstream/load_balancer_corpus/random_largest-port-value +++ b/test/common/upstream/load_balancer_corpus/random_largest-port-value @@ -24,6 +24,5 @@ actions { } num_hosts_in_priority_set: 65455 num_hosts_in_failover_set: 65455 -bytestring_for_random_calls: 2 -bytestring_for_random_calls: 3 +seed_for_prng: 5 } diff --git a/test/common/upstream/load_balancer_corpus/random_many_choose_hosts b/test/common/upstream/load_balancer_corpus/random_many_choose_hosts new file mode 100644 index 000000000000..6214937612c8 --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_many_choose_hosts @@ -0,0 +1,54 @@ +load_balancer_test_case { +common_lb_config { + +} +actions { + update_health_flags { + failover_host_set: false + num_healthy_hosts: 2 + } +} +actions { + prefetch { + + } +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +num_hosts_in_priority_set: 2 +num_hosts_in_failover_set: 0 +seed_for_prng: 1 +} diff --git a/test/common/upstream/load_balancer_corpus/random_max_ports b/test/common/upstream/load_balancer_corpus/random_max_ports index 48d1b7d8473a..cf60129bff8c 100644 --- a/test/common/upstream/load_balancer_corpus/random_max_ports +++ b/test/common/upstream/load_balancer_corpus/random_max_ports @@ -30,6 +30,5 @@ actions { } num_hosts_in_priority_set: 32726 num_hosts_in_failover_set: 32726 -bytestring_for_random_calls: 2 -bytestring_for_random_calls: 3 +seed_for_prng: 88 } diff --git a/test/common/upstream/load_balancer_corpus/random_overflowing_ports b/test/common/upstream/load_balancer_corpus/random_overflowing_ports index f036de0abcac..aeb04730d1b6 100644 --- a/test/common/upstream/load_balancer_corpus/random_overflowing_ports +++ b/test/common/upstream/load_balancer_corpus/random_overflowing_ports @@ -30,6 +30,5 @@ actions { } num_hosts_in_priority_set: 60000 num_hosts_in_failover_set: 60000 -bytestring_for_random_calls: 2 -bytestring_for_random_calls: 3 +seed_for_prng: 4 } diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 2f72b5726c81..bc9e73e8aad0 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -7,7 +7,7 @@ import "envoy/config/cluster/v3/cluster.proto"; import "google/protobuf/empty.proto"; message UpdateHealthFlags { - //The boolean corresponds to whether this action updates the failover set or not + // The boolean corresponds to whether this action updates the failover set or not bool failover_host_set = 1; uint32 num_healthy_hosts = 2; uint32 num_degraded_hosts = 3; @@ -34,9 +34,6 @@ message LoadBalancerTestCase { //These caps make sure that the port of the hosts constructed does not overflow uint32 num_hosts_in_priority_set = 3 [(validate.rules).uint32.lt = 32727]; uint32 num_hosts_in_failover_set = 4 [(validate.rules).uint32.lt = 32727]; - //Sequential uint64_t's that will return from random() calls in the random generator. - //Generating the data in the proto makes it deterministic and also makes it follow a - //true random distribution. Capped at 50 for space efficiency. - repeated uint64 bytestring_for_random_calls = 5 - [(validate.rules).repeated = {min_items: 1, max_items: 50}]; + //This number is used to instantiate the prng. The prng takes the place of random() calls, allowing a representative random distribution which is also deterministic. + uint64 seed_for_prng = 5 [(validate.rules).uint64.gt = 0]; } diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 0f1f6373353c..333561176fc0 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -3,31 +3,8 @@ #include "test/common/upstream/utility.h" namespace Envoy { - -namespace Random { -uint64_t FakeRandomGenerator::random() { - uint8_t index_of_data = counter % bytestring_.size(); - ++counter; - ENVOY_LOG_MISC(trace, "random() returned: {}", bytestring_.at(index_of_data)); - return bytestring_.at(index_of_data); -} -} // namespace Random - namespace Upstream { -// Anonymous namespace for helper functions -namespace { -std::vector -constructByteVectorForRandom(const Protobuf::RepeatedField& byte_string) { - std::vector byteVector; - byteVector.reserve(byte_string.size()); - for (const auto eightBytes : byte_string) { - byteVector.push_back(eightBytes); - } - return byteVector; -} -} // namespace - void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, uint32_t num_hosts_in_failover_set) { int port = 80; @@ -46,10 +23,51 @@ void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priorit // Initializes random and fixed host sets void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { - random_.bytestring_ = constructByteVectorForRandom(input.bytestring_for_random_calls()); + random_.initialize(input.seed_for_prng()); initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); } +//TODO: Mod it against the remaining hosts, have two sets where you take index out of one and put it in the other, or even just a set of indexes that you remove from +void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, + uint32_t num_healthy_hosts, + uint32_t num_degraded_hosts, + uint32_t num_excluded_hosts) { + MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); + // This downcast will not overflow because size is capped by port numbers + uint32_t host_set_size = host_set.hosts_.size(); + host_set.healthy_hosts_.clear(); + host_set.degraded_hosts_.clear(); + host_set.excluded_hosts_.clear(); + uint32_t i = 0; + //construct a vector here representing remaining indexes, an index will randomly get chosen from here every time and removed. Thus, this represents the remaining indexes + //When this goes to zero, there will be no more indexes left to place into healthy, degraded, and excluded hosts. + std::vector indexVector; + byteVector.reserve(host_set_size); + for (uint8_t i = 0; i < host_set_size; i++) { + indexVector.push_back(i); + } + + //Handle healthy hosts + for (uint32_t i = 0; i < num_healthy_hosts && indexVector.size() != 0; i++) { + uint64_t index = random_.random() % indexVector.size(); //does this size() return a uint64_t? also, should I add logs here? + host_set.healthy_hosts_.push_back(host_set.hosts_[index]); + } + + //Handle degraded hosts + for (uint32_t i = 0; i < num_degraded_hosts && indexVector.size() != 0; i++) { + uint64_t index = random_.random() % indexVector.size(); //does this size() return a uint64_t? + host_set.degraded_hosts_.push_back(host_set.hosts_[index]); + } + + //Handle excluded hosts + for (uint32_t i = 0; i < num_excluded_hosts && indexVector.size() != 0; i++) { + uint64_t index = random_.random() % indexVector.size(); //does this size() return a uint64_t? + host_set.excluded_hosts_.push_back(host_set.hosts_[index]); + } + + host_set.runCallbacks({}, {}); +} + // Updating host sets is shared amongst all the load balancer tests. Since logically, we're just // setting the mock priority set to have certain values, and all load balancers interface with host // sets and their health statuses, this action maps to all load balancers. @@ -60,9 +78,10 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); // Will not overflow because size is capped by port numbers uint32_t host_set_size = host_set.hosts_.size(); + //TODO: Clear vectors? uint32_t i = 0; for (; i < std::min(num_healthy_hosts, host_set_size); ++i) { - host_set.healthy_hosts_.push_back(host_set.hosts_[i]); + host_set.healthy_hosts_.push_back(host_set.hosts_[i]); //TODO: Preallocate space in this vector } for (; i < std::min(num_healthy_hosts + num_degraded_hosts, host_set_size); ++i) { host_set.degraded_hosts_.push_back(host_set.hosts_[i]); @@ -100,14 +119,12 @@ void LoadBalancerFuzzBase::replay( event.update_health_flags().num_excluded_hosts()); break; } - case test::common::upstream::LbAction::kPrefetch: { + case test::common::upstream::LbAction::kPrefetch: prefetch(); break; - } - case test::common::upstream::LbAction::kChooseHost: { + case test::common::upstream::LbAction::kChooseHost: chooseHost(); break; - } default: break; } diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 6ecdbaf562ef..66da987cc09c 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -1,5 +1,7 @@ #include "envoy/config/cluster/v3/cluster.pb.h" +#include + #include "common/upstream/load_balancer_impl.h" #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" @@ -18,11 +20,18 @@ class FakeRandomGenerator : public RandomGenerator { FakeRandomGenerator() = default; ~FakeRandomGenerator() override = default; + void initialize(uint64_t seed) { + prng_ = std::make_unique(seed); + } + // RandomGenerator - uint64_t random() override; // returns a part of the generated bytestring + uint64_t random() override { + uint64_t toReturn = (*prng_.get())(); //For logging purposes + ENVOY_LOG_MISC(trace, "random() returned: {}", toReturn); + return toReturn; + } std::string uuid() override { return ""; } - uint32_t counter = 0; // Will get modded against byte string length for byte string index - std::vector bytestring_; // String of bytes that returns on random() calls + std::unique_ptr prng_; }; } // namespace Random diff --git a/test/common/upstream/random_load_balancer_fuzz_test.cc b/test/common/upstream/random_load_balancer_fuzz_test.cc index e3ab92bee76d..6d5700654989 100644 --- a/test/common/upstream/random_load_balancer_fuzz_test.cc +++ b/test/common/upstream/random_load_balancer_fuzz_test.cc @@ -16,21 +16,20 @@ DEFINE_PROTO_FUZZER(const test::common::upstream::RandomLoadBalancerTestCase& in return; } - std::unique_ptr load_balancer_fuzz = - std::make_unique(); - load_balancer_fuzz->initializeLbComponents(input.load_balancer_test_case()); + LoadBalancerFuzzBase load_balancer_fuzz = LoadBalancerFuzzBase(); + load_balancer_fuzz.initializeLbComponents(input.load_balancer_test_case()); try { - load_balancer_fuzz->lb_ = std::make_unique( - load_balancer_fuzz->priority_set_, nullptr, load_balancer_fuzz->stats_, - load_balancer_fuzz->runtime_, load_balancer_fuzz->random_, + load_balancer_fuzz.lb_ = std::make_unique( + load_balancer_fuzz.priority_set_, nullptr, load_balancer_fuzz.stats_, + load_balancer_fuzz.runtime_, load_balancer_fuzz.random_, input.load_balancer_test_case().common_lb_config()); } catch (EnvoyException& e) { ENVOY_LOG_MISC(debug, "EnvoyException; {}", e.what()); return; } - load_balancer_fuzz->replay(input.load_balancer_test_case().actions()); + load_balancer_fuzz.replay(input.load_balancer_test_case().actions()); } } // namespace Upstream From e43bb2c20d18672ef4e4badc15046a806f4f313c Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 9 Oct 2020 00:31:42 +0000 Subject: [PATCH 16/34] Responded to Harvey's comments Signed-off-by: Zach --- .../load_balancer_corpus/random_NoHosts | 4 +- .../load_balancer_corpus/random_Normal | 6 +- ...h-ba5efdfd9c412a8507087120783fe6529b1ac0cb | 4 +- .../random_largest-port-value | 4 +- .../random_many_choose_hosts | 6 +- .../load_balancer_corpus/random_max_ports | 2 +- .../random_overflowing_ports | 6 +- .../random_test_something | 34 ++++++ test/common/upstream/load_balancer_fuzz.proto | 14 +-- .../upstream/load_balancer_fuzz_base.cc | 102 ++++++++---------- .../common/upstream/load_balancer_fuzz_base.h | 23 ++-- 11 files changed, 115 insertions(+), 90 deletions(-) create mode 100644 test/common/upstream/load_balancer_corpus/random_test_something diff --git a/test/common/upstream/load_balancer_corpus/random_NoHosts b/test/common/upstream/load_balancer_corpus/random_NoHosts index dd0182f379cb..98f50013c017 100644 --- a/test/common/upstream/load_balancer_corpus/random_NoHosts +++ b/test/common/upstream/load_balancer_corpus/random_NoHosts @@ -12,7 +12,7 @@ actions { } } -num_hosts_in_priority_set: 0 -num_hosts_in_failover_set: 0 +num_hosts_in_host_set: 0 +num_hosts_in_host_set: 0 seed_for_prng: 2 } diff --git a/test/common/upstream/load_balancer_corpus/random_Normal b/test/common/upstream/load_balancer_corpus/random_Normal index 66d10e480b7b..3347434dc436 100644 --- a/test/common/upstream/load_balancer_corpus/random_Normal +++ b/test/common/upstream/load_balancer_corpus/random_Normal @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - failover_host_set: false + host_index: 0 num_healthy_hosts: 2 } } @@ -28,7 +28,7 @@ actions { } } -num_hosts_in_priority_set: 2 -num_hosts_in_failover_set: 0 +num_hosts_in_host_set: 2 +num_hosts_in_host_set: 0 seed_for_prng: 1 } diff --git a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb index 15b484674c52..7a30c203dd20 100644 --- a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb +++ b/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb @@ -26,7 +26,7 @@ actions { choose_host { } } -num_hosts_in_priority_set: 2 -num_hosts_in_failover_set: 9007199258945536 +num_hosts_in_host_set: 2 +num_hosts_in_host_set: 9007199258945536 seed_for_prng: 6 } diff --git a/test/common/upstream/load_balancer_corpus/random_largest-port-value b/test/common/upstream/load_balancer_corpus/random_largest-port-value index 5e29cff14ab6..0d9fbda247fd 100644 --- a/test/common/upstream/load_balancer_corpus/random_largest-port-value +++ b/test/common/upstream/load_balancer_corpus/random_largest-port-value @@ -22,7 +22,7 @@ actions { choose_host { } } -num_hosts_in_priority_set: 65455 -num_hosts_in_failover_set: 65455 +num_hosts_in_host_set: 65455 +num_hosts_in_host_set: 65455 seed_for_prng: 5 } diff --git a/test/common/upstream/load_balancer_corpus/random_many_choose_hosts b/test/common/upstream/load_balancer_corpus/random_many_choose_hosts index 6214937612c8..4847c31741a1 100644 --- a/test/common/upstream/load_balancer_corpus/random_many_choose_hosts +++ b/test/common/upstream/load_balancer_corpus/random_many_choose_hosts @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - failover_host_set: false + host_index: 0 num_healthy_hosts: 2 } } @@ -48,7 +48,7 @@ actions { } } -num_hosts_in_priority_set: 2 -num_hosts_in_failover_set: 0 +num_hosts_in_host_set: 2 +num_hosts_in_host_set: 0 seed_for_prng: 1 } diff --git a/test/common/upstream/load_balancer_corpus/random_max_ports b/test/common/upstream/load_balancer_corpus/random_max_ports index cf60129bff8c..7d4285ee5397 100644 --- a/test/common/upstream/load_balancer_corpus/random_max_ports +++ b/test/common/upstream/load_balancer_corpus/random_max_ports @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - failover_host_set: false + host_index: 0 num_healthy_hosts: 2 } } diff --git a/test/common/upstream/load_balancer_corpus/random_overflowing_ports b/test/common/upstream/load_balancer_corpus/random_overflowing_ports index aeb04730d1b6..e425c3d14da5 100644 --- a/test/common/upstream/load_balancer_corpus/random_overflowing_ports +++ b/test/common/upstream/load_balancer_corpus/random_overflowing_ports @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - failover_host_set: false + host_index: 0 num_healthy_hosts: 2 } } @@ -28,7 +28,7 @@ actions { } } -num_hosts_in_priority_set: 60000 -num_hosts_in_failover_set: 60000 +num_hosts_in_host_set: 60000 +num_hosts_in_host_set: 60000 seed_for_prng: 4 } diff --git a/test/common/upstream/load_balancer_corpus/random_test_something b/test/common/upstream/load_balancer_corpus/random_test_something new file mode 100644 index 000000000000..1ce65341fb6d --- /dev/null +++ b/test/common/upstream/load_balancer_corpus/random_test_something @@ -0,0 +1,34 @@ +load_balancer_test_case { +common_lb_config { + +} +actions { + update_health_flags { + host_index: 0 + num_healthy_hosts: 2 + } +} +actions { + prefetch { + + } +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +num_hosts_in_host_set: 250 +num_hosts_in_host_set: 250 +seed_for_prng: 4 +} diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index bc9e73e8aad0..5a078d931cc7 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -7,8 +7,7 @@ import "envoy/config/cluster/v3/cluster.proto"; import "google/protobuf/empty.proto"; message UpdateHealthFlags { - // The boolean corresponds to whether this action updates the failover set or not - bool failover_host_set = 1; + uint64 host_index = 1; uint32 num_healthy_hosts = 2; uint32 num_degraded_hosts = 3; uint32 num_excluded_hosts = 4; @@ -30,10 +29,11 @@ message LoadBalancerTestCase { envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; repeated LbAction actions = 2; - //Ports of hosts constructed range from 80 - 65455, all on the same Ip Address - //These caps make sure that the port of the hosts constructed does not overflow - uint32 num_hosts_in_priority_set = 3 [(validate.rules).uint32.lt = 32727]; - uint32 num_hosts_in_failover_set = 4 [(validate.rules).uint32.lt = 32727]; + + //TODO: Localities + repeated uint32 num_hosts_in_host_set = 3 + [(validate.rules).repeated = {min_items: 1, max_items: 20}]; + //This number is used to instantiate the prng. The prng takes the place of random() calls, allowing a representative random distribution which is also deterministic. - uint64 seed_for_prng = 5 [(validate.rules).uint64.gt = 0]; + uint64 seed_for_prng = 4 [(validate.rules).uint64.gt = 0]; } diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 333561176fc0..3844c6778217 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -5,96 +5,88 @@ namespace Envoy { namespace Upstream { -void LoadBalancerFuzzBase::initializeFixedHostSets(uint32_t num_hosts_in_priority_set, - uint32_t num_hosts_in_failover_set) { - int port = 80; - for (uint32_t i = 0; i < num_hosts_in_priority_set; ++i) { - host_set_.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); - ++port; +void LoadBalancerFuzzBase::initializeASingleHostSet(uint32_t num_hosts_in_host_set, + uint8_t index_of_host_set) { + ENVOY_LOG_MISC(trace, "Will attempt to initialize host set {} with {} hosts.", index_of_host_set, + num_hosts_in_host_set); + MockHostSet& host_set = *priority_set_.getMockHostSet(index_of_host_set); + uint32_t hosts_made = 0; + // Cap each host set at 250 hosts for efficiency + uint32_t max_num_hosts_in_host_set = 250; + // Leave port clause in for future changes + while (hosts_made < std::min(num_hosts_in_host_set, max_num_hosts_in_host_set) && port_ < 65535) { + host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port_))); + ++port_; + ++hosts_made; } - for (uint32_t i = 0; i < num_hosts_in_failover_set; ++i) { - failover_host_set_.hosts_.push_back( - makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); - ++port; - } - // TODO(zasweq): More than two host sets? + // TODO: Random call and mod against host_set size for locality logic } // Initializes random and fixed host sets void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { random_.initialize(input.seed_for_prng()); - initializeFixedHostSets(input.num_hosts_in_priority_set(), input.num_hosts_in_failover_set()); + uint8_t index_of_host_set = 0; + for (uint16_t num_hosts_in_host_set : input.num_hosts_in_host_set()) { + initializeASingleHostSet(num_hosts_in_host_set, index_of_host_set); + index_of_host_set++; + } + num_host_sets_ = index_of_host_set; } -//TODO: Mod it against the remaining hosts, have two sets where you take index out of one and put it in the other, or even just a set of indexes that you remove from -void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, +// Updating host sets is shared amongst all the load balancer tests. Since logically, we're just +// setting the mock priority set to have certain values, and all load balancers interface with host +// sets and their health statuses, this action maps to all load balancers. +void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(uint64_t host_index, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts) { - MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); + uint8_t index_of_host_set = host_index % num_host_sets_; + ENVOY_LOG_MISC(trace, "Updating health flags for host set: {}", index_of_host_set); + MockHostSet& host_set = *priority_set_.getMockHostSet(index_of_host_set); // This downcast will not overflow because size is capped by port numbers uint32_t host_set_size = host_set.hosts_.size(); host_set.healthy_hosts_.clear(); host_set.degraded_hosts_.clear(); host_set.excluded_hosts_.clear(); - uint32_t i = 0; - //construct a vector here representing remaining indexes, an index will randomly get chosen from here every time and removed. Thus, this represents the remaining indexes - //When this goes to zero, there will be no more indexes left to place into healthy, degraded, and excluded hosts. + // The vector constructed here represents remaining indexes, an index will randomly get chosen + // from here every time and removed. Thus, this represents the remaining indexes When this goes to + // zero, there will be no more indexes left to place into healthy, degraded, and excluded hosts. + ENVOY_LOG_MISC(trace, "Host set size: {}", host_set_size); std::vector indexVector; - byteVector.reserve(host_set_size); + indexVector.reserve(host_set_size); for (uint8_t i = 0; i < host_set_size; i++) { indexVector.push_back(i); } - - //Handle healthy hosts + for (uint32_t i = 0; i < num_healthy_hosts && indexVector.size() != 0; i++) { - uint64_t index = random_.random() % indexVector.size(); //does this size() return a uint64_t? also, should I add logs here? + uint64_t indexOfIndexVector = random_.random() % indexVector.size(); + uint64_t index = indexVector.at(indexOfIndexVector); + ENVOY_LOG_MISC(trace, "Added host {} to healthy hosts for host set {}", index, + index_of_host_set); host_set.healthy_hosts_.push_back(host_set.hosts_[index]); + indexVector.erase(indexVector.begin() + indexOfIndexVector); } - //Handle degraded hosts for (uint32_t i = 0; i < num_degraded_hosts && indexVector.size() != 0; i++) { - uint64_t index = random_.random() % indexVector.size(); //does this size() return a uint64_t? + uint64_t indexOfIndexVector = random_.random() % indexVector.size(); + uint64_t index = indexVector.at(indexOfIndexVector); + ENVOY_LOG_MISC(trace, "Added host {} to degraded hosts for host set {}", index, + index_of_host_set); host_set.degraded_hosts_.push_back(host_set.hosts_[index]); } - //Handle excluded hosts for (uint32_t i = 0; i < num_excluded_hosts && indexVector.size() != 0; i++) { - uint64_t index = random_.random() % indexVector.size(); //does this size() return a uint64_t? + uint64_t indexOfIndexVector = random_.random() % indexVector.size(); + uint64_t index = indexVector.at(indexOfIndexVector); + ENVOY_LOG_MISC(trace, "Added host {} to excluded hosts for host set {}", index, + index_of_host_set); host_set.excluded_hosts_.push_back(host_set.hosts_[index]); } host_set.runCallbacks({}, {}); } -// Updating host sets is shared amongst all the load balancer tests. Since logically, we're just -// setting the mock priority set to have certain values, and all load balancers interface with host -// sets and their health statuses, this action maps to all load balancers. -void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(bool failover_host_set, - uint32_t num_healthy_hosts, - uint32_t num_degraded_hosts, - uint32_t num_excluded_hosts) { - MockHostSet& host_set = *priority_set_.getMockHostSet(int(failover_host_set)); - // Will not overflow because size is capped by port numbers - uint32_t host_set_size = host_set.hosts_.size(); - //TODO: Clear vectors? - uint32_t i = 0; - for (; i < std::min(num_healthy_hosts, host_set_size); ++i) { - host_set.healthy_hosts_.push_back(host_set.hosts_[i]); //TODO: Preallocate space in this vector - } - for (; i < std::min(num_healthy_hosts + num_degraded_hosts, host_set_size); ++i) { - host_set.degraded_hosts_.push_back(host_set.hosts_[i]); - } - - for (; i < std::min(num_healthy_hosts + num_degraded_hosts + num_excluded_hosts, host_set_size); - ++i) { - host_set.excluded_hosts_.push_back(host_set.hosts_[i]); - } - - host_set.runCallbacks({}, {}); -} - void LoadBalancerFuzzBase::prefetch() { // TODO: context, could generate it in proto action lb_->peekAnotherHost(nullptr); @@ -113,7 +105,7 @@ void LoadBalancerFuzzBase::replay( ENVOY_LOG_MISC(trace, "Action: {}", event.DebugString()); switch (event.action_selector_case()) { case test::common::upstream::LbAction::kUpdateHealthFlags: { - updateHealthFlagsForAHostSet(event.update_health_flags().failover_host_set(), + updateHealthFlagsForAHostSet(event.update_health_flags().host_index(), event.update_health_flags().num_healthy_hosts(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts()); diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 66da987cc09c..b1f42051e634 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -1,7 +1,7 @@ -#include "envoy/config/cluster/v3/cluster.pb.h" - #include +#include "envoy/config/cluster/v3/cluster.pb.h" + #include "common/upstream/load_balancer_impl.h" #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" @@ -20,18 +20,16 @@ class FakeRandomGenerator : public RandomGenerator { FakeRandomGenerator() = default; ~FakeRandomGenerator() override = default; - void initialize(uint64_t seed) { - prng_ = std::make_unique(seed); - } + void initialize(uint64_t seed) { prng_ = std::make_unique(seed); } // RandomGenerator uint64_t random() override { - uint64_t toReturn = (*prng_.get())(); //For logging purposes + uint64_t toReturn = (*prng_.get())(); ENVOY_LOG_MISC(trace, "random() returned: {}", toReturn); return toReturn; } std::string uuid() override { return ""; } - std::unique_ptr prng_; + std::unique_ptr prng_; }; } // namespace Random @@ -45,13 +43,12 @@ class LoadBalancerFuzzBase { // Untrusted upstreams don't have the ability to change the host set size, so keep it constant // over the fuzz iteration. - void initializeFixedHostSets(uint32_t num_hosts_in_priority_set, - uint32_t num_hosts_in_failover_set); + void initializeASingleHostSet(uint32_t num_hosts_in_host_set, uint8_t index_of_host_set); // Initializes load balancer components shared amongst every load balancer, random_, and // priority_set_ void initializeLbComponents(const test::common::upstream::LoadBalancerTestCase& input); - void updateHealthFlagsForAHostSet(bool failover_host_set, uint32_t num_healthy_hosts, + void updateHealthFlagsForAHostSet(uint64_t host_index, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, uint32_t num_excluded_hosts); // These two actions have a lot of logic attached to them. However, all the logic that the load // balancer needs to run its algorithm is already encapsulated within the load balancer. Thus, @@ -69,10 +66,12 @@ class LoadBalancerFuzzBase { NiceMock runtime_; Random::FakeRandomGenerator random_; NiceMock priority_set_; - MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); - MockHostSet& failover_host_set_ = *priority_set_.getMockHostSet(1); std::shared_ptr info_{new NiceMock()}; std::unique_ptr lb_; + + // There are used to construct the priority set at the beginning of the fuzz iteration + uint16_t port_ = 80; + uint8_t num_host_sets_ = 0; }; } // namespace Upstream From 6e3c4207ed1058506247a6b7c9fa9be1da6356eb Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 9 Oct 2020 01:10:35 +0000 Subject: [PATCH 17/34] Style Signed-off-by: Zach --- test/common/upstream/BUILD | 2 +- test/common/upstream/load_balancer_fuzz.proto | 10 +++---- .../random_NoHosts | 0 .../random_Normal | 0 ...h-ba5efdfd9c412a8507087120783fe6529b1ac0cb | 0 .../random_largest-port-value | 0 .../random_many_choose_hosts | 0 .../random_max_ports | 0 .../random_overflowing_ports | 0 .../random_test_something | 0 ...t-6b0d6b83136a4cf0b9ccd468f11207a792859d43 | 27 +++++++++++++++++++ ...t-9144cfbb40b5101ecc28b205b10e6c36a72aae83 | 21 +++++++++++++++ 12 files changed, 54 insertions(+), 6 deletions(-) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_NoHosts (100%) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_Normal (100%) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb (100%) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_largest-port-value (100%) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_many_choose_hosts (100%) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_max_ports (100%) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_overflowing_ports (100%) rename test/common/upstream/{load_balancer_corpus => random_load_balancer_corpus}/random_test_something (100%) create mode 100644 test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 create mode 100644 test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 55b6e92ba2ba..10f8011ae420 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -280,7 +280,7 @@ envoy_proto_library( envoy_cc_fuzz_test( name = "random_load_balancer_fuzz_test", srcs = ["random_load_balancer_fuzz_test.cc"], - corpus = "//test/common/upstream:load_balancer_corpus", + corpus = "//test/common/upstream:random_load_balancer_corpus", deps = [ ":load_balancer_fuzz_lib", ":load_balancer_fuzz_proto_cc_proto", diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 5a078d931cc7..d199aaa29ed5 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -22,18 +22,18 @@ message LbAction { } } -//This message represents what LoadBalancerFuzzBase will interact with, performing setup of host sets and calling into load balancers. -//The logic that this message represents and the base class for load balancing fuzzing will be logic that maps to all types of load balancing -//and can be modularly used at the highest level for each load balancer. +// This message represents what LoadBalancerFuzzBase will interact with, performing setup of host sets and calling into load balancers. +// The logic that this message represents and the base class for load balancing fuzzing will be logic that maps to all types of load balancing +// and can be modularly used at the highest level for each load balancer. message LoadBalancerTestCase { envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; repeated LbAction actions = 2; - //TODO: Localities + // TODO: Localities repeated uint32 num_hosts_in_host_set = 3 [(validate.rules).repeated = {min_items: 1, max_items: 20}]; - //This number is used to instantiate the prng. The prng takes the place of random() calls, allowing a representative random distribution which is also deterministic. + // This number is used to instantiate the prng. The prng takes the place of random() calls, allowing a representative random distribution which is also deterministic. uint64 seed_for_prng = 4 [(validate.rules).uint64.gt = 0]; } diff --git a/test/common/upstream/load_balancer_corpus/random_NoHosts b/test/common/upstream/random_load_balancer_corpus/random_NoHosts similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_NoHosts rename to test/common/upstream/random_load_balancer_corpus/random_NoHosts diff --git a/test/common/upstream/load_balancer_corpus/random_Normal b/test/common/upstream/random_load_balancer_corpus/random_Normal similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_Normal rename to test/common/upstream/random_load_balancer_corpus/random_Normal diff --git a/test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb b/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb rename to test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb diff --git a/test/common/upstream/load_balancer_corpus/random_largest-port-value b/test/common/upstream/random_load_balancer_corpus/random_largest-port-value similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_largest-port-value rename to test/common/upstream/random_load_balancer_corpus/random_largest-port-value diff --git a/test/common/upstream/load_balancer_corpus/random_many_choose_hosts b/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_many_choose_hosts rename to test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts diff --git a/test/common/upstream/load_balancer_corpus/random_max_ports b/test/common/upstream/random_load_balancer_corpus/random_max_ports similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_max_ports rename to test/common/upstream/random_load_balancer_corpus/random_max_ports diff --git a/test/common/upstream/load_balancer_corpus/random_overflowing_ports b/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_overflowing_ports rename to test/common/upstream/random_load_balancer_corpus/random_overflowing_ports diff --git a/test/common/upstream/load_balancer_corpus/random_test_something b/test/common/upstream/random_load_balancer_corpus/random_test_something similarity index 100% rename from test/common/upstream/load_balancer_corpus/random_test_something rename to test/common/upstream/random_load_balancer_corpus/random_test_something diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 new file mode 100644 index 000000000000..7eb04c5eaba0 --- /dev/null +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 @@ -0,0 +1,27 @@ +load_balancer_test_case { + common_lb_config { + healthy_panic_threshold { + value: 1.35807730621777e-312 + } + zone_aware_lb_config { + routing_enabled { + } + min_cluster_size { + value: 7380836839843720192 + } + fail_traffic_on_panic: true + } + consistent_hashing_lb_config { + hash_balance_factor { + value: 27656 + } + } + } + actions { + update_health_flags { + num_excluded_hosts: 268435456 + } + } + num_hosts_in_host_set: 2063625226 + seed_for_prng: 32 +} diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 new file mode 100644 index 000000000000..6b59648c7a15 --- /dev/null +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 @@ -0,0 +1,21 @@ +load_balancer_test_case { + common_lb_config { + healthy_panic_threshold { + value: 4.88907830238399e-311 + } + consistent_hashing_lb_config { + use_hostname_for_hashing: true + hash_balance_factor { + value: 1024 + } + } + } + actions { + update_health_flags { + host_index: 270582939648 + num_degraded_hosts: 4194304 + } + } + num_hosts_in_host_set: 1024 + seed_for_prng: 62208 +} From a7d7e88621c0e5053c8fffdc43f7fc93ed041c3c Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 9 Oct 2020 01:24:41 +0000 Subject: [PATCH 18/34] Responded to Harvey's comments Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 3 ++ .../upstream/load_balancer_fuzz_base.cc | 33 ++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index d199aaa29ed5..80edfc34c99d 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -7,7 +7,10 @@ import "envoy/config/cluster/v3/cluster.proto"; import "google/protobuf/empty.proto"; message UpdateHealthFlags { + // The host index determines what host set within the priority set which will get updated. uint64 host_index = 1; + // These will determine how many hosts will get placed into health hosts, degraded hosts, and + // excluded hosts from the full host list. uint32 num_healthy_hosts = 2; uint32 num_degraded_hosts = 3; uint32 num_excluded_hosts = 4; diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 3844c6778217..7d79e50a6139 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -50,38 +50,41 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(uint64_t host_index, host_set.degraded_hosts_.clear(); host_set.excluded_hosts_.clear(); // The vector constructed here represents remaining indexes, an index will randomly get chosen - // from here every time and removed. Thus, this represents the remaining indexes When this goes to - // zero, there will be no more indexes left to place into healthy, degraded, and excluded hosts. + // from here every time and removed. Thus, this represents the remaining indexes. When this goes + // to zero, there will be no more indexes left to place into healthy, degraded, and excluded + // hosts. ENVOY_LOG_MISC(trace, "Host set size: {}", host_set_size); - std::vector indexVector; - indexVector.reserve(host_set_size); + std::vector index_vector; + index_vector.reserve(host_set_size); for (uint8_t i = 0; i < host_set_size; i++) { - indexVector.push_back(i); + index_vector.push_back(i); } - for (uint32_t i = 0; i < num_healthy_hosts && indexVector.size() != 0; i++) { - uint64_t indexOfIndexVector = random_.random() % indexVector.size(); - uint64_t index = indexVector.at(indexOfIndexVector); + for (uint32_t i = 0; i < num_healthy_hosts && index_vector.size() != 0; i++) { + uint64_t index_of_index_vector = random_.random() % index_vector.size(); + uint64_t index = index_vector.at(index_of_index_vector); ENVOY_LOG_MISC(trace, "Added host {} to healthy hosts for host set {}", index, index_of_host_set); host_set.healthy_hosts_.push_back(host_set.hosts_[index]); - indexVector.erase(indexVector.begin() + indexOfIndexVector); + index_vector.erase(index_vector.begin() + index_of_index_vector); } - for (uint32_t i = 0; i < num_degraded_hosts && indexVector.size() != 0; i++) { - uint64_t indexOfIndexVector = random_.random() % indexVector.size(); - uint64_t index = indexVector.at(indexOfIndexVector); + for (uint32_t i = 0; i < num_degraded_hosts && index_vector.size() != 0; i++) { + uint64_t index_of_index_vector = random_.random() % index_vector.size(); + uint64_t index = index_vector.at(index_of_index_vector); ENVOY_LOG_MISC(trace, "Added host {} to degraded hosts for host set {}", index, index_of_host_set); host_set.degraded_hosts_.push_back(host_set.hosts_[index]); + index_vector.erase(index_vector.begin() + index_of_index_vector); } - for (uint32_t i = 0; i < num_excluded_hosts && indexVector.size() != 0; i++) { - uint64_t indexOfIndexVector = random_.random() % indexVector.size(); - uint64_t index = indexVector.at(indexOfIndexVector); + for (uint32_t i = 0; i < num_excluded_hosts && index_vector.size() != 0; i++) { + uint64_t index_of_index_vector = random_.random() % index_vector.size(); + uint64_t index = index_vector.at(index_of_index_vector); ENVOY_LOG_MISC(trace, "Added host {} to excluded hosts for host set {}", index, index_of_host_set); host_set.excluded_hosts_.push_back(host_set.hosts_[index]); + index_vector.erase(index_vector.begin() + index_of_index_vector); } host_set.runCallbacks({}, {}); From 5c6bdaf9a129dc8c67dfe0c6895fc8bd803d9277 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 9 Oct 2020 02:18:21 +0000 Subject: [PATCH 19/34] Spelling CI Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 80edfc34c99d..4e19778e0494 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -27,7 +27,7 @@ message LbAction { // This message represents what LoadBalancerFuzzBase will interact with, performing setup of host sets and calling into load balancers. // The logic that this message represents and the base class for load balancing fuzzing will be logic that maps to all types of load balancing -// and can be modularly used at the highest level for each load balancer. +// and can be used in a modular way at the highest level for each load balancer. message LoadBalancerTestCase { envoy.config.cluster.v3.Cluster.CommonLbConfig common_lb_config = 1 [(validate.rules).message.required = true]; From 92666c1ea7e8a5f1c8e40746d570a6be8ce62102 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 9 Oct 2020 22:30:18 +0000 Subject: [PATCH 20/34] Changed update to use generated bytes, added util class Signed-off-by: Zach --- test/common/upstream/BUILD | 1 + test/common/upstream/load_balancer_fuzz.proto | 2 + .../upstream/load_balancer_fuzz_base.cc | 54 +++++-------- .../common/upstream/load_balancer_fuzz_base.h | 28 +------ .../random_256_ports | 35 ++++++++ .../random_load_balancer_corpus/random_Normal | 1 + .../random_many_choose_hosts | 1 + .../random_max_ports | 1 + .../random_overflowing_ports | 1 + .../random_test_something | 1 + ...t-6b0d6b83136a4cf0b9ccd468f11207a792859d43 | 1 + ...t-9144cfbb40b5101ecc28b205b10e6c36a72aae83 | 1 + test/fuzz/BUILD | 7 ++ test/fuzz/random.h | 79 +++++++++++++++++++ 14 files changed, 156 insertions(+), 57 deletions(-) create mode 100644 test/common/upstream/random_load_balancer_corpus/random_256_ports create mode 100644 test/fuzz/random.h diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 10f8011ae420..216896626c45 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -250,6 +250,7 @@ envoy_cc_test_library( ":load_balancer_fuzz_proto_cc_proto", ":utility_lib", "//source/common/upstream:load_balancer_lib", + "//test/fuzz:random_lib", "//test/mocks:common_lib", "//test/mocks/runtime:runtime_mocks", "//test/mocks/upstream:cluster_info_mocks", diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 4e19778e0494..ae251f7818c2 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -14,6 +14,8 @@ message UpdateHealthFlags { uint32 num_healthy_hosts = 2; uint32 num_degraded_hosts = 3; uint32 num_excluded_hosts = 4; + // This is used to determine which hosts get marked as healthy, degraded, and excluded. + bytes random_bytestring = 5 [(validate.rules).bytes = {min_len: 1, max_len: 256}]; } message LbAction { diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 7d79e50a6139..bd285da6b9cc 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -11,8 +11,8 @@ void LoadBalancerFuzzBase::initializeASingleHostSet(uint32_t num_hosts_in_host_s num_hosts_in_host_set); MockHostSet& host_set = *priority_set_.getMockHostSet(index_of_host_set); uint32_t hosts_made = 0; - // Cap each host set at 250 hosts for efficiency - uint32_t max_num_hosts_in_host_set = 250; + // Cap each host set at 256 hosts for efficiency + uint32_t max_num_hosts_in_host_set = 256; // Leave port clause in for future changes while (hosts_made < std::min(num_hosts_in_host_set, max_num_hosts_in_host_set) && port_ < 65535) { host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port_))); @@ -25,7 +25,7 @@ void LoadBalancerFuzzBase::initializeASingleHostSet(uint32_t num_hosts_in_host_s // Initializes random and fixed host sets void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { - random_.initialize(input.seed_for_prng()); + random_.initializeSeed(input.seed_for_prng()); uint8_t index_of_host_set = 0; for (uint16_t num_hosts_in_host_set : input.num_hosts_in_host_set()) { initializeASingleHostSet(num_hosts_in_host_set, index_of_host_set); @@ -40,7 +40,8 @@ void LoadBalancerFuzzBase::initializeLbComponents( void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(uint64_t host_index, uint32_t num_healthy_hosts, uint32_t num_degraded_hosts, - uint32_t num_excluded_hosts) { + uint32_t num_excluded_hosts, + std::string random_bytestring) { uint8_t index_of_host_set = host_index % num_host_sets_; ENVOY_LOG_MISC(trace, "Updating health flags for host set: {}", index_of_host_set); MockHostSet& host_set = *priority_set_.getMockHostSet(index_of_host_set); @@ -49,42 +50,28 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(uint64_t host_index, host_set.healthy_hosts_.clear(); host_set.degraded_hosts_.clear(); host_set.excluded_hosts_.clear(); - // The vector constructed here represents remaining indexes, an index will randomly get chosen - // from here every time and removed. Thus, this represents the remaining indexes. When this goes - // to zero, there will be no more indexes left to place into healthy, degraded, and excluded - // hosts. - ENVOY_LOG_MISC(trace, "Host set size: {}", host_set_size); - std::vector index_vector; - index_vector.reserve(host_set_size); - for (uint8_t i = 0; i < host_set_size; i++) { - index_vector.push_back(i); - } - for (uint32_t i = 0; i < num_healthy_hosts && index_vector.size() != 0; i++) { - uint64_t index_of_index_vector = random_.random() % index_vector.size(); - uint64_t index = index_vector.at(index_of_index_vector); - ENVOY_LOG_MISC(trace, "Added host {} to healthy hosts for host set {}", index, - index_of_host_set); + Fuzz::ProperSubsetSelector subset_selector(random_bytestring); + + std::vector> subsets = subset_selector.constructSubsets( + 3, {num_healthy_hosts, num_degraded_hosts, num_excluded_hosts}, host_set_size); + + // Healthy hosts are first subset + for (uint8_t index : subsets.at(0)) { host_set.healthy_hosts_.push_back(host_set.hosts_[index]); - index_vector.erase(index_vector.begin() + index_of_index_vector); + ENVOY_LOG_MISC(trace, "Index of host made healthy: {}", index); } - for (uint32_t i = 0; i < num_degraded_hosts && index_vector.size() != 0; i++) { - uint64_t index_of_index_vector = random_.random() % index_vector.size(); - uint64_t index = index_vector.at(index_of_index_vector); - ENVOY_LOG_MISC(trace, "Added host {} to degraded hosts for host set {}", index, - index_of_host_set); + // Degraded hosts are second subset + for (uint8_t index : subsets.at(1)) { host_set.degraded_hosts_.push_back(host_set.hosts_[index]); - index_vector.erase(index_vector.begin() + index_of_index_vector); + ENVOY_LOG_MISC(trace, "Index of host made degraded: {}", index); } - for (uint32_t i = 0; i < num_excluded_hosts && index_vector.size() != 0; i++) { - uint64_t index_of_index_vector = random_.random() % index_vector.size(); - uint64_t index = index_vector.at(index_of_index_vector); - ENVOY_LOG_MISC(trace, "Added host {} to excluded hosts for host set {}", index, - index_of_host_set); + // Excluded hosts are third subset + for (uint8_t index : subsets.at(1)) { host_set.excluded_hosts_.push_back(host_set.hosts_[index]); - index_vector.erase(index_vector.begin() + index_of_index_vector); + ENVOY_LOG_MISC(trace, "Index of host made excluded: {}", index); } host_set.runCallbacks({}, {}); @@ -111,7 +98,8 @@ void LoadBalancerFuzzBase::replay( updateHealthFlagsForAHostSet(event.update_health_flags().host_index(), event.update_health_flags().num_healthy_hosts(), event.update_health_flags().num_degraded_hosts(), - event.update_health_flags().num_excluded_hosts()); + event.update_health_flags().num_excluded_hosts(), + event.update_health_flags().random_bytestring()); break; } case test::common::upstream::LbAction::kPrefetch: diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index b1f42051e634..8ffa340b2623 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -1,10 +1,9 @@ -#include - #include "envoy/config/cluster/v3/cluster.pb.h" #include "common/upstream/load_balancer_impl.h" #include "test/common/upstream/load_balancer_fuzz.pb.validate.h" +#include "test/fuzz/random.h" #include "test/mocks/common.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/upstream/cluster_info.h" @@ -13,26 +12,6 @@ #include "test/mocks/upstream/priority_set.h" namespace Envoy { - -namespace Random { -class FakeRandomGenerator : public RandomGenerator { -public: - FakeRandomGenerator() = default; - ~FakeRandomGenerator() override = default; - - void initialize(uint64_t seed) { prng_ = std::make_unique(seed); } - - // RandomGenerator - uint64_t random() override { - uint64_t toReturn = (*prng_.get())(); - ENVOY_LOG_MISC(trace, "random() returned: {}", toReturn); - return toReturn; - } - std::string uuid() override { return ""; } - std::unique_ptr prng_; -}; -} // namespace Random - namespace Upstream { // This class implements replay logic, and also handles the initial setup of static host sets and @@ -49,7 +28,8 @@ class LoadBalancerFuzzBase { // priority_set_ void initializeLbComponents(const test::common::upstream::LoadBalancerTestCase& input); void updateHealthFlagsForAHostSet(uint64_t host_index, uint32_t num_healthy_hosts, - uint32_t num_degraded_hosts, uint32_t num_excluded_hosts); + uint32_t num_degraded_hosts, uint32_t num_excluded_hosts, + std::string random_bytestring); // These two actions have a lot of logic attached to them. However, all the logic that the load // balancer needs to run its algorithm is already encapsulated within the load balancer. Thus, // once the load balancer is constructed, all this class has to do is call lb_->peekAnotherHost() @@ -64,7 +44,7 @@ class LoadBalancerFuzzBase { Stats::IsolatedStoreImpl stats_store_; ClusterStats stats_; NiceMock runtime_; - Random::FakeRandomGenerator random_; + Random::PsuedoRandomGenerator64 random_; NiceMock priority_set_; std::shared_ptr info_{new NiceMock()}; std::unique_ptr lb_; diff --git a/test/common/upstream/random_load_balancer_corpus/random_256_ports b/test/common/upstream/random_load_balancer_corpus/random_256_ports new file mode 100644 index 000000000000..cd152ce088da --- /dev/null +++ b/test/common/upstream/random_load_balancer_corpus/random_256_ports @@ -0,0 +1,35 @@ +load_balancer_test_case { +common_lb_config { + +} +actions { + update_health_flags { + host_index: 0 + num_healthy_hosts: 256 + random_bytestring: "\x01\x02\x03\x04\x45\x80" + } +} +actions { + prefetch { + + } +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +num_hosts_in_host_set: 256 +num_hosts_in_host_set: 256 +seed_for_prng: 4 +} diff --git a/test/common/upstream/random_load_balancer_corpus/random_Normal b/test/common/upstream/random_load_balancer_corpus/random_Normal index 3347434dc436..eee4101535ff 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_Normal +++ b/test/common/upstream/random_load_balancer_corpus/random_Normal @@ -6,6 +6,7 @@ actions { update_health_flags { host_index: 0 num_healthy_hosts: 2 + random_bytestring: "\x01\x02" } } actions { diff --git a/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts b/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts index 4847c31741a1..7224e7c9af02 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts +++ b/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts @@ -6,6 +6,7 @@ actions { update_health_flags { host_index: 0 num_healthy_hosts: 2 + random_bytestring: "\x01\x02\x03\x04" } } actions { diff --git a/test/common/upstream/random_load_balancer_corpus/random_max_ports b/test/common/upstream/random_load_balancer_corpus/random_max_ports index 7d4285ee5397..1454ff3f1057 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_max_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_max_ports @@ -6,6 +6,7 @@ actions { update_health_flags { host_index: 0 num_healthy_hosts: 2 + random_bytestring: "\x01\x02\x03\x04" } } actions { diff --git a/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports b/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports index e425c3d14da5..234853319dd3 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports @@ -6,6 +6,7 @@ actions { update_health_flags { host_index: 0 num_healthy_hosts: 2 + random_bytestring: "\x01\x02" } } actions { diff --git a/test/common/upstream/random_load_balancer_corpus/random_test_something b/test/common/upstream/random_load_balancer_corpus/random_test_something index 1ce65341fb6d..a78ca95de4d3 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_test_something +++ b/test/common/upstream/random_load_balancer_corpus/random_test_something @@ -6,6 +6,7 @@ actions { update_health_flags { host_index: 0 num_healthy_hosts: 2 + random_bytestring: "\x01\x02" } } actions { diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 index 7eb04c5eaba0..8038384ecef4 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 @@ -20,6 +20,7 @@ load_balancer_test_case { actions { update_health_flags { num_excluded_hosts: 268435456 + random_bytestring: "\x01\x02" } } num_hosts_in_host_set: 2063625226 diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 index 6b59648c7a15..9259e080f4f5 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 @@ -14,6 +14,7 @@ load_balancer_test_case { update_health_flags { host_index: 270582939648 num_degraded_hosts: 4194304 + random_bytestring: "\x01\x02\x03\x04" } } num_hosts_in_host_set: 1024 diff --git a/test/fuzz/BUILD b/test/fuzz/BUILD index 35bd8e0ac197..8772ac3bc779 100644 --- a/test/fuzz/BUILD +++ b/test/fuzz/BUILD @@ -68,3 +68,10 @@ envoy_cc_test_library( "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) + +envoy_cc_test_library( + name = "random_lib", + hdrs = ["random.h"], + deps = [ + ], +) diff --git a/test/fuzz/random.h b/test/fuzz/random.h new file mode 100644 index 000000000000..f78d9259d390 --- /dev/null +++ b/test/fuzz/random.h @@ -0,0 +1,79 @@ +#include +#include + +namespace Envoy { +namespace Random { + +class PsuedoRandomGenerator64 : public RandomGenerator { +public: + PsuedoRandomGenerator64() = default; + ~PsuedoRandomGenerator64() override = default; + + void initializeSeed(uint64_t seed) { prng_ = std::make_unique(seed); } + + // RandomGenerator + uint64_t random() override { + uint64_t to_return = (*prng_.get())(); + ENVOY_LOG_MISC(trace, "random() returned: {}", to_return); + return to_return; + } + std::string uuid() override { return ""; } + std::unique_ptr prng_; +}; + +} // namespace Random + +namespace Fuzz { +class ProperSubsetSelector { +public: + ProperSubsetSelector(std::string random_bytestring) { + random_bytestring_ = random_bytestring; + index_of_random_bytestring_ = 0; + } + + // Returns a vector of vectors, each vector of bytes representing a single subset + std::vector> + constructSubsets(uint32_t number_of_subsets, + std::vector number_of_elements_in_each_subset, + uint32_t number_of_elements) { + ASSERT(number_of_subsets == number_of_elements_in_each_subset.size()); + index_vector_.clear(); + index_vector_.reserve(number_of_elements); + for (uint32_t i = 0; i < number_of_elements; i++) { + index_vector_.push_back(i); + } + std::vector> subsets; + for (uint32_t i = 0; i < number_of_subsets; i++) { + subsets.push_back(constructSubset(number_of_elements_in_each_subset.at(i))); + } + return subsets; + } + + // Builds a single subset by pulling indexes off index_vector_ + std::vector constructSubset(uint32_t number_of_elements_in_subset) { + std::vector subset; + for (uint32_t i = 0; i < number_of_elements_in_subset && index_vector_.size() != 0; i++) { + uint64_t index_of_index_vector = + random_bytestring_[index_of_random_bytestring_] % index_vector_.size(); + uint64_t index = index_vector_.at(index_of_index_vector); + subset.push_back(index); + index_vector_.erase(index_vector_.begin() + index_of_index_vector); + ++index_of_random_bytestring_; + // Index of bytestring will wrap around if overflows + if (index_of_random_bytestring_ == random_bytestring_.length()) { + index_of_random_bytestring_ = 0; + } + } + return subset; + } + + std::vector index_vector_; + + // This bytestring will be iterated through logically representing randomness in order to choose + // subsets + std::string random_bytestring_; + uint32_t index_of_random_bytestring_; +}; + +} // namespace Fuzz +} // namespace Envoy From 6ee35db4774a9cac588dae6a9ca6f5386c880510 Mon Sep 17 00:00:00 2001 From: Zach Date: Mon, 12 Oct 2020 23:19:07 +0000 Subject: [PATCH 21/34] Responded to Asra's comments Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 8 ++- .../upstream/load_balancer_fuzz_base.cc | 56 ++++++++++--------- .../common/upstream/load_balancer_fuzz_base.h | 11 ++-- .../random_256_ports | 6 +- .../random_NoHosts | 4 +- .../random_load_balancer_corpus/random_Normal | 6 +- ...h-ba5efdfd9c412a8507087120783fe6529b1ac0cb | 4 +- .../random_largest-port-value | 4 +- .../random_many_choose_hosts | 6 +- .../random_max_ports | 6 +- .../random_overflowing_ports | 6 +- .../random_test_something | 6 +- ...t-6b0d6b83136a4cf0b9ccd468f11207a792859d43 | 2 +- ...t-9144cfbb40b5101ecc28b205b10e6c36a72aae83 | 4 +- test/fuzz/BUILD | 2 + test/fuzz/random.h | 35 +++++++----- 16 files changed, 91 insertions(+), 75 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index ae251f7818c2..16c745c79d73 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -7,8 +7,8 @@ import "envoy/config/cluster/v3/cluster.proto"; import "google/protobuf/empty.proto"; message UpdateHealthFlags { - // The host index determines what host set within the priority set which will get updated. - uint64 host_index = 1; + // The host priority determines what host set within the priority set which will get updated. + uint64 host_priority = 1; // These will determine how many hosts will get placed into health hosts, degraded hosts, and // excluded hosts from the full host list. uint32 num_healthy_hosts = 2; @@ -36,7 +36,9 @@ message LoadBalancerTestCase { repeated LbAction actions = 2; // TODO: Localities - repeated uint32 num_hosts_in_host_set = 3 + // Each generated integer will cause the fuzzer to initialize hosts at a certain priority level, each integer generated adding a priority + // level with integer generated hosts in that new priority level. Capped at 20 for simplicity. + repeated uint32 num_hosts_in_priority_level = 3 [(validate.rules).repeated = {min_items: 1, max_items: 20}]; // This number is used to instantiate the prng. The prng takes the place of random() calls, allowing a representative random distribution which is also deterministic. diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index bd285da6b9cc..37ec790d979f 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -2,19 +2,22 @@ #include "test/common/upstream/utility.h" +#define MAX_NUM_HOSTS_IN_PRIORITY_LEVEL 256 + namespace Envoy { namespace Upstream { -void LoadBalancerFuzzBase::initializeASingleHostSet(uint32_t num_hosts_in_host_set, - uint8_t index_of_host_set) { - ENVOY_LOG_MISC(trace, "Will attempt to initialize host set {} with {} hosts.", index_of_host_set, +void LoadBalancerFuzzBase::initializeASingleHostSet(const uint32_t num_hosts_in_host_set, + const uint8_t priority_level) { + ENVOY_LOG_MISC(trace, "Will attempt to initialize host set {} with {} hosts.", priority_level, num_hosts_in_host_set); - MockHostSet& host_set = *priority_set_.getMockHostSet(index_of_host_set); + MockHostSet& host_set = *priority_set_.getMockHostSet(priority_level); uint32_t hosts_made = 0; // Cap each host set at 256 hosts for efficiency - uint32_t max_num_hosts_in_host_set = 256; + const uint32_t max_num_hosts_in_priority_level = MAX_NUM_HOSTS_IN_PRIORITY_LEVEL; // Leave port clause in for future changes - while (hosts_made < std::min(num_hosts_in_host_set, max_num_hosts_in_host_set) && port_ < 65535) { + while (hosts_made < std::min(num_hosts_in_host_set, max_num_hosts_in_priority_level) && + port_ < 65535) { host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port_))); ++port_; ++hosts_made; @@ -26,25 +29,25 @@ void LoadBalancerFuzzBase::initializeASingleHostSet(uint32_t num_hosts_in_host_s void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { random_.initializeSeed(input.seed_for_prng()); - uint8_t index_of_host_set = 0; - for (uint16_t num_hosts_in_host_set : input.num_hosts_in_host_set()) { - initializeASingleHostSet(num_hosts_in_host_set, index_of_host_set); - index_of_host_set++; + uint8_t priority_of_host_set = 0; + for (uint16_t num_hosts_in_priority_level : input.num_hosts_in_priority_level()) { + initializeASingleHostSet(num_hosts_in_priority_level, priority_of_host_set); + priority_of_host_set++; } - num_host_sets_ = index_of_host_set; + num_priority_levels_ = priority_of_host_set; } // Updating host sets is shared amongst all the load balancer tests. Since logically, we're just // setting the mock priority set to have certain values, and all load balancers interface with host // sets and their health statuses, this action maps to all load balancers. -void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(uint64_t host_index, - uint32_t num_healthy_hosts, - uint32_t num_degraded_hosts, - uint32_t num_excluded_hosts, - std::string random_bytestring) { - uint8_t index_of_host_set = host_index % num_host_sets_; - ENVOY_LOG_MISC(trace, "Updating health flags for host set: {}", index_of_host_set); - MockHostSet& host_set = *priority_set_.getMockHostSet(index_of_host_set); +void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_priority, + const uint32_t num_healthy_hosts, + const uint32_t num_degraded_hosts, + const uint32_t num_excluded_hosts, + const std::string random_bytestring) { + const uint8_t priority_of_host_set = host_priority % num_priority_levels_; + ENVOY_LOG_MISC(trace, "Updating health flags for host set at priority: {}", priority_of_host_set); + MockHostSet& host_set = *priority_set_.getMockHostSet(priority_of_host_set); // This downcast will not overflow because size is capped by port numbers uint32_t host_set_size = host_set.hosts_.size(); host_set.healthy_hosts_.clear(); @@ -54,24 +57,27 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(uint64_t host_index, Fuzz::ProperSubsetSelector subset_selector(random_bytestring); std::vector> subsets = subset_selector.constructSubsets( - 3, {num_healthy_hosts, num_degraded_hosts, num_excluded_hosts}, host_set_size); + {num_healthy_hosts, num_degraded_hosts, num_excluded_hosts}, host_set_size); // Healthy hosts are first subset for (uint8_t index : subsets.at(0)) { host_set.healthy_hosts_.push_back(host_set.hosts_[index]); - ENVOY_LOG_MISC(trace, "Index of host made healthy: {}", index); + ENVOY_LOG_MISC(trace, "Index of host made healthy at priority level {}: {}", + priority_of_host_set, index); } // Degraded hosts are second subset for (uint8_t index : subsets.at(1)) { host_set.degraded_hosts_.push_back(host_set.hosts_[index]); - ENVOY_LOG_MISC(trace, "Index of host made degraded: {}", index); + ENVOY_LOG_MISC(trace, "Index of host made degraded at priority level {}: {}", + priority_of_host_set, index); } // Excluded hosts are third subset - for (uint8_t index : subsets.at(1)) { + for (uint8_t index : subsets.at(2)) { host_set.excluded_hosts_.push_back(host_set.hosts_[index]); - ENVOY_LOG_MISC(trace, "Index of host made excluded: {}", index); + ENVOY_LOG_MISC(trace, "Index of host made excluded at priority level {}: {}", + priority_of_host_set, index); } host_set.runCallbacks({}, {}); @@ -95,7 +101,7 @@ void LoadBalancerFuzzBase::replay( ENVOY_LOG_MISC(trace, "Action: {}", event.DebugString()); switch (event.action_selector_case()) { case test::common::upstream::LbAction::kUpdateHealthFlags: { - updateHealthFlagsForAHostSet(event.update_health_flags().host_index(), + updateHealthFlagsForAHostSet(event.update_health_flags().host_priority(), event.update_health_flags().num_healthy_hosts(), event.update_health_flags().num_degraded_hosts(), event.update_health_flags().num_excluded_hosts(), diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 8ffa340b2623..57c0bc6bbdaf 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -22,14 +22,15 @@ class LoadBalancerFuzzBase { // Untrusted upstreams don't have the ability to change the host set size, so keep it constant // over the fuzz iteration. - void initializeASingleHostSet(uint32_t num_hosts_in_host_set, uint8_t index_of_host_set); + void initializeASingleHostSet(const uint32_t num_hosts_in_host_set, const uint8_t priority_level); // Initializes load balancer components shared amongst every load balancer, random_, and // priority_set_ void initializeLbComponents(const test::common::upstream::LoadBalancerTestCase& input); - void updateHealthFlagsForAHostSet(uint64_t host_index, uint32_t num_healthy_hosts, - uint32_t num_degraded_hosts, uint32_t num_excluded_hosts, - std::string random_bytestring); + void updateHealthFlagsForAHostSet(const uint64_t host_priority, const uint32_t num_healthy_hosts, + const uint32_t num_degraded_hosts, + const uint32_t num_excluded_hosts, + const std::string random_bytestring); // These two actions have a lot of logic attached to them. However, all the logic that the load // balancer needs to run its algorithm is already encapsulated within the load balancer. Thus, // once the load balancer is constructed, all this class has to do is call lb_->peekAnotherHost() @@ -51,7 +52,7 @@ class LoadBalancerFuzzBase { // There are used to construct the priority set at the beginning of the fuzz iteration uint16_t port_ = 80; - uint8_t num_host_sets_ = 0; + uint8_t num_priority_levels_ = 0; }; } // namespace Upstream diff --git a/test/common/upstream/random_load_balancer_corpus/random_256_ports b/test/common/upstream/random_load_balancer_corpus/random_256_ports index cd152ce088da..65ded4399181 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_256_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_256_ports @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - host_index: 0 + host_priority: 0 num_healthy_hosts: 256 random_bytestring: "\x01\x02\x03\x04\x45\x80" } @@ -29,7 +29,7 @@ actions { } } -num_hosts_in_host_set: 256 -num_hosts_in_host_set: 256 +num_hosts_in_priority_level: 256 +num_hosts_in_priority_level: 256 seed_for_prng: 4 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_NoHosts b/test/common/upstream/random_load_balancer_corpus/random_NoHosts index 98f50013c017..8a91f2d17ced 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_NoHosts +++ b/test/common/upstream/random_load_balancer_corpus/random_NoHosts @@ -12,7 +12,7 @@ actions { } } -num_hosts_in_host_set: 0 -num_hosts_in_host_set: 0 +num_hosts_in_priority_level: 0 +num_hosts_in_priority_level: 0 seed_for_prng: 2 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_Normal b/test/common/upstream/random_load_balancer_corpus/random_Normal index eee4101535ff..1bfd0a2dd5d9 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_Normal +++ b/test/common/upstream/random_load_balancer_corpus/random_Normal @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - host_index: 0 + host_priority: 0 num_healthy_hosts: 2 random_bytestring: "\x01\x02" } @@ -29,7 +29,7 @@ actions { } } -num_hosts_in_host_set: 2 -num_hosts_in_host_set: 0 +num_hosts_in_priority_level: 2 +num_hosts_in_priority_level: 0 seed_for_prng: 1 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb b/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb index 7a30c203dd20..295929546e99 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb +++ b/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb @@ -26,7 +26,7 @@ actions { choose_host { } } -num_hosts_in_host_set: 2 -num_hosts_in_host_set: 9007199258945536 +num_hosts_in_priority_level: 2 +num_hosts_in_priority_level: 9007199258945536 seed_for_prng: 6 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_largest-port-value b/test/common/upstream/random_load_balancer_corpus/random_largest-port-value index 0d9fbda247fd..ef8726fba5cd 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_largest-port-value +++ b/test/common/upstream/random_load_balancer_corpus/random_largest-port-value @@ -22,7 +22,7 @@ actions { choose_host { } } -num_hosts_in_host_set: 65455 -num_hosts_in_host_set: 65455 +num_hosts_in_priority_level: 65455 +num_hosts_in_priority_level: 65455 seed_for_prng: 5 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts b/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts index 7224e7c9af02..60f3e7e07852 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts +++ b/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - host_index: 0 + host_priority: 0 num_healthy_hosts: 2 random_bytestring: "\x01\x02\x03\x04" } @@ -49,7 +49,7 @@ actions { } } -num_hosts_in_host_set: 2 -num_hosts_in_host_set: 0 +num_hosts_in_priority_level: 2 +num_hosts_in_priority_level: 0 seed_for_prng: 1 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_max_ports b/test/common/upstream/random_load_balancer_corpus/random_max_ports index 1454ff3f1057..d214489e9fe2 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_max_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_max_ports @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - host_index: 0 + host_priority: 0 num_healthy_hosts: 2 random_bytestring: "\x01\x02\x03\x04" } @@ -29,7 +29,7 @@ actions { } } -num_hosts_in_priority_set: 32726 -num_hosts_in_failover_set: 32726 +num_hosts_in_priority_level: 32726 +num_hosts_in_priority_level: 32726 seed_for_prng: 88 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports b/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports index 234853319dd3..481204e85b56 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - host_index: 0 + host_priority: 0 num_healthy_hosts: 2 random_bytestring: "\x01\x02" } @@ -29,7 +29,7 @@ actions { } } -num_hosts_in_host_set: 60000 -num_hosts_in_host_set: 60000 +num_hosts_in_priority_level: 60000 +num_hosts_in_priority_level: 60000 seed_for_prng: 4 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_test_something b/test/common/upstream/random_load_balancer_corpus/random_test_something index a78ca95de4d3..19b9201dbb3d 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_test_something +++ b/test/common/upstream/random_load_balancer_corpus/random_test_something @@ -4,7 +4,7 @@ common_lb_config { } actions { update_health_flags { - host_index: 0 + host_priority: 0 num_healthy_hosts: 2 random_bytestring: "\x01\x02" } @@ -29,7 +29,7 @@ actions { } } -num_hosts_in_host_set: 250 -num_hosts_in_host_set: 250 +num_hosts_in_priority_level: 250 +num_hosts_in_priority_level: 250 seed_for_prng: 4 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 index 8038384ecef4..daf95d962631 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 @@ -23,6 +23,6 @@ load_balancer_test_case { random_bytestring: "\x01\x02" } } - num_hosts_in_host_set: 2063625226 + num_hosts_in_priority_level: 2063625226 seed_for_prng: 32 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 index 9259e080f4f5..de515e3b39a7 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 @@ -12,11 +12,11 @@ load_balancer_test_case { } actions { update_health_flags { - host_index: 270582939648 + host_priority: 270582939648 num_degraded_hosts: 4194304 random_bytestring: "\x01\x02\x03\x04" } } - num_hosts_in_host_set: 1024 + num_hosts_in_priority_level: 1024 seed_for_prng: 62208 } diff --git a/test/fuzz/BUILD b/test/fuzz/BUILD index 8772ac3bc779..e128a3c3f497 100644 --- a/test/fuzz/BUILD +++ b/test/fuzz/BUILD @@ -73,5 +73,7 @@ envoy_cc_test_library( name = "random_lib", hdrs = ["random.h"], deps = [ + "//include/envoy/common:random_generator_interface", + "//source/common/common:assert_lib", ], ) diff --git a/test/fuzz/random.h b/test/fuzz/random.h index f78d9259d390..9b8478efc222 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -13,6 +13,8 @@ class PsuedoRandomGenerator64 : public RandomGenerator { // RandomGenerator uint64_t random() override { + // Makes sure initializeSeed() was already called + ASSERT(prng_ != nullptr); uint64_t to_return = (*prng_.get())(); ENVOY_LOG_MISC(trace, "random() returned: {}", to_return); return to_return; @@ -26,43 +28,46 @@ class PsuedoRandomGenerator64 : public RandomGenerator { namespace Fuzz { class ProperSubsetSelector { public: - ProperSubsetSelector(std::string random_bytestring) { - random_bytestring_ = random_bytestring; - index_of_random_bytestring_ = 0; - } + ProperSubsetSelector(const std::string& random_bytestring) + : random_bytestring_(random_bytestring) {} + + /** + * This function does proper subset selection on a certain number of elements. It returns a vector + * of vectors of bytes. Each vector of bytes represents the indexes of a single subset. The + * "randomness" of the subset that the class will use is determined by a bytestring passed into + * the class. Example: call into function with a vector {3, 5} representing subset sizes, and 15 + * as number_of_elements. This function would return something such as {{3, 14, 7}, {2, 1, 13, 8, + * 6}} + */ - // Returns a vector of vectors, each vector of bytes representing a single subset std::vector> - constructSubsets(uint32_t number_of_subsets, - std::vector number_of_elements_in_each_subset, + constructSubsets(const std::vector& number_of_elements_in_each_subset, uint32_t number_of_elements) { - ASSERT(number_of_subsets == number_of_elements_in_each_subset.size()); index_vector_.clear(); index_vector_.reserve(number_of_elements); for (uint32_t i = 0; i < number_of_elements; i++) { index_vector_.push_back(i); } std::vector> subsets; - for (uint32_t i = 0; i < number_of_subsets; i++) { + for (uint32_t i = 0; i < number_of_elements_in_each_subset.size(); i++) { subsets.push_back(constructSubset(number_of_elements_in_each_subset.at(i))); } return subsets; } +private: // Builds a single subset by pulling indexes off index_vector_ std::vector constructSubset(uint32_t number_of_elements_in_subset) { std::vector subset; for (uint32_t i = 0; i < number_of_elements_in_subset && index_vector_.size() != 0; i++) { + // Index of bytestring will wrap around if it "overflows" past the random bytestring's length. uint64_t index_of_index_vector = - random_bytestring_[index_of_random_bytestring_] % index_vector_.size(); + random_bytestring_[index_of_random_bytestring_ % random_bytestring_.length()] % + index_vector_.size(); uint64_t index = index_vector_.at(index_of_index_vector); subset.push_back(index); index_vector_.erase(index_vector_.begin() + index_of_index_vector); ++index_of_random_bytestring_; - // Index of bytestring will wrap around if overflows - if (index_of_random_bytestring_ == random_bytestring_.length()) { - index_of_random_bytestring_ = 0; - } } return subset; } @@ -72,7 +77,7 @@ class ProperSubsetSelector { // This bytestring will be iterated through logically representing randomness in order to choose // subsets std::string random_bytestring_; - uint32_t index_of_random_bytestring_; + uint32_t index_of_random_bytestring_ = 0; }; } // namespace Fuzz From a81eabe707e8d713320dd4a3547da99bb612386d Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 13 Oct 2020 01:54:22 +0000 Subject: [PATCH 22/34] Added logic for localities Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 18 ++- .../upstream/load_balancer_fuzz_base.cc | 131 +++++++++++++++++- .../common/upstream/load_balancer_fuzz_base.h | 9 +- .../random_256_ports | 10 +- .../random_NoHosts | 10 +- .../random_load_balancer_corpus/random_Normal | 10 +- ...h-ba5efdfd9c412a8507087120783fe6529b1ac0cb | 10 +- .../random_largest-port-value | 10 +- .../random_many_choose_hosts | 10 +- .../random_max_ports | 10 +- .../random_overflowing_ports | 10 +- .../random_test_something | 10 +- ...t-6b0d6b83136a4cf0b9ccd468f11207a792859d43 | 5 +- ...t-9144cfbb40b5101ecc28b205b10e6c36a72aae83 | 5 +- .../random_with-locality | 49 +++++++ 15 files changed, 275 insertions(+), 32 deletions(-) create mode 100644 test/common/upstream/random_load_balancer_corpus/random_with-locality diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 16c745c79d73..93945609a7b8 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -27,6 +27,16 @@ message LbAction { } } +message SetupPriorityLevel { + uint32 num_hosts_in_priority_level = 1; + // Doesn't need a cap, as subset utility class handles "overflowing" subsets + uint32 num_hosts_locality_one = 2; + uint32 num_hosts_locality_two = 3; + uint32 num_hosts_locality_three = 4; // Hard cap at 3 localities for simplicity + // For choosing which hosts go in which locality + bytes random_bytestring = 5 [(validate.rules).bytes = {min_len: 1, max_len: 256}]; +} + // This message represents what LoadBalancerFuzzBase will interact with, performing setup of host sets and calling into load balancers. // The logic that this message represents and the base class for load balancing fuzzing will be logic that maps to all types of load balancing // and can be used in a modular way at the highest level for each load balancer. @@ -35,12 +45,12 @@ message LoadBalancerTestCase { [(validate.rules).message.required = true]; repeated LbAction actions = 2; - // TODO: Localities - // Each generated integer will cause the fuzzer to initialize hosts at a certain priority level, each integer generated adding a priority + // Each generated integer will cause the fuzzer to initialize hosts at a certain priority level, each integer generated adding a priority // level with integer generated hosts in that new priority level. Capped at 20 for simplicity. - repeated uint32 num_hosts_in_priority_level = 3 + repeated SetupPriorityLevel setup_priority_levels = 3 [(validate.rules).repeated = {min_items: 1, max_items: 20}]; - // This number is used to instantiate the prng. The prng takes the place of random() calls, allowing a representative random distribution which is also deterministic. + // This number is used to instantiate the prng. The prng takes the place of random() calls, allowing a representative random distribution + // which is also deterministic. uint64 seed_for_prng = 4 [(validate.rules).uint64.gt = 0]; } diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 37ec790d979f..febfd73174cc 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -7,22 +7,55 @@ namespace Envoy { namespace Upstream { -void LoadBalancerFuzzBase::initializeASingleHostSet(const uint32_t num_hosts_in_host_set, - const uint8_t priority_level) { +void LoadBalancerFuzzBase::initializeASingleHostSet( + const test::common::upstream::SetupPriorityLevel& setup_priority_level, + const uint8_t priority_level) { + uint32_t num_hosts_in_priority_level = setup_priority_level.num_hosts_in_priority_level(); ENVOY_LOG_MISC(trace, "Will attempt to initialize host set {} with {} hosts.", priority_level, - num_hosts_in_host_set); + num_hosts_in_priority_level); MockHostSet& host_set = *priority_set_.getMockHostSet(priority_level); uint32_t hosts_made = 0; // Cap each host set at 256 hosts for efficiency const uint32_t max_num_hosts_in_priority_level = MAX_NUM_HOSTS_IN_PRIORITY_LEVEL; // Leave port clause in for future changes - while (hosts_made < std::min(num_hosts_in_host_set, max_num_hosts_in_priority_level) && + while (hosts_made < std::min(num_hosts_in_priority_level, max_num_hosts_in_priority_level) && port_ < 65535) { host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port_))); ++port_; ++hosts_made; } - // TODO: Random call and mod against host_set size for locality logic + + Fuzz::ProperSubsetSelector subset_selector(setup_priority_level.random_bytestring()); + + std::vector> localities = subset_selector.constructSubsets( + {setup_priority_level.num_hosts_locality_one(), setup_priority_level.num_hosts_locality_two(), + setup_priority_level.num_hosts_locality_three()}, + num_hosts_in_priority_level); + + // Construct three vectors of hosts each representing a locality level, construct + // hosts_per_locality from these three vectors + HostVector locality_one = {}; + for (uint8_t index : localities[0]) { + ENVOY_LOG_MISC(trace, "Added host at index {} to locality 1", index); + locality_one.push_back(host_set.hosts_[index]); + locality_indexes_[index] = 1; + } + + HostVector locality_two = {}; + for (uint8_t index : localities[1]) { + ENVOY_LOG_MISC(trace, "Added host at index {} to locality 2", index); + locality_two.push_back(host_set.hosts_[index]); + locality_indexes_[index] = 2; + } + + HostVector locality_three = {}; + for (uint8_t index : localities[2]) { + ENVOY_LOG_MISC(trace, "Added host at index {} to locality 3", index); + locality_three.push_back(host_set.hosts_[index]); + locality_indexes_[index] = 3; + } + + host_set.hosts_per_locality_ = makeHostsPerLocality({locality_one, locality_two, locality_three}); } // Initializes random and fixed host sets @@ -30,8 +63,8 @@ void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { random_.initializeSeed(input.seed_for_prng()); uint8_t priority_of_host_set = 0; - for (uint16_t num_hosts_in_priority_level : input.num_hosts_in_priority_level()) { - initializeASingleHostSet(num_hosts_in_priority_level, priority_of_host_set); + for (const auto& setup_priority_level : input.setup_priority_levels()) { + initializeASingleHostSet(setup_priority_level, priority_of_host_set); priority_of_host_set++; } num_priority_levels_ = priority_of_host_set; @@ -80,6 +113,90 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio priority_of_host_set, index); } + // Handle updating health flags for hosts_per_locality_ + HostVector healthy_hosts_locality_one = {}; + HostVector degraded_hosts_locality_one = {}; + HostVector excluded_hosts_locality_one = {}; + + HostVector healthy_hosts_locality_two = {}; + HostVector degraded_hosts_locality_two = {}; + HostVector excluded_hosts_locality_two = {}; + + HostVector healthy_hosts_locality_three = {}; + HostVector degraded_hosts_locality_three = {}; + HostVector excluded_hosts_locality_three = {}; + + for (uint8_t index : subsets.at(0)) { + // If the host is in a locality, we have to add it to healthy hosts per locality + if (!(locality_indexes_.find(index) == locality_indexes_.end())) { + ENVOY_LOG_MISC(trace, "Added healthy host at index {} in locality {}", index, + locality_indexes_[index]); + switch (locality_indexes_[index]) { + case 1: + healthy_hosts_locality_one.push_back(host_set.hosts_[index]); + break; + case 2: + healthy_hosts_locality_two.push_back(host_set.hosts_[index]); + break; + case 3: + healthy_hosts_locality_three.push_back(host_set.hosts_[index]); + break; + default: // shouldn't hit + NOT_REACHED_GCOVR_EXCL_LINE; + } + } + } + + for (uint8_t index : subsets.at(1)) { + // If the host is in a locality, we have to add it to degraded hosts per locality + if (!(locality_indexes_.find(index) == locality_indexes_.end())) { + ENVOY_LOG_MISC(trace, "Added degraded host at index {} in locality {}", index, + locality_indexes_[index]); + switch (locality_indexes_[index]) { + case 1: + degraded_hosts_locality_one.push_back(host_set.hosts_[index]); + break; + case 2: + degraded_hosts_locality_two.push_back(host_set.hosts_[index]); + break; + case 3: + degraded_hosts_locality_three.push_back(host_set.hosts_[index]); + break; + default: // shouldn't hit + NOT_REACHED_GCOVR_EXCL_LINE; + } + } + } + + for (uint8_t index : subsets.at(2)) { + // If the host is in a locality, we have to add it to excluded hosts per locality + if (!(locality_indexes_.find(index) == locality_indexes_.end())) { + ENVOY_LOG_MISC(trace, "Added excluded host at index {} in locality {}", index, + locality_indexes_[index]); + switch (locality_indexes_[index]) { + case 1: + excluded_hosts_locality_one.push_back(host_set.hosts_[index]); + break; + case 2: + excluded_hosts_locality_two.push_back(host_set.hosts_[index]); + break; + case 3: + excluded_hosts_locality_three.push_back(host_set.hosts_[index]); + break; + default: // shouldn't hit + NOT_REACHED_GCOVR_EXCL_LINE; + } + } + } + // This overrides what is currently present in the host set, thus not having to expliclity call + // vector.clear() + host_set.healthy_hosts_per_locality_ = makeHostsPerLocality( + {healthy_hosts_locality_one, healthy_hosts_locality_two, healthy_hosts_locality_three}); + host_set.degraded_hosts_per_locality_ = makeHostsPerLocality( + {degraded_hosts_locality_one, degraded_hosts_locality_two, degraded_hosts_locality_three}); + host_set.excluded_hosts_per_locality_ = makeHostsPerLocality( + {excluded_hosts_locality_one, excluded_hosts_locality_two, excluded_hosts_locality_three}); + host_set.runCallbacks({}, {}); } diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 57c0bc6bbdaf..0bf599157415 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -22,7 +22,9 @@ class LoadBalancerFuzzBase { // Untrusted upstreams don't have the ability to change the host set size, so keep it constant // over the fuzz iteration. - void initializeASingleHostSet(const uint32_t num_hosts_in_host_set, const uint8_t priority_level); + void + initializeASingleHostSet(const test::common::upstream::SetupPriorityLevel& setup_priority_level, + const uint8_t priority_level); // Initializes load balancer components shared amongst every load balancer, random_, and // priority_set_ @@ -53,6 +55,11 @@ class LoadBalancerFuzzBase { // There are used to construct the priority set at the beginning of the fuzz iteration uint16_t port_ = 80; uint8_t num_priority_levels_ = 0; + + // This map used when updating health flags - making sure the health flags are updated hosts in + // localities Key - index of host within full host list, value - locality level host at index is + // in + absl::node_hash_map locality_indexes_; }; } // namespace Upstream diff --git a/test/common/upstream/random_load_balancer_corpus/random_256_ports b/test/common/upstream/random_load_balancer_corpus/random_256_ports index 65ded4399181..1924462a2ee7 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_256_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_256_ports @@ -29,7 +29,13 @@ actions { } } -num_hosts_in_priority_level: 256 -num_hosts_in_priority_level: 256 +setup_priority_levels { + num_hosts_in_priority_level: 256 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 256 + random_bytestring: "\x01\x02" +} seed_for_prng: 4 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_NoHosts b/test/common/upstream/random_load_balancer_corpus/random_NoHosts index 8a91f2d17ced..551225e908e3 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_NoHosts +++ b/test/common/upstream/random_load_balancer_corpus/random_NoHosts @@ -12,7 +12,13 @@ actions { } } -num_hosts_in_priority_level: 0 -num_hosts_in_priority_level: 0 +setup_priority_levels { + num_hosts_in_priority_level: 0 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 0 + random_bytestring: "\x01\x02" +} seed_for_prng: 2 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_Normal b/test/common/upstream/random_load_balancer_corpus/random_Normal index 1bfd0a2dd5d9..61bb66f8638c 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_Normal +++ b/test/common/upstream/random_load_balancer_corpus/random_Normal @@ -29,7 +29,13 @@ actions { } } -num_hosts_in_priority_level: 2 -num_hosts_in_priority_level: 0 +setup_priority_levels { + num_hosts_in_priority_level: 2 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 0 + random_bytestring: "\x01\x02" +} seed_for_prng: 1 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb b/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb index 295929546e99..602a393132bf 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb +++ b/test/common/upstream/random_load_balancer_corpus/random_crash-ba5efdfd9c412a8507087120783fe6529b1ac0cb @@ -26,7 +26,13 @@ actions { choose_host { } } -num_hosts_in_priority_level: 2 -num_hosts_in_priority_level: 9007199258945536 +setup_priority_levels { + num_hosts_in_priority_level: 2 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 9007199259945536 + random_bytestring: "\x01\x02" +} seed_for_prng: 6 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_largest-port-value b/test/common/upstream/random_load_balancer_corpus/random_largest-port-value index ef8726fba5cd..2f95ce787ef1 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_largest-port-value +++ b/test/common/upstream/random_load_balancer_corpus/random_largest-port-value @@ -22,7 +22,13 @@ actions { choose_host { } } -num_hosts_in_priority_level: 65455 -num_hosts_in_priority_level: 65455 +nsetup_priority_levels { + num_hosts_in_priority_level: 65455 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 65455 + random_bytestring: "\x01\x02" +} seed_for_prng: 5 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts b/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts index 60f3e7e07852..b263d07ec40e 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts +++ b/test/common/upstream/random_load_balancer_corpus/random_many_choose_hosts @@ -49,7 +49,13 @@ actions { } } -num_hosts_in_priority_level: 2 -num_hosts_in_priority_level: 0 +setup_priority_levels { + num_hosts_in_priority_level: 2 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 0 + random_bytestring: "\x01\x02" +} seed_for_prng: 1 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_max_ports b/test/common/upstream/random_load_balancer_corpus/random_max_ports index d214489e9fe2..4a7406d8b765 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_max_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_max_ports @@ -29,7 +29,13 @@ actions { } } -num_hosts_in_priority_level: 32726 -num_hosts_in_priority_level: 32726 +setup_priority_levels { + num_hosts_in_priority_level: 32726 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 32726 + random_bytestring: "\x01\x02" +} seed_for_prng: 88 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports b/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports index 481204e85b56..4598c29dbe10 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports +++ b/test/common/upstream/random_load_balancer_corpus/random_overflowing_ports @@ -29,7 +29,13 @@ actions { } } -num_hosts_in_priority_level: 60000 -num_hosts_in_priority_level: 60000 +setup_priority_levels { + num_hosts_in_priority_level: 60000 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 60000 + random_bytestring: "\x01\x02" +} seed_for_prng: 4 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_test_something b/test/common/upstream/random_load_balancer_corpus/random_test_something index 19b9201dbb3d..172e2cb1c051 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_test_something +++ b/test/common/upstream/random_load_balancer_corpus/random_test_something @@ -29,7 +29,13 @@ actions { } } -num_hosts_in_priority_level: 250 -num_hosts_in_priority_level: 250 +setup_priority_levels { + num_hosts_in_priority_level: 250 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 250 + random_bytestring: "\x01\x02" +} seed_for_prng: 4 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 index daf95d962631..96f3d0efd72b 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-6b0d6b83136a4cf0b9ccd468f11207a792859d43 @@ -23,6 +23,9 @@ load_balancer_test_case { random_bytestring: "\x01\x02" } } - num_hosts_in_priority_level: 2063625226 + setup_priority_levels { + num_hosts_in_priority_level: 13534154135 + random_bytestring: "\x01\x02" + } seed_for_prng: 32 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 index de515e3b39a7..2fca35ed475d 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 +++ b/test/common/upstream/random_load_balancer_corpus/random_timeout-9144cfbb40b5101ecc28b205b10e6c36a72aae83 @@ -17,6 +17,9 @@ load_balancer_test_case { random_bytestring: "\x01\x02\x03\x04" } } - num_hosts_in_priority_level: 1024 + setup_priority_levels { + num_hosts_in_priority_level: 1024 + random_bytestring: "\x01\x02" + } seed_for_prng: 62208 } diff --git a/test/common/upstream/random_load_balancer_corpus/random_with-locality b/test/common/upstream/random_load_balancer_corpus/random_with-locality new file mode 100644 index 000000000000..385be32c1947 --- /dev/null +++ b/test/common/upstream/random_load_balancer_corpus/random_with-locality @@ -0,0 +1,49 @@ +load_balancer_test_case { +common_lb_config { + +} +actions { + update_health_flags { + host_priority: 0 + num_healthy_hosts: 2 + num_degraded_hosts: 3 + num_excluded_hosts: 4 + random_bytestring: "\x01\x02\x03\x04\x05\x06" + } +} +actions { + prefetch { + + } +} +actions { + prefetch { + + } +} +actions { + choose_host { + + } +} +actions { + choose_host { + + } +} +setup_priority_levels { + num_hosts_in_priority_level: 20 + num_hosts_locality_one: 3 + num_hosts_locality_two: 4 + num_hosts_locality_three: 5 + random_bytestring: "\x01\x02" +} +setup_priority_levels { + num_hosts_in_priority_level: 20 + num_hosts_locality_one: 3 + num_hosts_locality_two: 4 + num_hosts_locality_three: 5 + random_bytestring: "\x01\x02" +} +seed_for_prng: 1 +} From 31a5668d624c06dcd7f6d0e89df81f0dd166d9ea Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 13 Oct 2020 04:34:03 +0000 Subject: [PATCH 23/34] Fixed slow iterations Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 11 +++-- .../upstream/load_balancer_fuzz_base.cc | 4 +- ...t-eed4596101efb3e737f736c8d5bcd4f0815a8728 | 40 ++++++++++++++++ .../random_slow-unit-test | 46 +++++++++++++++++++ 4 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 test/common/upstream/random_load_balancer_corpus/random_slow-unit-eed4596101efb3e737f736c8d5bcd4f0815a8728 create mode 100644 test/common/upstream/random_load_balancer_corpus/random_slow-unit-test diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index 93945609a7b8..b217cc55a42f 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -28,11 +28,12 @@ message LbAction { } message SetupPriorityLevel { - uint32 num_hosts_in_priority_level = 1; - // Doesn't need a cap, as subset utility class handles "overflowing" subsets - uint32 num_hosts_locality_one = 2; - uint32 num_hosts_locality_two = 3; - uint32 num_hosts_locality_three = 4; // Hard cap at 3 localities for simplicity + uint32 num_hosts_in_priority_level = 1 [(validate.rules).uint32.lte = 500]; + // Doesn't need a cap on sum, as subset utility class handles "overflowing" subsets + uint32 num_hosts_locality_one = 2 [(validate.rules).uint32.lte = 500]; + uint32 num_hosts_locality_two = 3 [(validate.rules).uint32.lte = 500]; + // Hard cap at 3 localities for simplicity + uint32 num_hosts_locality_three = 4 [(validate.rules).uint32.lte = 500]; // For choosing which hosts go in which locality bytes random_bytestring = 5 [(validate.rules).bytes = {min_len: 1, max_len: 256}]; } diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index febfd73174cc..d75932784b4e 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -30,7 +30,7 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( std::vector> localities = subset_selector.constructSubsets( {setup_priority_level.num_hosts_locality_one(), setup_priority_level.num_hosts_locality_two(), setup_priority_level.num_hosts_locality_three()}, - num_hosts_in_priority_level); + std::min(num_hosts_in_priority_level, max_num_hosts_in_priority_level)); // Construct three vectors of hosts each representing a locality level, construct // hosts_per_locality from these three vectors @@ -188,7 +188,7 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio } } } - // This overrides what is currently present in the host set, thus not having to expliclity call + // This overrides what is currently present in the host set, thus not having to explicitly call // vector.clear() host_set.healthy_hosts_per_locality_ = makeHostsPerLocality( {healthy_hosts_locality_one, healthy_hosts_locality_two, healthy_hosts_locality_three}); diff --git a/test/common/upstream/random_load_balancer_corpus/random_slow-unit-eed4596101efb3e737f736c8d5bcd4f0815a8728 b/test/common/upstream/random_load_balancer_corpus/random_slow-unit-eed4596101efb3e737f736c8d5bcd4f0815a8728 new file mode 100644 index 000000000000..7bebf1a2cf96 --- /dev/null +++ b/test/common/upstream/random_load_balancer_corpus/random_slow-unit-eed4596101efb3e737f736c8d5bcd4f0815a8728 @@ -0,0 +1,40 @@ +load_balancer_test_case { + common_lb_config { + update_merge_window { + nanos: 512 + } + } + actions { + update_health_flags { + num_healthy_hosts: 2 + random_bytestring: "\001\002\003\004" + } + } + actions { + prefetch { + } + } + actions { + prefetch { + } + } + actions { + choose_host { + } + } + actions { + update_health_flags { + num_healthy_hosts: 2 + random_bytestring: "\001\002\003\004" + } + } + setup_priority_levels { + num_hosts_in_priority_level: 536903638 + random_bytestring: "\001\002" + } + setup_priority_levels { + num_hosts_in_priority_level: 32726 + random_bytestring: "\001\002" + } + seed_for_prng: 88 +} diff --git a/test/common/upstream/random_load_balancer_corpus/random_slow-unit-test b/test/common/upstream/random_load_balancer_corpus/random_slow-unit-test new file mode 100644 index 000000000000..e1f2fcfdd303 --- /dev/null +++ b/test/common/upstream/random_load_balancer_corpus/random_slow-unit-test @@ -0,0 +1,46 @@ +load_balancer_test_case { + common_lb_config { + update_merge_window { + nanos: 512 + } + } + actions { + update_health_flags { + num_healthy_hosts: 2 + random_bytestring: "\001\002\003\004" + } + } + actions { + prefetch { + } + } + actions { + prefetch { + } + } + actions { + choose_host { + } + } + actions { + update_health_flags { + num_healthy_hosts: 2 + random_bytestring: "\001\002\003\004" + } + } + setup_priority_levels { + num_hosts_in_priority_level: 500 + num_hosts_locality_one: 50 + num_hosts_locality_two: 50 + num_hosts_locality_three: 50 + random_bytestring: "\001\002" + } + setup_priority_levels { + num_hosts_in_priority_level: 500 + num_hosts_locality_one: 50 + num_hosts_locality_two: 50 + num_hosts_locality_three: 50 + random_bytestring: "\001\002" + } + seed_for_prng: 88 +} From 91e5738c1f57a8599557d0bc7949c103976b72ab Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 13 Oct 2020 19:10:40 +0000 Subject: [PATCH 24/34] Partially responded to comments Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 4 ++ .../upstream/load_balancer_fuzz_base.cc | 40 ++++++++++--------- .../common/upstream/load_balancer_fuzz_base.h | 8 +++- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index b217cc55a42f..a8b6bc3902f4 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -21,8 +21,12 @@ message UpdateHealthFlags { message LbAction { oneof action_selector { option (validate.required) = true; + // This updates the health flags of hosts at a certain priority level. The number of hosts in each priority level/in localities is static, + // as untrusted upstreams cannot change that, and can only change their health flags. UpdateHealthFlags update_health_flags = 1; + // Prefetches a host using the encapsulated specific load balancer. google.protobuf.Empty prefetch = 2; + // Chooses a host using the encapsulated specific load balancer. google.protobuf.Empty choose_host = 3; } } diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index d75932784b4e..6c0b4a9ede78 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -2,15 +2,19 @@ #include "test/common/upstream/utility.h" -#define MAX_NUM_HOSTS_IN_PRIORITY_LEVEL 256 - namespace Envoy { namespace Upstream { +namespace { + +constexpr uint32_t MAX_NUM_HOSTS_IN_PRIORITY_LEVEL = 256; + +} // namespace + void LoadBalancerFuzzBase::initializeASingleHostSet( const test::common::upstream::SetupPriorityLevel& setup_priority_level, const uint8_t priority_level) { - uint32_t num_hosts_in_priority_level = setup_priority_level.num_hosts_in_priority_level(); + const uint32_t num_hosts_in_priority_level = setup_priority_level.num_hosts_in_priority_level(); ENVOY_LOG_MISC(trace, "Will attempt to initialize host set {} with {} hosts.", priority_level, num_hosts_in_priority_level); MockHostSet& host_set = *priority_set_.getMockHostSet(priority_level); @@ -27,7 +31,7 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( Fuzz::ProperSubsetSelector subset_selector(setup_priority_level.random_bytestring()); - std::vector> localities = subset_selector.constructSubsets( + const std::vector> localities = subset_selector.constructSubsets( {setup_priority_level.num_hosts_locality_one(), setup_priority_level.num_hosts_locality_two(), setup_priority_level.num_hosts_locality_three()}, std::min(num_hosts_in_priority_level, max_num_hosts_in_priority_level)); @@ -38,21 +42,21 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( for (uint8_t index : localities[0]) { ENVOY_LOG_MISC(trace, "Added host at index {} to locality 1", index); locality_one.push_back(host_set.hosts_[index]); - locality_indexes_[index] = 1; + locality_indexes_[index] = LoadBalancerFuzzBase::Locality::ONE; } HostVector locality_two = {}; for (uint8_t index : localities[1]) { ENVOY_LOG_MISC(trace, "Added host at index {} to locality 2", index); locality_two.push_back(host_set.hosts_[index]); - locality_indexes_[index] = 2; + locality_indexes_[index] = LoadBalancerFuzzBase::Locality::TWO; } HostVector locality_three = {}; for (uint8_t index : localities[2]) { ENVOY_LOG_MISC(trace, "Added host at index {} to locality 3", index); locality_three.push_back(host_set.hosts_[index]); - locality_indexes_[index] = 3; + locality_indexes_[index] = LoadBalancerFuzzBase::Locality::THREE; } host_set.hosts_per_locality_ = makeHostsPerLocality({locality_one, locality_two, locality_three}); @@ -82,14 +86,14 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio ENVOY_LOG_MISC(trace, "Updating health flags for host set at priority: {}", priority_of_host_set); MockHostSet& host_set = *priority_set_.getMockHostSet(priority_of_host_set); // This downcast will not overflow because size is capped by port numbers - uint32_t host_set_size = host_set.hosts_.size(); + const uint32_t host_set_size = host_set.hosts_.size(); host_set.healthy_hosts_.clear(); host_set.degraded_hosts_.clear(); host_set.excluded_hosts_.clear(); Fuzz::ProperSubsetSelector subset_selector(random_bytestring); - std::vector> subsets = subset_selector.constructSubsets( + const std::vector> subsets = subset_selector.constructSubsets( {num_healthy_hosts, num_degraded_hosts, num_excluded_hosts}, host_set_size); // Healthy hosts are first subset @@ -132,13 +136,13 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio ENVOY_LOG_MISC(trace, "Added healthy host at index {} in locality {}", index, locality_indexes_[index]); switch (locality_indexes_[index]) { - case 1: + case LoadBalancerFuzzBase::Locality::ONE: healthy_hosts_locality_one.push_back(host_set.hosts_[index]); break; - case 2: + case LoadBalancerFuzzBase::Locality::TWO: healthy_hosts_locality_two.push_back(host_set.hosts_[index]); break; - case 3: + case LoadBalancerFuzzBase::Locality::THREE: healthy_hosts_locality_three.push_back(host_set.hosts_[index]); break; default: // shouldn't hit @@ -153,13 +157,13 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio ENVOY_LOG_MISC(trace, "Added degraded host at index {} in locality {}", index, locality_indexes_[index]); switch (locality_indexes_[index]) { - case 1: + case LoadBalancerFuzzBase::Locality::ONE: degraded_hosts_locality_one.push_back(host_set.hosts_[index]); break; - case 2: + case LoadBalancerFuzzBase::Locality::TWO: degraded_hosts_locality_two.push_back(host_set.hosts_[index]); break; - case 3: + case LoadBalancerFuzzBase::Locality::THREE: degraded_hosts_locality_three.push_back(host_set.hosts_[index]); break; default: // shouldn't hit @@ -174,13 +178,13 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio ENVOY_LOG_MISC(trace, "Added excluded host at index {} in locality {}", index, locality_indexes_[index]); switch (locality_indexes_[index]) { - case 1: + case LoadBalancerFuzzBase::Locality::ONE: excluded_hosts_locality_one.push_back(host_set.hosts_[index]); break; - case 2: + case LoadBalancerFuzzBase::Locality::TWO: excluded_hosts_locality_two.push_back(host_set.hosts_[index]); break; - case 3: + case LoadBalancerFuzzBase::Locality::THREE: excluded_hosts_locality_three.push_back(host_set.hosts_[index]); break; default: // shouldn't hit diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 0bf599157415..e24114be9f8d 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -56,10 +56,16 @@ class LoadBalancerFuzzBase { uint16_t port_ = 80; uint8_t num_priority_levels_ = 0; + enum class Locality { + ONE, + TWO, + THREE, + }; + // This map used when updating health flags - making sure the health flags are updated hosts in // localities Key - index of host within full host list, value - locality level host at index is // in - absl::node_hash_map locality_indexes_; + absl::node_hash_map locality_indexes_; }; } // namespace Upstream From 794918b645ab0e96dda0389dcfdbd02d371cd7eb Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 13 Oct 2020 20:00:24 +0000 Subject: [PATCH 25/34] Clang Tidy Signed-off-by: Zach --- test/fuzz/BUILD | 1 + test/fuzz/random.h | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/fuzz/BUILD b/test/fuzz/BUILD index e128a3c3f497..adb238a53f17 100644 --- a/test/fuzz/BUILD +++ b/test/fuzz/BUILD @@ -75,5 +75,6 @@ envoy_cc_test_library( deps = [ "//include/envoy/common:random_generator_interface", "//source/common/common:assert_lib", + "//source/common/common:minimal_logger_lib", ], ) diff --git a/test/fuzz/random.h b/test/fuzz/random.h index 9b8478efc222..6ef59fc5f7df 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -1,6 +1,9 @@ +#include #include #include +#include "envoy/common/random_generator.h" + namespace Envoy { namespace Random { @@ -49,8 +52,8 @@ class ProperSubsetSelector { index_vector_.push_back(i); } std::vector> subsets; - for (uint32_t i = 0; i < number_of_elements_in_each_subset.size(); i++) { - subsets.push_back(constructSubset(number_of_elements_in_each_subset.at(i))); + for (uint32_t i : number_of_elements_in_each_subset) { + subsets.push_back(constructSubset(i)); } return subsets; } @@ -59,7 +62,7 @@ class ProperSubsetSelector { // Builds a single subset by pulling indexes off index_vector_ std::vector constructSubset(uint32_t number_of_elements_in_subset) { std::vector subset; - for (uint32_t i = 0; i < number_of_elements_in_subset && index_vector_.size() != 0; i++) { + for (uint32_t i = 0; i < number_of_elements_in_subset && !index_vector_.empty(); i++) { // Index of bytestring will wrap around if it "overflows" past the random bytestring's length. uint64_t index_of_index_vector = random_bytestring_[index_of_random_bytestring_ % random_bytestring_.length()] % From c1c8e29ddc221d14a80b689ac36c8aa9e9354898 Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 13 Oct 2020 21:48:14 +0000 Subject: [PATCH 26/34] Adi's refactor comment Signed-off-by: Zach --- .../upstream/load_balancer_fuzz_base.cc | 112 ++++++------------ .../common/upstream/load_balancer_fuzz_base.h | 8 +- 2 files changed, 35 insertions(+), 85 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 6c0b4a9ede78..43c16bf29658 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -42,21 +42,21 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( for (uint8_t index : localities[0]) { ENVOY_LOG_MISC(trace, "Added host at index {} to locality 1", index); locality_one.push_back(host_set.hosts_[index]); - locality_indexes_[index] = LoadBalancerFuzzBase::Locality::ONE; + locality_indexes_[index] = 0; } HostVector locality_two = {}; for (uint8_t index : localities[1]) { ENVOY_LOG_MISC(trace, "Added host at index {} to locality 2", index); locality_two.push_back(host_set.hosts_[index]); - locality_indexes_[index] = LoadBalancerFuzzBase::Locality::TWO; + locality_indexes_[index] = 1; } HostVector locality_three = {}; for (uint8_t index : localities[2]) { ENVOY_LOG_MISC(trace, "Added host at index {} to locality 3", index); locality_three.push_back(host_set.hosts_[index]); - locality_indexes_[index] = LoadBalancerFuzzBase::Locality::THREE; + locality_indexes_[index] = 2; } host_set.hosts_per_locality_ = makeHostsPerLocality({locality_one, locality_two, locality_three}); @@ -118,88 +118,44 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio } // Handle updating health flags for hosts_per_locality_ - HostVector healthy_hosts_locality_one = {}; - HostVector degraded_hosts_locality_one = {}; - HostVector excluded_hosts_locality_one = {}; - HostVector healthy_hosts_locality_two = {}; - HostVector degraded_hosts_locality_two = {}; - HostVector excluded_hosts_locality_two = {}; - - HostVector healthy_hosts_locality_three = {}; - HostVector degraded_hosts_locality_three = {}; - HostVector excluded_hosts_locality_three = {}; - - for (uint8_t index : subsets.at(0)) { - // If the host is in a locality, we have to add it to healthy hosts per locality - if (!(locality_indexes_.find(index) == locality_indexes_.end())) { - ENVOY_LOG_MISC(trace, "Added healthy host at index {} in locality {}", index, - locality_indexes_[index]); - switch (locality_indexes_[index]) { - case LoadBalancerFuzzBase::Locality::ONE: - healthy_hosts_locality_one.push_back(host_set.hosts_[index]); - break; - case LoadBalancerFuzzBase::Locality::TWO: - healthy_hosts_locality_two.push_back(host_set.hosts_[index]); - break; - case LoadBalancerFuzzBase::Locality::THREE: - healthy_hosts_locality_three.push_back(host_set.hosts_[index]); - break; - default: // shouldn't hit - NOT_REACHED_GCOVR_EXCL_LINE; - } - } - } - - for (uint8_t index : subsets.at(1)) { - // If the host is in a locality, we have to add it to degraded hosts per locality - if (!(locality_indexes_.find(index) == locality_indexes_.end())) { - ENVOY_LOG_MISC(trace, "Added degraded host at index {} in locality {}", index, - locality_indexes_[index]); - switch (locality_indexes_[index]) { - case LoadBalancerFuzzBase::Locality::ONE: - degraded_hosts_locality_one.push_back(host_set.hosts_[index]); - break; - case LoadBalancerFuzzBase::Locality::TWO: - degraded_hosts_locality_two.push_back(host_set.hosts_[index]); - break; - case LoadBalancerFuzzBase::Locality::THREE: - degraded_hosts_locality_three.push_back(host_set.hosts_[index]); - break; - default: // shouldn't hit - NOT_REACHED_GCOVR_EXCL_LINE; + // The index within the array of the vector represents the locality + std::array healthy_hosts_per_locality; + std::array degraded_hosts_per_locality; + std::array excluded_hosts_per_locality; + + // Wrap those three in an array here, where the index represents health flag of + // healthy/degraded/excluded, used for indexing during iteration through subsets + std::array, 3> locality_health_flags = { + healthy_hosts_per_locality, degraded_hosts_per_locality, excluded_hosts_per_locality}; + + // Iterate through subsets + for (uint8_t health_flag = 0; health_flag < locality_health_flags.size(); health_flag++) { + for (uint8_t index : subsets.at(health_flag)) { // Each subset logically represents a health + // flag + // If the host is in a locality, we have to update the corresponding health flag host vector + if (!(locality_indexes_.find(index) == locality_indexes_.end())) { + // First dimension of array represents health_flag, second represents locality, which is + // pulled from map + locality_health_flags[health_flag][locality_indexes_[index]].push_back( + host_set.hosts_[index]); + ENVOY_LOG_MISC(trace, "Added host at index {} in locality {} to health flag set {}", index, + locality_indexes_[index], health_flag + 1); } } } - for (uint8_t index : subsets.at(2)) { - // If the host is in a locality, we have to add it to excluded hosts per locality - if (!(locality_indexes_.find(index) == locality_indexes_.end())) { - ENVOY_LOG_MISC(trace, "Added excluded host at index {} in locality {}", index, - locality_indexes_[index]); - switch (locality_indexes_[index]) { - case LoadBalancerFuzzBase::Locality::ONE: - excluded_hosts_locality_one.push_back(host_set.hosts_[index]); - break; - case LoadBalancerFuzzBase::Locality::TWO: - excluded_hosts_locality_two.push_back(host_set.hosts_[index]); - break; - case LoadBalancerFuzzBase::Locality::THREE: - excluded_hosts_locality_three.push_back(host_set.hosts_[index]); - break; - default: // shouldn't hit - NOT_REACHED_GCOVR_EXCL_LINE; - } - } - } // This overrides what is currently present in the host set, thus not having to explicitly call // vector.clear() - host_set.healthy_hosts_per_locality_ = makeHostsPerLocality( - {healthy_hosts_locality_one, healthy_hosts_locality_two, healthy_hosts_locality_three}); - host_set.degraded_hosts_per_locality_ = makeHostsPerLocality( - {degraded_hosts_locality_one, degraded_hosts_locality_two, degraded_hosts_locality_three}); - host_set.excluded_hosts_per_locality_ = makeHostsPerLocality( - {excluded_hosts_locality_one, excluded_hosts_locality_two, excluded_hosts_locality_three}); + host_set.healthy_hosts_per_locality_ = + makeHostsPerLocality({healthy_hosts_per_locality[0], healthy_hosts_per_locality[1], + healthy_hosts_per_locality[2]}); + host_set.degraded_hosts_per_locality_ = + makeHostsPerLocality({degraded_hosts_per_locality[0], degraded_hosts_per_locality[1], + degraded_hosts_per_locality[2]}); + host_set.excluded_hosts_per_locality_ = + makeHostsPerLocality({excluded_hosts_per_locality[0], excluded_hosts_per_locality[1], + excluded_hosts_per_locality[2]}); host_set.runCallbacks({}, {}); } diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index e24114be9f8d..0bf599157415 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -56,16 +56,10 @@ class LoadBalancerFuzzBase { uint16_t port_ = 80; uint8_t num_priority_levels_ = 0; - enum class Locality { - ONE, - TWO, - THREE, - }; - // This map used when updating health flags - making sure the health flags are updated hosts in // localities Key - index of host within full host list, value - locality level host at index is // in - absl::node_hash_map locality_indexes_; + absl::node_hash_map locality_indexes_; }; } // namespace Upstream From 741b3a0cb178d3f8b999ec54419afd106235c006 Mon Sep 17 00:00:00 2001 From: Zach Date: Wed, 14 Oct 2020 03:59:54 +0000 Subject: [PATCH 27/34] Clang tidy and Harvey nit Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz_base.cc | 4 ++-- test/fuzz/random.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 43c16bf29658..a962734c9c33 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -7,7 +7,7 @@ namespace Upstream { namespace { -constexpr uint32_t MAX_NUM_HOSTS_IN_PRIORITY_LEVEL = 256; +constexpr uint32_t MaxNumHostsPerPriorityLevel = 256; } // namespace @@ -20,7 +20,7 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( MockHostSet& host_set = *priority_set_.getMockHostSet(priority_level); uint32_t hosts_made = 0; // Cap each host set at 256 hosts for efficiency - const uint32_t max_num_hosts_in_priority_level = MAX_NUM_HOSTS_IN_PRIORITY_LEVEL; + const uint32_t max_num_hosts_in_priority_level = MaxNumHostsPerPriorityLevel; // Leave port clause in for future changes while (hosts_made < std::min(num_hosts_in_priority_level, max_num_hosts_in_priority_level) && port_ < 65535) { diff --git a/test/fuzz/random.h b/test/fuzz/random.h index 6ef59fc5f7df..7a33dbf4d450 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -4,6 +4,9 @@ #include "envoy/common/random_generator.h" +#include "common/common/assert.h" +#include "common/common/logger.h" + namespace Envoy { namespace Random { @@ -18,7 +21,7 @@ class PsuedoRandomGenerator64 : public RandomGenerator { uint64_t random() override { // Makes sure initializeSeed() was already called ASSERT(prng_ != nullptr); - uint64_t to_return = (*prng_.get())(); + uint64_t to_return = (*prng_)(); ENVOY_LOG_MISC(trace, "random() returned: {}", to_return); return to_return; } From 52cbbd55829dc1b48eecac02c9f899fcd7f88bfa Mon Sep 17 00:00:00 2001 From: Zach Date: Wed, 14 Oct 2020 19:13:33 +0000 Subject: [PATCH 28/34] Responded to Asra's comments Signed-off-by: Zach --- .../upstream/load_balancer_fuzz_base.cc | 60 ++++++++----------- .../common/upstream/load_balancer_fuzz_base.h | 13 ++-- test/fuzz/random.h | 3 +- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index a962734c9c33..bcb8f934c94b 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -19,10 +19,8 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( num_hosts_in_priority_level); MockHostSet& host_set = *priority_set_.getMockHostSet(priority_level); uint32_t hosts_made = 0; - // Cap each host set at 256 hosts for efficiency - const uint32_t max_num_hosts_in_priority_level = MaxNumHostsPerPriorityLevel; - // Leave port clause in for future changes - while (hosts_made < std::min(num_hosts_in_priority_level, max_num_hosts_in_priority_level) && + // Cap each host set at 256 hosts for efficiency - Leave port clause in for future changes + while (hosts_made < std::min(num_hosts_in_priority_level, MaxNumHostsPerPriorityLevel) && port_ < 65535) { host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port_))); ++port_; @@ -34,31 +32,25 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( const std::vector> localities = subset_selector.constructSubsets( {setup_priority_level.num_hosts_locality_one(), setup_priority_level.num_hosts_locality_two(), setup_priority_level.num_hosts_locality_three()}, - std::min(num_hosts_in_priority_level, max_num_hosts_in_priority_level)); + std::min(num_hosts_in_priority_level, MaxNumHostsPerPriorityLevel)); - // Construct three vectors of hosts each representing a locality level, construct - // hosts_per_locality from these three vectors HostVector locality_one = {}; - for (uint8_t index : localities[0]) { - ENVOY_LOG_MISC(trace, "Added host at index {} to locality 1", index); - locality_one.push_back(host_set.hosts_[index]); - locality_indexes_[index] = 0; - } - HostVector locality_two = {}; - for (uint8_t index : localities[1]) { - ENVOY_LOG_MISC(trace, "Added host at index {} to locality 2", index); - locality_two.push_back(host_set.hosts_[index]); - locality_indexes_[index] = 1; - } - HostVector locality_three = {}; - for (uint8_t index : localities[2]) { - ENVOY_LOG_MISC(trace, "Added host at index {} to locality 3", index); - locality_three.push_back(host_set.hosts_[index]); - locality_indexes_[index] = 2; + // Used to index into correct locality in iteration through subsets + std::array locality_indexes = {locality_one, locality_two, locality_three}; + + for (uint8_t locality = 0; locality < locality_indexes.size(); locality++) { + for (uint8_t index : localities[locality]) { + locality_indexes[locality].push_back(host_set.hosts_[index]); + locality_indexes_[index] = locality; + } } + ENVOY_LOG_MISC(trace, "Added these hosts to locality 1: ", absl::StrJoin(localities[0], " ")); + ENVOY_LOG_MISC(trace, "Added these hosts to locality 2: ", absl::StrJoin(localities[1], " ")); + ENVOY_LOG_MISC(trace, "Added these hosts to locality 3: ", absl::StrJoin(localities[2], " ")); + host_set.hosts_per_locality_ = makeHostsPerLocality({locality_one, locality_two, locality_three}); } @@ -66,12 +58,12 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { random_.initializeSeed(input.seed_for_prng()); - uint8_t priority_of_host_set = 0; - for (const auto& setup_priority_level : input.setup_priority_levels()) { - initializeASingleHostSet(setup_priority_level, priority_of_host_set); - priority_of_host_set++; + for (uint8_t priority_of_host_set = 0; + priority_of_host_set < input.setup_priority_levels().size(); ++priority_of_host_set) { + initializeASingleHostSet(input.setup_priority_levels().at(priority_of_host_set), + priority_of_host_set); } - num_priority_levels_ = priority_of_host_set; + num_priority_levels_ = input.setup_priority_levels().size(); } // Updating host sets is shared amongst all the load balancer tests. Since logically, we're just @@ -99,23 +91,23 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // Healthy hosts are first subset for (uint8_t index : subsets.at(0)) { host_set.healthy_hosts_.push_back(host_set.hosts_[index]); - ENVOY_LOG_MISC(trace, "Index of host made healthy at priority level {}: {}", - priority_of_host_set, index); } + ENVOY_LOG_MISC(trace, "Hosts made healthy at priority level {}: {}", priority_of_host_set, + absl::StrJoin(subsets.at(0), " ")); // Degraded hosts are second subset for (uint8_t index : subsets.at(1)) { host_set.degraded_hosts_.push_back(host_set.hosts_[index]); - ENVOY_LOG_MISC(trace, "Index of host made degraded at priority level {}: {}", - priority_of_host_set, index); } + ENVOY_LOG_MISC(trace, "Hosts made degraded at priority level {}: {}", priority_of_host_set, + absl::StrJoin(subsets.at(1), " ")); // Excluded hosts are third subset for (uint8_t index : subsets.at(2)) { host_set.excluded_hosts_.push_back(host_set.hosts_[index]); - ENVOY_LOG_MISC(trace, "Index of host made excluded at priority level {}: {}", - priority_of_host_set, index); } + ENVOY_LOG_MISC(trace, "Hosts made excluded at priority level {}: {}", priority_of_host_set, + absl::StrJoin(subsets.at(2), " ")); // Handle updating health flags for hosts_per_locality_ diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 0bf599157415..4d7b73472d3b 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -20,12 +20,6 @@ class LoadBalancerFuzzBase { public: LoadBalancerFuzzBase() : stats_(ClusterInfoImpl::generateStats(stats_store_)){}; - // Untrusted upstreams don't have the ability to change the host set size, so keep it constant - // over the fuzz iteration. - void - initializeASingleHostSet(const test::common::upstream::SetupPriorityLevel& setup_priority_level, - const uint8_t priority_level); - // Initializes load balancer components shared amongst every load balancer, random_, and // priority_set_ void initializeLbComponents(const test::common::upstream::LoadBalancerTestCase& input); @@ -52,6 +46,13 @@ class LoadBalancerFuzzBase { std::shared_ptr info_{new NiceMock()}; std::unique_ptr lb_; +private: + // Untrusted upstreams don't have the ability to change the host set size, so keep it constant + // over the fuzz iteration. + void + initializeASingleHostSet(const test::common::upstream::SetupPriorityLevel& setup_priority_level, + const uint8_t priority_level); + // There are used to construct the priority set at the beginning of the fuzz iteration uint16_t port_ = 80; uint8_t num_priority_levels_ = 0; diff --git a/test/fuzz/random.h b/test/fuzz/random.h index 7a33dbf4d450..8d6689d06ed5 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -55,6 +55,7 @@ class ProperSubsetSelector { index_vector_.push_back(i); } std::vector> subsets; + subsets.reserve(number_of_elements_in_each_subset.size()); for (uint32_t i : number_of_elements_in_each_subset) { subsets.push_back(constructSubset(i)); } @@ -82,7 +83,7 @@ class ProperSubsetSelector { // This bytestring will be iterated through logically representing randomness in order to choose // subsets - std::string random_bytestring_; + const std::string random_bytestring_; uint32_t index_of_random_bytestring_ = 0; }; From 4bec47db90291afbf4efa33884d01c1cff1cc801 Mon Sep 17 00:00:00 2001 From: Zach Date: Thu, 15 Oct 2020 05:12:52 +0000 Subject: [PATCH 29/34] Partially responded to comments, still have 0(N^2) and flags Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz.proto | 7 +++--- .../upstream/load_balancer_fuzz_base.cc | 22 +++++++++--------- .../random_with-locality | 12 +++++----- test/fuzz/random.h | 23 +++++++++---------- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz.proto b/test/common/upstream/load_balancer_fuzz.proto index a8b6bc3902f4..c4b1ead2c7d0 100644 --- a/test/common/upstream/load_balancer_fuzz.proto +++ b/test/common/upstream/load_balancer_fuzz.proto @@ -33,11 +33,10 @@ message LbAction { message SetupPriorityLevel { uint32 num_hosts_in_priority_level = 1 [(validate.rules).uint32.lte = 500]; - // Doesn't need a cap on sum, as subset utility class handles "overflowing" subsets - uint32 num_hosts_locality_one = 2 [(validate.rules).uint32.lte = 500]; - uint32 num_hosts_locality_two = 3 [(validate.rules).uint32.lte = 500]; + uint32 num_hosts_locality_a = 2 [(validate.rules).uint32.lte = 500]; + uint32 num_hosts_locality_b = 3 [(validate.rules).uint32.lte = 500]; // Hard cap at 3 localities for simplicity - uint32 num_hosts_locality_three = 4 [(validate.rules).uint32.lte = 500]; + uint32 num_hosts_locality_c = 4 [(validate.rules).uint32.lte = 500]; // For choosing which hosts go in which locality bytes random_bytestring = 5 [(validate.rules).bytes = {min_len: 1, max_len: 256}]; } diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index bcb8f934c94b..3cf7bd35dccc 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -30,15 +30,15 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( Fuzz::ProperSubsetSelector subset_selector(setup_priority_level.random_bytestring()); const std::vector> localities = subset_selector.constructSubsets( - {setup_priority_level.num_hosts_locality_one(), setup_priority_level.num_hosts_locality_two(), - setup_priority_level.num_hosts_locality_three()}, + {setup_priority_level.num_hosts_locality_a(), setup_priority_level.num_hosts_locality_b(), + setup_priority_level.num_hosts_locality_c()}, std::min(num_hosts_in_priority_level, MaxNumHostsPerPriorityLevel)); - HostVector locality_one = {}; - HostVector locality_two = {}; - HostVector locality_three = {}; + HostVector locality_a = {}; + HostVector locality_b = {}; + HostVector locality_c = {}; // Used to index into correct locality in iteration through subsets - std::array locality_indexes = {locality_one, locality_two, locality_three}; + std::array locality_indexes = {locality_a, locality_b, locality_c}; for (uint8_t locality = 0; locality < locality_indexes.size(); locality++) { for (uint8_t index : localities[locality]) { @@ -51,7 +51,7 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( ENVOY_LOG_MISC(trace, "Added these hosts to locality 2: ", absl::StrJoin(localities[1], " ")); ENVOY_LOG_MISC(trace, "Added these hosts to locality 3: ", absl::StrJoin(localities[2], " ")); - host_set.hosts_per_locality_ = makeHostsPerLocality({locality_one, locality_two, locality_three}); + host_set.hosts_per_locality_ = makeHostsPerLocality({locality_a, locality_b, locality_c}); } // Initializes random and fixed host sets @@ -127,10 +127,10 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // flag // If the host is in a locality, we have to update the corresponding health flag host vector if (!(locality_indexes_.find(index) == locality_indexes_.end())) { - // First dimension of array represents health_flag, second represents locality, which is - // pulled from map - locality_health_flags[health_flag][locality_indexes_[index]].push_back( - host_set.hosts_[index]); + // After computing the host index subsets, we want to propagate these changes to a host set + // by building and using these host vectors + uint8_t locality = locality_indexes_[index]; + locality_health_flags[health_flag][locality].push_back(host_set.hosts_[index]); ENVOY_LOG_MISC(trace, "Added host at index {} in locality {} to health flag set {}", index, locality_indexes_[index], health_flag + 1); } diff --git a/test/common/upstream/random_load_balancer_corpus/random_with-locality b/test/common/upstream/random_load_balancer_corpus/random_with-locality index 385be32c1947..3f2f1281845f 100644 --- a/test/common/upstream/random_load_balancer_corpus/random_with-locality +++ b/test/common/upstream/random_load_balancer_corpus/random_with-locality @@ -33,16 +33,16 @@ actions { } setup_priority_levels { num_hosts_in_priority_level: 20 - num_hosts_locality_one: 3 - num_hosts_locality_two: 4 - num_hosts_locality_three: 5 + num_hosts_locality_a: 3 + num_hosts_locality_b: 4 + num_hosts_locality_c: 5 random_bytestring: "\x01\x02" } setup_priority_levels { num_hosts_in_priority_level: 20 - num_hosts_locality_one: 3 - num_hosts_locality_two: 4 - num_hosts_locality_three: 5 + num_hosts_locality_a: 3 + num_hosts_locality_b: 4 + num_hosts_locality_c: 5 random_bytestring: "\x01\x02" } seed_for_prng: 1 diff --git a/test/fuzz/random.h b/test/fuzz/random.h index 8d6689d06ed5..ae9516ada21c 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -49,39 +49,38 @@ class ProperSubsetSelector { std::vector> constructSubsets(const std::vector& number_of_elements_in_each_subset, uint32_t number_of_elements) { - index_vector_.clear(); - index_vector_.reserve(number_of_elements); + std::vector index_vector; + index_vector.reserve(number_of_elements); for (uint32_t i = 0; i < number_of_elements; i++) { - index_vector_.push_back(i); + index_vector.push_back(i); } std::vector> subsets; subsets.reserve(number_of_elements_in_each_subset.size()); for (uint32_t i : number_of_elements_in_each_subset) { - subsets.push_back(constructSubset(i)); + subsets.push_back(constructSubset(i, index_vector)); } return subsets; } private: // Builds a single subset by pulling indexes off index_vector_ - std::vector constructSubset(uint32_t number_of_elements_in_subset) { + std::vector constructSubset(uint32_t number_of_elements_in_subset, + std::vector& index_vector) { std::vector subset; - for (uint32_t i = 0; i < number_of_elements_in_subset && !index_vector_.empty(); i++) { + for (uint32_t i = 0; i < number_of_elements_in_subset && !index_vector.empty(); i++) { // Index of bytestring will wrap around if it "overflows" past the random bytestring's length. uint64_t index_of_index_vector = random_bytestring_[index_of_random_bytestring_ % random_bytestring_.length()] % - index_vector_.size(); - uint64_t index = index_vector_.at(index_of_index_vector); + index_vector.size(); + uint64_t index = index_vector.at(index_of_index_vector); subset.push_back(index); - index_vector_.erase(index_vector_.begin() + index_of_index_vector); + index_vector.erase(index_vector.begin() + index_of_index_vector); ++index_of_random_bytestring_; } return subset; } - std::vector index_vector_; - - // This bytestring will be iterated through logically representing randomness in order to choose + // This bytestring will be iterated through representing randomness in order to choose // subsets const std::string random_bytestring_; uint32_t index_of_random_bytestring_ = 0; From 11a7f745fa7609382e5ab6df5956c5bbdeb9f1bc Mon Sep 17 00:00:00 2001 From: Zach Date: Thu, 15 Oct 2020 19:06:19 +0000 Subject: [PATCH 30/34] Removed O(N^2) and added health flags Signed-off-by: Zach --- .../upstream/load_balancer_fuzz_base.cc | 21 ++++++++++++++++--- test/fuzz/random.h | 17 ++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 3cf7bd35dccc..00200ca51ee0 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -47,9 +47,12 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( } } - ENVOY_LOG_MISC(trace, "Added these hosts to locality 1: ", absl::StrJoin(localities[0], " ")); - ENVOY_LOG_MISC(trace, "Added these hosts to locality 2: ", absl::StrJoin(localities[1], " ")); - ENVOY_LOG_MISC(trace, "Added these hosts to locality 3: ", absl::StrJoin(localities[2], " ")); + ENVOY_LOG_MISC(trace, "Added these hosts to locality 1: {}", + absl::StrJoin(localities.at(0), " ")); + ENVOY_LOG_MISC(trace, "Added these hosts to locality 2: {}", + absl::StrJoin(localities.at(1), " ")); + ENVOY_LOG_MISC(trace, "Added these hosts to locality 3: {}", + absl::StrJoin(localities.at(2), " ")); host_set.hosts_per_locality_ = makeHostsPerLocality({locality_a, locality_b, locality_c}); } @@ -91,6 +94,7 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // Healthy hosts are first subset for (uint8_t index : subsets.at(0)) { host_set.healthy_hosts_.push_back(host_set.hosts_[index]); + // No health flags for healthy } ENVOY_LOG_MISC(trace, "Hosts made healthy at priority level {}: {}", priority_of_host_set, absl::StrJoin(subsets.at(0), " ")); @@ -98,6 +102,11 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // Degraded hosts are second subset for (uint8_t index : subsets.at(1)) { host_set.degraded_hosts_.push_back(host_set.hosts_[index]); + // Health flags are not currently directly used by most load balancers, but + // they may be added and also are used by other components. + // There are two health flags that map to Host::Health::Degraded, DEGRADED_ACTIVE_HC and + // DEGRADED_EDS_HEALTH. Choose one hardcoded for simpliclity. + host_set.hosts_[index]->healthFlagSet(Host::HealthFlag::DEGRADED_ACTIVE_HC); } ENVOY_LOG_MISC(trace, "Hosts made degraded at priority level {}: {}", priority_of_host_set, absl::StrJoin(subsets.at(1), " ")); @@ -105,7 +114,13 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // Excluded hosts are third subset for (uint8_t index : subsets.at(2)) { host_set.excluded_hosts_.push_back(host_set.hosts_[index]); + // Health flags are not currently directly used by most load balancers, but + // they may be added and also are used by other components. + // There are three health flags that map to Host::Health::Degraded, FAILED_ACTIVE_HC, + // FAILED_OUTLIER_CHECK, and FAILED_EDS_HEALTH. Choose one hardcoded for simpliclity. + host_set.hosts_[index]->healthFlagSet(Host::HealthFlag::FAILED_ACTIVE_HC); } + ENVOY_LOG_MISC(trace, "Hosts made excluded at priority level {}: {}", priority_of_host_set, absl::StrJoin(subsets.at(2), " ")); diff --git a/test/fuzz/random.h b/test/fuzz/random.h index ae9516ada21c..456f8025b4a4 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -1,5 +1,6 @@ #include #include +#include #include #include "envoy/common/random_generator.h" @@ -49,6 +50,7 @@ class ProperSubsetSelector { std::vector> constructSubsets(const std::vector& number_of_elements_in_each_subset, uint32_t number_of_elements) { + num_elements_left_ = number_of_elements; std::vector index_vector; index_vector.reserve(number_of_elements); for (uint32_t i = 0; i < number_of_elements; i++) { @@ -67,16 +69,21 @@ class ProperSubsetSelector { std::vector constructSubset(uint32_t number_of_elements_in_subset, std::vector& index_vector) { std::vector subset; - for (uint32_t i = 0; i < number_of_elements_in_subset && !index_vector.empty(); i++) { + + for (uint32_t i = 0; i < number_of_elements_in_subset && !(num_elements_left_ == 0); i++) { // Index of bytestring will wrap around if it "overflows" past the random bytestring's length. uint64_t index_of_index_vector = random_bytestring_[index_of_random_bytestring_ % random_bytestring_.length()] % - index_vector.size(); + num_elements_left_; uint64_t index = index_vector.at(index_of_index_vector); subset.push_back(index); - index_vector.erase(index_vector.begin() + index_of_index_vector); + // Move the index chosen to the end of the vector - will not be chosen again + std::swap(index_vector[index_of_index_vector], index_vector[num_elements_left_ - 1]); + --num_elements_left_; + ++index_of_random_bytestring_; } + return subset; } @@ -84,6 +91,10 @@ class ProperSubsetSelector { // subsets const std::string random_bytestring_; uint32_t index_of_random_bytestring_ = 0; + + // Used to make subset construction linear time complexity with std::swap - chosen indexes will be + // swapped to end of vector, and won't be chosen again due to modding against this integer + uint32_t num_elements_left_; }; } // namespace Fuzz From 46752371cdd7712b9af01fe27b6883588dc72121 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 16 Oct 2020 18:28:16 +0000 Subject: [PATCH 31/34] Responded to Asra's comments Signed-off-by: Zach --- .../upstream/load_balancer_fuzz_base.cc | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 00200ca51ee0..4431916908ee 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -15,8 +15,8 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( const test::common::upstream::SetupPriorityLevel& setup_priority_level, const uint8_t priority_level) { const uint32_t num_hosts_in_priority_level = setup_priority_level.num_hosts_in_priority_level(); - ENVOY_LOG_MISC(trace, "Will attempt to initialize host set {} with {} hosts.", priority_level, - num_hosts_in_priority_level); + ENVOY_LOG_MISC(trace, "Will attempt to initialize host set at priority level {} with {} hosts.", + priority_level, num_hosts_in_priority_level); MockHostSet& host_set = *priority_set_.getMockHostSet(priority_level); uint32_t hosts_made = 0; // Cap each host set at 256 hosts for efficiency - Leave port clause in for future changes @@ -32,7 +32,7 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( const std::vector> localities = subset_selector.constructSubsets( {setup_priority_level.num_hosts_locality_a(), setup_priority_level.num_hosts_locality_b(), setup_priority_level.num_hosts_locality_c()}, - std::min(num_hosts_in_priority_level, MaxNumHostsPerPriorityLevel)); + host_set.hosts_.size()); HostVector locality_a = {}; HostVector locality_b = {}; @@ -45,15 +45,10 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( locality_indexes[locality].push_back(host_set.hosts_[index]); locality_indexes_[index] = locality; } + ENVOY_LOG_MISC(trace, "Added these hosts to locality {}: {}", locality + 1, + absl::StrJoin(localities.at(locality), " ")); } - ENVOY_LOG_MISC(trace, "Added these hosts to locality 1: {}", - absl::StrJoin(localities.at(0), " ")); - ENVOY_LOG_MISC(trace, "Added these hosts to locality 2: {}", - absl::StrJoin(localities.at(1), " ")); - ENVOY_LOG_MISC(trace, "Added these hosts to locality 3: {}", - absl::StrJoin(localities.at(2), " ")); - host_set.hosts_per_locality_ = makeHostsPerLocality({locality_a, locality_b, locality_c}); } @@ -80,6 +75,14 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio const uint8_t priority_of_host_set = host_priority % num_priority_levels_; ENVOY_LOG_MISC(trace, "Updating health flags for host set at priority: {}", priority_of_host_set); MockHostSet& host_set = *priority_set_.getMockHostSet(priority_of_host_set); + // Remove health flags from hosts with health flags set - previous iterations of this function + // with hosts placed degraded and excluded buckets + for (auto& host : host_set.degraded_hosts_) { + host->healthFlagClear(Host::HealthFlag::DEGRADED_ACTIVE_HC); + } + for (auto& host : host_set.excluded_hosts_) { + host->healthFlagClear(Host::HealthFlag::FAILED_ACTIVE_HC); + } // This downcast will not overflow because size is capped by port numbers const uint32_t host_set_size = host_set.hosts_.size(); host_set.healthy_hosts_.clear(); @@ -131,23 +134,24 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio std::array degraded_hosts_per_locality; std::array excluded_hosts_per_locality; - // Wrap those three in an array here, where the index represents health flag of + // Wrap those three in an array here, where the index represents health status of // healthy/degraded/excluded, used for indexing during iteration through subsets - std::array, 3> locality_health_flags = { + std::array, 3> locality_health_statuses = { healthy_hosts_per_locality, degraded_hosts_per_locality, excluded_hosts_per_locality}; // Iterate through subsets - for (uint8_t health_flag = 0; health_flag < locality_health_flags.size(); health_flag++) { - for (uint8_t index : subsets.at(health_flag)) { // Each subset logically represents a health - // flag - // If the host is in a locality, we have to update the corresponding health flag host vector + for (uint8_t health_status = 0; health_status < locality_health_statuses.size(); + health_status++) { + for (uint8_t index : subsets.at(health_status)) { // Each subset logically represents a health + // status + // If the host is in a locality, we have to update the corresponding health status host vector if (!(locality_indexes_.find(index) == locality_indexes_.end())) { // After computing the host index subsets, we want to propagate these changes to a host set // by building and using these host vectors uint8_t locality = locality_indexes_[index]; - locality_health_flags[health_flag][locality].push_back(host_set.hosts_[index]); - ENVOY_LOG_MISC(trace, "Added host at index {} in locality {} to health flag set {}", index, - locality_indexes_[index], health_flag + 1); + locality_health_statuses[health_status][locality].push_back(host_set.hosts_[index]); + ENVOY_LOG_MISC(trace, "Added host at index {} in locality {} to health status {}", index, + locality_indexes_[index] + 1, health_status + 1); } } } From d07db49985109167ec76a179c5c932accfd58203 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 16 Oct 2020 20:47:28 +0000 Subject: [PATCH 32/34] Spelling Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz_base.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index 4431916908ee..d8327245166a 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -108,7 +108,7 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // Health flags are not currently directly used by most load balancers, but // they may be added and also are used by other components. // There are two health flags that map to Host::Health::Degraded, DEGRADED_ACTIVE_HC and - // DEGRADED_EDS_HEALTH. Choose one hardcoded for simpliclity. + // DEGRADED_EDS_HEALTH. Choose one hardcoded for simplicity. host_set.hosts_[index]->healthFlagSet(Host::HealthFlag::DEGRADED_ACTIVE_HC); } ENVOY_LOG_MISC(trace, "Hosts made degraded at priority level {}: {}", priority_of_host_set, @@ -120,7 +120,7 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // Health flags are not currently directly used by most load balancers, but // they may be added and also are used by other components. // There are three health flags that map to Host::Health::Degraded, FAILED_ACTIVE_HC, - // FAILED_OUTLIER_CHECK, and FAILED_EDS_HEALTH. Choose one hardcoded for simpliclity. + // FAILED_OUTLIER_CHECK, and FAILED_EDS_HEALTH. Choose one hardcoded for simplicity. host_set.hosts_[index]->healthFlagSet(Host::HealthFlag::FAILED_ACTIVE_HC); } From ff8e22fbb65c5f8113fd9fe37a89eab6aaa79902 Mon Sep 17 00:00:00 2001 From: Zach Date: Mon, 19 Oct 2020 22:32:16 +0000 Subject: [PATCH 33/34] Responded to Harvey's comments Signed-off-by: Zach --- .../upstream/load_balancer_fuzz_base.cc | 63 ++++++++++++------- .../common/upstream/load_balancer_fuzz_base.h | 6 +- test/fuzz/BUILD | 9 +++ test/fuzz/random.h | 4 +- test/fuzz/random_test.cc | 24 +++++++ 5 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 test/fuzz/random_test.cc diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index d8327245166a..c0a01f9cd684 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -6,14 +6,17 @@ namespace Envoy { namespace Upstream { namespace { - +// TODO(zasweq): This will be relaxed in the future in order to fully represent the state space +// possible within Load Balancing. In it's current state, it is too slow (particularly due to calls +// to makeTestHost()) to scale up hosts. Once this is made more efficient, this number will be +// increased. constexpr uint32_t MaxNumHostsPerPriorityLevel = 256; } // namespace void LoadBalancerFuzzBase::initializeASingleHostSet( const test::common::upstream::SetupPriorityLevel& setup_priority_level, - const uint8_t priority_level) { + const uint8_t priority_level, uint16_t& port) { const uint32_t num_hosts_in_priority_level = setup_priority_level.num_hosts_in_priority_level(); ENVOY_LOG_MISC(trace, "Will attempt to initialize host set at priority level {} with {} hosts.", priority_level, num_hosts_in_priority_level); @@ -21,9 +24,9 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( uint32_t hosts_made = 0; // Cap each host set at 256 hosts for efficiency - Leave port clause in for future changes while (hosts_made < std::min(num_hosts_in_priority_level, MaxNumHostsPerPriorityLevel) && - port_ < 65535) { - host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port_))); - ++port_; + port < 65535) { + host_set.hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:" + std::to_string(port))); + ++port; ++hosts_made; } @@ -56,10 +59,11 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { random_.initializeSeed(input.seed_for_prng()); + uint16_t port; for (uint8_t priority_of_host_set = 0; priority_of_host_set < input.setup_priority_levels().size(); ++priority_of_host_set) { initializeASingleHostSet(input.setup_priority_levels().at(priority_of_host_set), - priority_of_host_set); + priority_of_host_set, port); } num_priority_levels_ = input.setup_priority_levels().size(); } @@ -89,21 +93,27 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio host_set.degraded_hosts_.clear(); host_set.excluded_hosts_.clear(); + enum HealthStatus { + HEALTHY = 0, + DEGRADED = 1, + EXCLUDED = 2, + }; + Fuzz::ProperSubsetSelector subset_selector(random_bytestring); const std::vector> subsets = subset_selector.constructSubsets( {num_healthy_hosts, num_degraded_hosts, num_excluded_hosts}, host_set_size); // Healthy hosts are first subset - for (uint8_t index : subsets.at(0)) { + for (uint8_t index : subsets.at(HealthStatus::HEALTHY)) { host_set.healthy_hosts_.push_back(host_set.hosts_[index]); // No health flags for healthy } ENVOY_LOG_MISC(trace, "Hosts made healthy at priority level {}: {}", priority_of_host_set, - absl::StrJoin(subsets.at(0), " ")); + absl::StrJoin(subsets.at(HealthStatus::HEALTHY), " ")); // Degraded hosts are second subset - for (uint8_t index : subsets.at(1)) { + for (uint8_t index : subsets.at(HealthStatus::DEGRADED)) { host_set.degraded_hosts_.push_back(host_set.hosts_[index]); // Health flags are not currently directly used by most load balancers, but // they may be added and also are used by other components. @@ -112,10 +122,10 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio host_set.hosts_[index]->healthFlagSet(Host::HealthFlag::DEGRADED_ACTIVE_HC); } ENVOY_LOG_MISC(trace, "Hosts made degraded at priority level {}: {}", priority_of_host_set, - absl::StrJoin(subsets.at(1), " ")); + absl::StrJoin(subsets.at(HealthStatus::DEGRADED), " ")); // Excluded hosts are third subset - for (uint8_t index : subsets.at(2)) { + for (uint8_t index : subsets.at(HealthStatus::EXCLUDED)) { host_set.excluded_hosts_.push_back(host_set.hosts_[index]); // Health flags are not currently directly used by most load balancers, but // they may be added and also are used by other components. @@ -123,11 +133,15 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // FAILED_OUTLIER_CHECK, and FAILED_EDS_HEALTH. Choose one hardcoded for simplicity. host_set.hosts_[index]->healthFlagSet(Host::HealthFlag::FAILED_ACTIVE_HC); } - ENVOY_LOG_MISC(trace, "Hosts made excluded at priority level {}: {}", priority_of_host_set, - absl::StrJoin(subsets.at(2), " ")); + absl::StrJoin(subsets.at(HealthStatus::EXCLUDED), " ")); // Handle updating health flags for hosts_per_locality_ + enum Locality { + A = 0, + B = 1, + C = 2, + }; // The index within the array of the vector represents the locality std::array healthy_hosts_per_locality; @@ -158,16 +172,19 @@ void LoadBalancerFuzzBase::updateHealthFlagsForAHostSet(const uint64_t host_prio // This overrides what is currently present in the host set, thus not having to explicitly call // vector.clear() - host_set.healthy_hosts_per_locality_ = - makeHostsPerLocality({healthy_hosts_per_locality[0], healthy_hosts_per_locality[1], - healthy_hosts_per_locality[2]}); - host_set.degraded_hosts_per_locality_ = - makeHostsPerLocality({degraded_hosts_per_locality[0], degraded_hosts_per_locality[1], - degraded_hosts_per_locality[2]}); - host_set.excluded_hosts_per_locality_ = - makeHostsPerLocality({excluded_hosts_per_locality[0], excluded_hosts_per_locality[1], - excluded_hosts_per_locality[2]}); - + host_set.healthy_hosts_per_locality_ = makeHostsPerLocality( + {healthy_hosts_per_locality[Locality::A], healthy_hosts_per_locality[Locality::B], + healthy_hosts_per_locality[Locality::C]}); + host_set.degraded_hosts_per_locality_ = makeHostsPerLocality( + {degraded_hosts_per_locality[Locality::A], degraded_hosts_per_locality[Locality::B], + degraded_hosts_per_locality[Locality::C]}); + host_set.excluded_hosts_per_locality_ = makeHostsPerLocality( + {excluded_hosts_per_locality[Locality::A], excluded_hosts_per_locality[Locality::B], + excluded_hosts_per_locality[Locality::C]}); + + // These callbacks update load balancing data structures (callbacks are piped into priority set + // in LoadBalancerBase constructor) This won't have any hosts added or removed, as untrusted + // upstreams cannot do that. host_set.runCallbacks({}, {}); } diff --git a/test/common/upstream/load_balancer_fuzz_base.h b/test/common/upstream/load_balancer_fuzz_base.h index 4d7b73472d3b..deeb4c82c216 100644 --- a/test/common/upstream/load_balancer_fuzz_base.h +++ b/test/common/upstream/load_balancer_fuzz_base.h @@ -51,10 +51,10 @@ class LoadBalancerFuzzBase { // over the fuzz iteration. void initializeASingleHostSet(const test::common::upstream::SetupPriorityLevel& setup_priority_level, - const uint8_t priority_level); + const uint8_t priority_level, uint16_t& port); - // There are used to construct the priority set at the beginning of the fuzz iteration - uint16_t port_ = 80; + // This is used to choose a host set to update the flags in an update flags event by modding a + // random uint64 against this number. uint8_t num_priority_levels_ = 0; // This map used when updating health flags - making sure the health flags are updated hosts in diff --git a/test/fuzz/BUILD b/test/fuzz/BUILD index adb238a53f17..153f6f0a94f4 100644 --- a/test/fuzz/BUILD +++ b/test/fuzz/BUILD @@ -1,5 +1,6 @@ load( "//bazel:envoy_build_system.bzl", + "envoy_cc_test", "envoy_cc_test_library", "envoy_package", "envoy_proto_library", @@ -78,3 +79,11 @@ envoy_cc_test_library( "//source/common/common:minimal_logger_lib", ], ) + +envoy_cc_test( + name = "random_test", + srcs = ["random_test.cc"], + deps = [ + "//test/fuzz:random_lib", + ], +) diff --git a/test/fuzz/random.h b/test/fuzz/random.h index 456f8025b4a4..b8ea8cb8a3dc 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -22,7 +22,7 @@ class PsuedoRandomGenerator64 : public RandomGenerator { uint64_t random() override { // Makes sure initializeSeed() was already called ASSERT(prng_ != nullptr); - uint64_t to_return = (*prng_)(); + const uint64_t to_return = (*prng_)(); ENVOY_LOG_MISC(trace, "random() returned: {}", to_return); return to_return; } @@ -75,7 +75,7 @@ class ProperSubsetSelector { uint64_t index_of_index_vector = random_bytestring_[index_of_random_bytestring_ % random_bytestring_.length()] % num_elements_left_; - uint64_t index = index_vector.at(index_of_index_vector); + const uint64_t index = index_vector.at(index_of_index_vector); subset.push_back(index); // Move the index chosen to the end of the vector - will not be chosen again std::swap(index_vector[index_of_index_vector], index_vector[num_elements_left_ - 1]); diff --git a/test/fuzz/random_test.cc b/test/fuzz/random_test.cc new file mode 100644 index 000000000000..59223f33cb19 --- /dev/null +++ b/test/fuzz/random_test.cc @@ -0,0 +1,24 @@ +#include "test/fuzz/random.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Fuzz { + +// Test the subset selection - since selection is based on a passed in random bytestring you can +// work the algorithm yourself Pass in 5 elements, expect first subset to be element 2 and element +// 4, second subset to be elements 1, 2, 3 +TEST(BasicSubsetSelection, RandomTest) { + // \x01 chooses the first element, which gets swapped with last element, 0x3 chooses the third + // index, which gets swapped with last element etc. + std::string random_bytestring = "\x01\x03\x09\x04\x33"; + ProperSubsetSelector subset_selector(random_bytestring); + const std::vector> subsets = subset_selector.constructSubsets({2, 3}, 5); + std::vector subset_one = {1, 3}; + std::vector subset_two = {0, 2, 4}; + ASSERT_EQ(subsets[0], subset_one); + ASSERT_EQ(subsets[1], subset_two); +} + +} // namespace Fuzz +} // namespace Envoy From d71c5d13ba42192400794b479d7ab4ccc3f6ac9a Mon Sep 17 00:00:00 2001 From: Zach Date: Tue, 20 Oct 2020 15:32:47 +0000 Subject: [PATCH 34/34] Responded to comments Signed-off-by: Zach --- test/common/upstream/load_balancer_fuzz_base.cc | 2 +- test/fuzz/random.h | 5 ++++- test/fuzz/random_test.cc | 11 +++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/test/common/upstream/load_balancer_fuzz_base.cc b/test/common/upstream/load_balancer_fuzz_base.cc index c0a01f9cd684..6741f95f7581 100644 --- a/test/common/upstream/load_balancer_fuzz_base.cc +++ b/test/common/upstream/load_balancer_fuzz_base.cc @@ -59,7 +59,7 @@ void LoadBalancerFuzzBase::initializeASingleHostSet( void LoadBalancerFuzzBase::initializeLbComponents( const test::common::upstream::LoadBalancerTestCase& input) { random_.initializeSeed(input.seed_for_prng()); - uint16_t port; + uint16_t port = 80; for (uint8_t priority_of_host_set = 0; priority_of_host_set < input.setup_priority_levels().size(); ++priority_of_host_set) { initializeASingleHostSet(input.setup_priority_levels().at(priority_of_host_set), diff --git a/test/fuzz/random.h b/test/fuzz/random.h index b8ea8cb8a3dc..01b8f5e83df5 100644 --- a/test/fuzz/random.h +++ b/test/fuzz/random.h @@ -44,7 +44,10 @@ class ProperSubsetSelector { * "randomness" of the subset that the class will use is determined by a bytestring passed into * the class. Example: call into function with a vector {3, 5} representing subset sizes, and 15 * as number_of_elements. This function would return something such as {{3, 14, 7}, {2, 1, 13, 8, - * 6}} + * 6}}. If the sum of the number of elements in each elements in each subset > number of elements, + * this will stop constructing subsets once the number of elements has ran out and been already + * placed into subsets. So, if you had a vector {3, 5} representing subset sizes, and 2 as number + * of elements, the function would return something such as {{5, 3}}. */ std::vector> diff --git a/test/fuzz/random_test.cc b/test/fuzz/random_test.cc index 59223f33cb19..9e7fd1012260 100644 --- a/test/fuzz/random_test.cc +++ b/test/fuzz/random_test.cc @@ -1,7 +1,10 @@ #include "test/fuzz/random.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" +using testing::ContainerEq; + namespace Envoy { namespace Fuzz { @@ -14,10 +17,10 @@ TEST(BasicSubsetSelection, RandomTest) { std::string random_bytestring = "\x01\x03\x09\x04\x33"; ProperSubsetSelector subset_selector(random_bytestring); const std::vector> subsets = subset_selector.constructSubsets({2, 3}, 5); - std::vector subset_one = {1, 3}; - std::vector subset_two = {0, 2, 4}; - ASSERT_EQ(subsets[0], subset_one); - ASSERT_EQ(subsets[1], subset_two); + const std::vector expected_subset_one = {1, 3}; + const std::vector expected_subset_two = {0, 2, 4}; + EXPECT_THAT(subsets[0], ContainerEq(expected_subset_one)); + EXPECT_THAT(subsets[1], ContainerEq(expected_subset_two)); } } // namespace Fuzz