You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by as...@apache.org on 2020/08/28 12:47:13 UTC

[mesos] 05/05: Added basic tests for regexp-based constraints.

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 355b971ead7079e3fabcb46aa0a8b9e31c9fb79e
Author: Andrei Sekretenko <as...@apache.org>
AuthorDate: Mon Aug 17 20:57:43 2020 +0200

    Added basic tests for regexp-based constraints.
    
    Review: https://reviews.apache.org/r/72787
---
 .../master/offer_constraints_filter_tests.cpp      | 186 +++++++++++++++++++++
 1 file changed, 186 insertions(+)

diff --git a/src/tests/master/offer_constraints_filter_tests.cpp b/src/tests/master/offer_constraints_filter_tests.cpp
index db1976c..f80d56c 100644
--- a/src/tests/master/offer_constraints_filter_tests.cpp
+++ b/src/tests/master/offer_constraints_filter_tests.cpp
@@ -263,6 +263,192 @@ TEST(OfferConstraintsFilter, TwoAttributesWithTheSameName)
 }
 
 
+// Tests a single TextMatches constraint on a named attribute.
+TEST(OfferConstraintsFilter, NamedAttributeTextMatches)
+{
+  Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~(
+    {
+      "role_constraints": {
+        "roleA": {
+          "groups": [{
+            "attribute_constraints": [{
+              "selector": {"attribute_name": "bar"},
+              "predicate": {"text_matches": {"regex": "[a-d]+"}}
+            }]
+          }]
+        }
+      }
+    })~");
+
+  ASSERT_SOME(constraints);
+
+  const Try<OfferConstraintsFilter> filter = createFilter(*constraints);
+
+  ASSERT_SOME(filter);
+
+  // Attribute exists, is a text and matches the regex.
+  EXPECT_FALSE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:abcd")));
+
+  // If an attribute is not a text, the constraint is a pass-through.
+  EXPECT_FALSE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:123")));
+
+  EXPECT_FALSE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:[1-17]")));
+
+  // Attribute is a text which does not match.
+  EXPECT_TRUE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:bcde")));
+
+  // Attribute does not exist.
+  EXPECT_TRUE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("foo:abcd")));
+}
+
+
+// Tests a single TextNotMatches constraint on a named attribute.
+TEST(OfferConstraintsFilter, NamedAttributeTextNotMatches)
+{
+  Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~(
+    {
+      "role_constraints": {
+        "roleA": {
+          "groups": [{
+            "attribute_constraints": [{
+              "selector": {"attribute_name": "bar"},
+              "predicate": {"text_not_matches": {"regex": "[a-d]+"}}
+            }]
+          }]
+        }
+      }
+    })~");
+
+  ASSERT_SOME(constraints);
+
+  const Try<OfferConstraintsFilter> filter = createFilter(*constraints);
+
+  ASSERT_SOME(filter);
+
+  // Attribute exists, is a text and matches the regex.
+  EXPECT_TRUE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:abcd")));
+
+  // If an attribute is not a text, the constraint is a pass-through.
+  EXPECT_FALSE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:123")));
+
+  EXPECT_FALSE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:[1-17]")));
+
+  // Attribute is a text which does not match.
+  EXPECT_FALSE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("bar:bcde")));
+
+  // Attribute does not exist.
+  EXPECT_FALSE(
+      filter->isAgentExcluded("roleA", slaveInfoWithAttributes("foo:abcd")));
+}
+
+
+// Tests an invalid TextMatches constraint.
+TEST(OfferConstraintsFilter, InvalidTextMatches)
+{
+  Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~(
+    {
+      "role_constraints": {
+        "roleA": {
+          "groups": [{
+            "attribute_constraints": [{
+              "selector": {"attribute_name": "bar"},
+              "predicate": {"text_matches": {"regex": "[a-d"}}
+            }]
+          }]
+        }
+      }
+    })~");
+
+  ASSERT_SOME(constraints);
+
+  ASSERT_ERROR(createFilter(*constraints));
+}
+
+
+// Tests an invalid TextNotMatches constraint.
+TEST(OfferConstraintsFilter, InvalidTextNotMatches)
+{
+  Try<OfferConstraints> constraints = OfferConstraintsFromJSON(R"~(
+    {
+      "role_constraints": {
+        "roleA": {
+          "groups": [{
+            "attribute_constraints": [{
+              "selector": {"attribute_name": "bar"},
+              "predicate": {"text_not_matches": {"regex": "[a-d"}}
+            }]
+          }]
+        }
+      }
+    })~");
+
+  ASSERT_SOME(constraints);
+
+  ASSERT_ERROR(createFilter(*constraints));
+}
+
+
+// Tests that the constraints cannot specify a regex which will result in a too
+// complex RE2 regex program.
+TEST(OfferConstraintsFilter, RegexTooComplex)
+{
+  auto regexConstraints = [](const string& regex) {
+    return OfferConstraintsFromJSON(
+        R"~(
+      {
+        "role_constraints": {
+          "roleA": {
+            "groups": [{
+              "attribute_constraints": [{
+                "selector": {"attribute_name": "bar"},
+                "predicate": {"text_not_matches": {"regex": ")~" +
+        regex + R"~("}}
+              }]
+            }]
+          }
+        }
+      })~");
+  };
+
+  {
+    Try<OfferConstraints> good = regexConstraints("(a+){10}");
+    ASSERT_SOME(good);
+    ASSERT_SOME(createFilter(*good));
+  }
+
+  {
+    // This regexp can be compiled (fits into a memory limit) but results in
+    // a too large program.
+    Try<OfferConstraints> tooComplex = regexConstraints("(a+){50}");
+    ASSERT_SOME(tooComplex);
+
+    Try<OfferConstraintsFilter> filter = createFilter(*tooComplex);
+    ASSERT_ERROR(filter);
+    ASSERT_TRUE(strings::contains(filter.error(), "too complex"));
+  }
+
+  {
+    // This regexp does not even fit into a memory limit.
+    Try<OfferConstraints> tooLarge = regexConstraints("(a+){500}");
+    ASSERT_SOME(tooLarge);
+
+    Try<OfferConstraintsFilter> filter = createFilter(*tooLarge);
+    ASSERT_ERROR(filter);
+    ASSERT_TRUE(strings::contains(
+        filter.error(), "pattern too large - compile failed"));
+  }
+}
+
+
 // Tests a single group of two constraints.
 TEST(OfferConstraintsFilter, TwoConstraintsInGroup)
 {