From ae698bcff807af85720e3ba602700626e6122de0 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Thu, 14 Aug 2014 15:49:03 -0400 Subject: [PATCH] Allow field/label users to get info from fields Allows a consumer to get at the information stored in the field selector for querying an underlying data store. Not generic, but offers a simple start. --- pkg/labels/selector.go | 31 ++++++++++++++++++++++++++++++- pkg/labels/selector_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/pkg/labels/selector.go b/pkg/labels/selector.go index c35da49ac3a..79e7cac1a00 100644 --- a/pkg/labels/selector.go +++ b/pkg/labels/selector.go @@ -32,6 +32,12 @@ type Selector interface { // Empty returns true if this selector does not restrict the selection space. Empty() bool + // RequiresExactMatch allows a caller to introspect whether a given selector + // requires a single specific label to be set, and if so returns the value it + // requires. + // TODO: expand this to be more general + RequiresExactMatch(label string) (value string, found bool) + // String returns a human readable string that represents this selector. String() string } @@ -53,6 +59,13 @@ func (t *hasTerm) Empty() bool { return false } +func (t *hasTerm) RequiresExactMatch(label string) (value string, found bool) { + if t.label == label { + return t.value, true + } + return "", false +} + func (t *hasTerm) String() string { return fmt.Sprintf("%v=%v", t.label, t.value) } @@ -69,6 +82,10 @@ func (t *notHasTerm) Empty() bool { return false } +func (t *notHasTerm) RequiresExactMatch(label string) (value string, found bool) { + return "", false +} + func (t *notHasTerm) String() string { return fmt.Sprintf("%v!=%v", t.label, t.value) } @@ -99,6 +116,18 @@ func (t andTerm) Empty() bool { return true } +func (t andTerm) RequiresExactMatch(label string) (string, bool) { + if t == nil || len([]Selector(t)) == 0 { + return "", false + } + for i := range t { + if value, found := t[i].RequiresExactMatch(label); found { + return value, found + } + } + return "", false +} + func (t andTerm) String() string { var terms []string for _, q := range t { @@ -173,7 +202,7 @@ func SelectorFromSet(ls Set) Selector { return andTerm(items) } -// ParseSelector takes a string repsenting a selector and returns an +// ParseSelector takes a string representing a selector and returns an // object suitable for matching, or an error. func ParseSelector(selector string) (Selector, error) { parts := strings.Split(selector, ",") diff --git a/pkg/labels/selector_test.go b/pkg/labels/selector_test.go index 5539d71ea84..c151e400bf2 100644 --- a/pkg/labels/selector_test.go +++ b/pkg/labels/selector_test.go @@ -158,6 +158,9 @@ func TestSetIsEmpty(t *testing.T) { if (&hasTerm{}).Empty() { t.Errorf("hasTerm should not be empty") } + if (¬HasTerm{}).Empty() { + t.Errorf("notHasTerm should not be empty") + } if !(andTerm{andTerm{}}).Empty() { t.Errorf("Nested andTerm should be empty") } @@ -166,6 +169,36 @@ func TestSetIsEmpty(t *testing.T) { } } +func TestRequiresExactMatch(t *testing.T) { + testCases := map[string]struct { + S Selector + Label string + Value string + Found bool + }{ + "empty set": {Set{}.AsSelector(), "test", "", false}, + "nil andTerm": {andTerm(nil), "test", "", false}, + "empty hasTerm": {&hasTerm{}, "test", "", false}, + "skipped hasTerm": {&hasTerm{"a", "b"}, "test", "", false}, + "valid hasTerm": {&hasTerm{"test", "b"}, "test", "b", true}, + "valid hasTerm no value": {&hasTerm{"test", ""}, "test", "", true}, + "valid notHasTerm": {¬HasTerm{"test", "b"}, "test", "", false}, + "valid notHasTerm no value": {¬HasTerm{"test", ""}, "test", "", false}, + "nested andTerm": {andTerm{andTerm{}}, "test", "", false}, + "nested andTerm matches": {andTerm{&hasTerm{"test", "b"}}, "test", "b", true}, + "andTerm with non-match": {andTerm{&hasTerm{}, &hasTerm{"test", "b"}}, "test", "b", true}, + } + for k, v := range testCases { + value, found := v.S.RequiresExactMatch(v.Label) + if value != v.Value { + t.Errorf("%s: expected value %s, got %s", k, v.Value, value) + } + if found != v.Found { + t.Errorf("%s: expected found %s, got %s", k, v.Found, found) + } + } +} + func expectMatchRequirement(t *testing.T, req Requirement, ls Set) { if !req.Matches(ls) { t.Errorf("Wanted '%+v' to match '%s', but it did not.\n", req, ls)