mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-14 11:57:51 +00:00
source/custom: implement 'GtLt' operator
A new operator for checking that an input (integer) is between two values.
This commit is contained in:
parent
8b4314bbbb
commit
689703be48
2 changed files with 56 additions and 2 deletions
|
@ -46,8 +46,8 @@ type MatchExpression struct {
|
|||
// Value is the list of values that the operand evaluates the input
|
||||
// against. Value should be empty if the operator is Exists, DoesNotExist,
|
||||
// IsTrue or IsFalse. Value should contain exactly one element if the
|
||||
// operator is Gt or Lt. In other cases Value should contain at least one
|
||||
// element.
|
||||
// operator is Gt or Lt and exactly two elements if the operator is GtLt.
|
||||
// In other cases Value should contain at least one element.
|
||||
Value MatchValue `json:",omitempty"`
|
||||
|
||||
// valueRe caches compiled regexps for "InRegexp" operator
|
||||
|
@ -89,6 +89,11 @@ const (
|
|||
// Both the input and value must be integer numbers, otherwise an error is
|
||||
// returned.
|
||||
MatchLt MatchOp = "Lt"
|
||||
// MatchGtLt returns true if the input is between two values, i.e. greater
|
||||
// than the first value and less than the second value of the expression
|
||||
// (number of values in the expression must be exactly two). Both the input
|
||||
// and values must be integer numbers, otherwise an error is returned.
|
||||
MatchGtLt MatchOp = "GtLt"
|
||||
// MatchIsTrue returns true if the input holds the value "true". The
|
||||
// expression must not have any values.
|
||||
MatchIsTrue MatchOp = "IsTrue"
|
||||
|
@ -106,6 +111,7 @@ var matchOps = map[MatchOp]struct{}{
|
|||
MatchDoesNotExist: struct{}{},
|
||||
MatchGt: struct{}{},
|
||||
MatchLt: struct{}{},
|
||||
MatchGtLt: struct{}{},
|
||||
MatchIsTrue: struct{}{},
|
||||
MatchIsFalse: struct{}{},
|
||||
}
|
||||
|
@ -154,6 +160,20 @@ func (m *MatchExpression) Validate() error {
|
|||
if _, err := strconv.Atoi(m.Value[0]); err != nil {
|
||||
return fmt.Errorf("Value must be an integer for Op %q (have %v)", m.Op, m.Value[0])
|
||||
}
|
||||
case MatchGtLt:
|
||||
if len(m.Value) != 2 {
|
||||
return fmt.Errorf("Value must contain exactly two elements for Op %q (have %v)", m.Op, m.Value)
|
||||
}
|
||||
var err error
|
||||
v := make([]int, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
if v[i], err = strconv.Atoi(m.Value[i]); err != nil {
|
||||
return fmt.Errorf("Value must contain integers for Op %q (have %v)", m.Op, m.Value)
|
||||
}
|
||||
}
|
||||
if v[0] >= v[1] {
|
||||
return fmt.Errorf("Value[0] must be less than Value[1] for Op %q (have %v)", m.Op, m.Value)
|
||||
}
|
||||
case MatchInRegexp:
|
||||
if len(m.Value) == 0 {
|
||||
return fmt.Errorf("Value must be non-empty for Op %q", m.Op)
|
||||
|
@ -223,6 +243,19 @@ func (m *MatchExpression) Match(valid bool, value interface{}) (bool, error) {
|
|||
if (l < r && m.Op == MatchLt) || (l > r && m.Op == MatchGt) {
|
||||
return true, nil
|
||||
}
|
||||
case MatchGtLt:
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("not a number %q", value)
|
||||
}
|
||||
lr := make([]int, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
lr[i], err = strconv.Atoi(m.Value[i])
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("not a number %q in %v", m.Value[i], m)
|
||||
}
|
||||
}
|
||||
return v > lr[0] && v < lr[1], nil
|
||||
case MatchIsTrue:
|
||||
return value == "true", nil
|
||||
case MatchIsFalse:
|
||||
|
|
|
@ -73,6 +73,13 @@ func TestCreateMatchExpression(t *testing.T) {
|
|||
{op: e.MatchLt, values: V{"1", "2", "3"}, err: assert.NotNilf},
|
||||
{op: e.MatchLt, values: V{"a"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchGtLt, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1"}, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "2"}, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"2", "1"}, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "2", "3"}, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"a", "2"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIsTrue, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
|
@ -134,6 +141,12 @@ func TestMatch(t *testing.T) {
|
|||
{op: e.MatchLt, values: V{"2"}, input: "1", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, input: "1.0", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "1", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "1", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "10", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "2", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "1.0", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIsTrue, input: true, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, input: true, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, input: false, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
|
@ -155,6 +168,7 @@ func TestMatch(t *testing.T) {
|
|||
|
||||
{op: e.MatchGt, values: V{"3.0"}, input: 1, valid: true},
|
||||
{op: e.MatchLt, values: V{"0x2"}, input: 1, valid: true},
|
||||
{op: e.MatchGtLt, values: V{"1", "str"}, input: 1, valid: true},
|
||||
{op: "non-existent-op", values: V{"1"}, input: 1, valid: true},
|
||||
}
|
||||
|
||||
|
@ -196,6 +210,7 @@ func TestMatchKeys(t *testing.T) {
|
|||
{op: e.MatchInRegexp, values: V{"foo"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchGt, values: V{"1"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchLt, values: V{"1"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchIsTrue, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchIsFalse, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
@ -252,6 +267,12 @@ func TestMatchValues(t *testing.T) {
|
|||
{op: e.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIsTrue, name: "foo", result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, name: "foo", input: I{"foo": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, name: "foo", input: I{"foo": "true"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
|
Loading…
Reference in a new issue