Merge pull request #715 from meirf/value-in-set-selector

structured message for selector; matching functionality
pull/6/head
Daniel Smith 2014-08-01 16:47:47 -07:00
commit e8103e30a1
2 changed files with 100 additions and 0 deletions

View File

@ -20,6 +20,8 @@ import (
"fmt"
"sort"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
// Selector represents a label selector.
@ -105,6 +107,48 @@ func (t andTerm) String() string {
return strings.Join(terms, ",")
}
// Operator represents a key's relationship
// to a set of values in a Requirement.
// TODO: Should also represent key's existence.
type Operator int
const (
IN Operator = iota + 1
NOT_IN
)
// LabelSelector only not named 'Selector' due
// to name conflict until Selector is deprecated.
type LabelSelector struct {
Requirements []Requirement
}
type Requirement struct {
key string
operator Operator
strValues util.StringSet
}
func (r *Requirement) Matches(ls Labels) bool {
switch r.operator {
case IN:
return r.strValues.Has(ls.Get(r.key))
case NOT_IN:
return !r.strValues.Has(ls.Get(r.key))
default:
return false
}
}
func (sg *LabelSelector) Matches(ls Labels) bool {
for _, req := range sg.Requirements {
if !req.Matches(ls) {
return false
}
}
return true
}
func try(selectorPiece, op string) (lhs, rhs string, ok bool) {
pieces := strings.Split(selectorPiece, op)
if len(pieces) == 2 {

View File

@ -18,6 +18,8 @@ package labels
import (
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func TestSelectorParse(t *testing.T) {
@ -163,3 +165,57 @@ func TestSetIsEmpty(t *testing.T) {
t.Errorf("Nested andTerm should not be empty")
}
}
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)
}
}
func expectNoMatchRequirement(t *testing.T, req Requirement, ls Set) {
if req.Matches(ls) {
t.Errorf("Wanted '%+v' to not match '%s', but it did.", req, ls)
}
}
func TestRequirementMatches(t *testing.T) {
s := Set{"x": "foo", "y": "baz"}
a := Requirement{key: "x", operator: IN, strValues: util.NewStringSet("foo")}
b := Requirement{key: "x", operator: NOT_IN, strValues: util.NewStringSet("beta")}
c := Requirement{key: "y", operator: IN, strValues: nil}
d := Requirement{key: "y", strValues: util.NewStringSet("foo")}
expectMatchRequirement(t, a, s)
expectMatchRequirement(t, b, s)
expectNoMatchRequirement(t, c, s)
expectNoMatchRequirement(t, d, s)
}
func expectMatchLabSelector(t *testing.T, lsel LabelSelector, s Set) {
if !lsel.Matches(s) {
t.Errorf("Wanted '%+v' to match '%s', but it did not.\n", lsel, s)
}
}
func expectNoMatchLabSelector(t *testing.T, lsel LabelSelector, s Set) {
if lsel.Matches(s) {
t.Errorf("Wanted '%+v' to not match '%s', but it did.\n", lsel, s)
}
}
func TestLabelSelectorMatches(t *testing.T) {
s := Set{"x": "foo", "y": "baz"}
allMatch := LabelSelector{
Requirements: []Requirement{
{key: "x", operator: IN, strValues: util.NewStringSet("foo")},
{key: "y", operator: NOT_IN, strValues: util.NewStringSet("alpha")},
},
}
singleNonMatch := LabelSelector{
Requirements: []Requirement{
{key: "x", operator: IN, strValues: util.NewStringSet("foo")},
{key: "y", operator: IN, strValues: util.NewStringSet("alpha")},
},
}
expectMatchLabSelector(t, allMatch, s)
expectNoMatchLabSelector(t, singleNonMatch, s)
}