This is an automated email from the ASF dual-hosted git repository. asekretenko pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit f0af7082f8bd1586c7f5de9eaa3a8ef83060d632 Author: Andrei Sekretenko <asekrete...@apache.org> AuthorDate: Mon Aug 3 17:16:11 2020 +0200 Added basic tests for the `OfferConstraintsFilter`. Review: https://reviews.apache.org/r/72742 --- src/Makefile.am | 1 + src/tests/CMakeLists.txt | 1 + .../master/offer_constraints_filter_tests.cpp | 265 +++++++++++++++++++++ 3 files changed, 267 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index a91678e..8b95611 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2693,6 +2693,7 @@ mesos_tests_SOURCES = \ tests/master_tests.cpp \ tests/master/mock_master_api_subscriber.cpp \ tests/master/mock_master_api_subscriber.hpp \ + tests/master/offer_constraints_filter_tests.cpp \ tests/master/update_framework_tests.cpp \ tests/master_validation_tests.cpp \ tests/mesos.cpp \ diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index cf579f8..6b420d0 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -111,6 +111,7 @@ set(MESOS_TESTS_SRC master_load_tests.cpp master_maintenance_tests.cpp master_slave_reconciliation_tests.cpp + master/offer_constraints_filter_tests.cpp master/update_framework_tests.cpp metrics_tests.cpp operation_reconciliation_tests.cpp diff --git a/src/tests/master/offer_constraints_filter_tests.cpp b/src/tests/master/offer_constraints_filter_tests.cpp new file mode 100644 index 0000000..f88e201 --- /dev/null +++ b/src/tests/master/offer_constraints_filter_tests.cpp @@ -0,0 +1,265 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <memory> +#include <string> + +#include <gtest/gtest.h> + +#include <stout/gtest.hpp> +#include <stout/json.hpp> +#include <stout/protobuf.hpp> +#include <stout/try.hpp> + +#include <mesos/allocator/allocator.hpp> +#include <mesos/attributes.hpp> + +using std::string; +using std::unique_ptr; + +using ::mesos::Attributes; +using ::mesos::SlaveInfo; + +using ::mesos::allocator::OfferConstraintsFilter; + +using ::mesos::scheduler::OfferConstraints; + + +static Try<OfferConstraints> OfferConstraintsFromJSON(const string& json) +{ + Try<JSON::Object> jsonObject = JSON::parse<JSON::Object>(json); + + if (jsonObject.isError()) { + return Error(jsonObject.error()); + } + + return protobuf::parse<OfferConstraints>(*jsonObject); +} + + +static SlaveInfo slaveInfoWithAttributes(const string& attributes) +{ + SlaveInfo info; + *info.mutable_attributes() = Attributes::parse(attributes); + return info; +} + + +// Tests a single Exists constraint on a named attribute. +TEST(OfferConstraintsFilter, NamedAttributeExists) +{ + Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~( + { + "role_constraints": { + "roleA": { + "groups": [{ + "attribute_constraints": [{ + "selector": {"attribute_name": "bar"}, + "predicate": {"exists": {}} + }] + }] + } + } + })~"); + + ASSERT_SOME(constraints); + + const Try<OfferConstraintsFilter> filter = + OfferConstraintsFilter::create(std::move(*constraints)); + + ASSERT_SOME(filter); + + EXPECT_FALSE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:123"))); + + EXPECT_TRUE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("foo:123"))); + + EXPECT_FALSE(filter->isAgentExcluded( + "roleA", slaveInfoWithAttributes("foo:123;bar:456"))); +} + + +// Tests a single NotExists constraint on a named attribute. +TEST(OfferConstraintsFilter, NamedAttributeNotExists) +{ + Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~( + { + "role_constraints": { + "roleA": { + "groups": [{ + "attribute_constraints": [{ + "selector": {"attribute_name": "bar"}, + "predicate": {"not_exists": {}} + }] + }] + } + } + })~"); + + ASSERT_SOME(constraints); + + const Try<OfferConstraintsFilter> filter = + OfferConstraintsFilter::create(std::move(*constraints)); + + ASSERT_SOME(filter); + + EXPECT_TRUE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:123"))); + + EXPECT_FALSE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("foo:123"))); + + EXPECT_TRUE(filter->isAgentExcluded( + "roleA", slaveInfoWithAttributes("foo:123;bar:456"))); +} + + +// Tests a single group of two constraints. +TEST(OfferConstraintsFilter, TwoConstraintsInGroup) +{ + Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~( + { + "role_constraints": { + "roleA": { + "groups": [{ + "attribute_constraints": [ + { + "selector": {"attribute_name": "foo"}, + "predicate": {"exists": {}} + }, + { + "selector": {"attribute_name": "bar"}, + "predicate": {"not_exists": {}} + } + ] + }] + } + } + })~"); + + ASSERT_SOME(constraints); + + const Try<OfferConstraintsFilter> filter = + OfferConstraintsFilter::create(std::move(*constraints)); + + ASSERT_SOME(filter); + + EXPECT_TRUE(filter->isAgentExcluded("roleA", slaveInfoWithAttributes(""))); + + EXPECT_FALSE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("foo:123"))); + + EXPECT_TRUE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:456"))); + + EXPECT_TRUE(filter->isAgentExcluded( + "roleA", slaveInfoWithAttributes("bar:123;foo:456"))); + + EXPECT_FALSE(filter->isAgentExcluded( + "roleA", slaveInfoWithAttributes("baz:123;foo:456"))); +} + + +// Tests a constraint expression consisting of two groups. +TEST(OfferConstraintsFilter, TwoGroups) +{ + Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~( + { + "role_constraints": { + "roleA": { + "groups": [ + { + "attribute_constraints": [{ + "selector": {"attribute_name": "foo"}, + "predicate": {"exists": {}} + }] + }, + { + "attribute_constraints": [{ + "selector": {"attribute_name": "bar"}, + "predicate": {"not_exists": {}} + }] + } + ] + } + } + })~"); + + ASSERT_SOME(constraints); + + const Try<OfferConstraintsFilter> filter = + OfferConstraintsFilter::create(std::move(*constraints)); + + ASSERT_SOME(filter); + + EXPECT_FALSE(filter->isAgentExcluded("roleA", slaveInfoWithAttributes(""))); + + EXPECT_FALSE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("baz:123"))); + + EXPECT_TRUE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:123"))); + + EXPECT_FALSE(filter->isAgentExcluded( + "roleA", slaveInfoWithAttributes("bar:123;foo:456"))); +} + + +// Tests offer constraints for two roles. +TEST(OfferConstraintsFilter, TwoRoles) +{ + Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~( + { + "role_constraints": { + "roleA": { + "groups": [{ + "attribute_constraints": [{ + "selector": {"attribute_name": "foo"}, + "predicate": {"exists": {}} + }] + }] + }, + "roleB": { + "groups": [{ + "attribute_constraints": [{ + "selector": {"attribute_name": "bar"}, + "predicate": {"exists": {}} + }] + }] + } + } + })~"); + + ASSERT_SOME(constraints); + + const Try<OfferConstraintsFilter> filter = + OfferConstraintsFilter::create(std::move(*constraints)); + + ASSERT_SOME(filter); + + EXPECT_TRUE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:123"))); + + EXPECT_FALSE( + filter->isAgentExcluded("roleA", slaveInfoWithAttributes("foo:123"))); + + EXPECT_FALSE( + filter->isAgentExcluded("roleB", slaveInfoWithAttributes("bar:123"))); + + EXPECT_TRUE( + filter->isAgentExcluded("roleB", slaveInfoWithAttributes("foo:123"))); +}