test(constraint): unit tests + integration tests + make validate
This commit is contained in:
parent
cd2100ed84
commit
f46accc74d
7 changed files with 362 additions and 40 deletions
|
@ -7,6 +7,7 @@ import (
|
|||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/ty/fun"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/containous/traefik/safe"
|
||||
|
@ -88,28 +89,22 @@ func (provider *ConsulCatalog) healthyNodes(service string) (catalogUpdate, erro
|
|||
return catalogUpdate{}, err
|
||||
}
|
||||
|
||||
set := map[string]bool{}
|
||||
tags := []string{}
|
||||
nodes := []*api.ServiceEntry{}
|
||||
for _, node := range data {
|
||||
nodes := fun.Filter(func(node *api.ServiceEntry) bool {
|
||||
constraintTags := provider.getContraintTags(node.Service.Tags)
|
||||
if ok, failingConstraint, err := provider.MatchConstraints(constraintTags); err != nil {
|
||||
return catalogUpdate{}, err
|
||||
} else if ok == true {
|
||||
nodes = append(nodes, node)
|
||||
// merge tags of every nodes in a single slice
|
||||
// only if node match constraint
|
||||
for _, tag := range node.Service.Tags {
|
||||
if _, ok := set[tag]; ok == false {
|
||||
set[tag] = true
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
}
|
||||
} else if ok == false && failingConstraint != nil {
|
||||
ok, failingConstraint := provider.MatchConstraints(constraintTags)
|
||||
if ok == false && failingConstraint != nil {
|
||||
log.Debugf("Service %v pruned by '%v' constraint", service, failingConstraint.String())
|
||||
}
|
||||
return ok
|
||||
}, data).([]*api.ServiceEntry)
|
||||
|
||||
}
|
||||
//Merge tags of nodes matching constraints, in a single slice.
|
||||
tags := fun.Foldl(func(node *api.ServiceEntry, set []string) []string {
|
||||
return fun.Keys(fun.Union(
|
||||
fun.Set(set),
|
||||
fun.Set(node.Service.Tags),
|
||||
).(map[string]bool)).([]string)
|
||||
}, []string{}, nodes).([]string)
|
||||
|
||||
return catalogUpdate{
|
||||
Service: &serviceUpdate{
|
||||
|
|
|
@ -29,22 +29,21 @@ type BaseProvider struct {
|
|||
|
||||
// MatchConstraints must match with EVERY single contraint
|
||||
// returns first constraint that do not match or nil
|
||||
// returns errors for future use (regex)
|
||||
func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint, error) {
|
||||
func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint) {
|
||||
// if there is no tags and no contraints, filtering is disabled
|
||||
if len(tags) == 0 && len(p.Constraints) == 0 {
|
||||
return true, nil, nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
for _, constraint := range p.Constraints {
|
||||
if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); xor(ok == true, constraint.MustMatch == true) {
|
||||
return false, constraint, nil
|
||||
// xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint
|
||||
if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch {
|
||||
return false, constraint
|
||||
}
|
||||
}
|
||||
|
||||
// If no constraint or every constraints matching
|
||||
return true, nil, nil
|
||||
>>>>>>> e844462... feat(constraints): Implementation of constraints (cmd + toml + matching functions), implementation proposal with consul
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *BaseProvider) getConfiguration(defaultTemplateFile string, funcMap template.FuncMap, templateObjects interface{}) (*types.Configuration, error) {
|
||||
|
@ -98,8 +97,3 @@ func normalize(name string) string {
|
|||
// get function
|
||||
return strings.Join(strings.FieldsFunc(name, fargs), "-")
|
||||
}
|
||||
|
||||
// golang does not support ^ operator
|
||||
func xor(cond1 bool, cond2 bool) bool {
|
||||
return cond1 != cond2
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"github.com/containous/traefik/types"
|
||||
)
|
||||
|
||||
type myProvider struct {
|
||||
|
@ -206,3 +208,100 @@ func TestGetConfigurationReturnsCorrectMaxConnConfiguration(t *testing.T) {
|
|||
t.Fatalf("Configuration did not parse MaxConn.ExtractorFunc properly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchingConstraints(t *testing.T) {
|
||||
cases := []struct {
|
||||
constraints []*types.Constraint
|
||||
tags []string
|
||||
expected bool
|
||||
}{
|
||||
// simple test: must match
|
||||
{
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Regex: "us-east-1",
|
||||
},
|
||||
},
|
||||
tags: []string{
|
||||
"us-east-1",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
// simple test: must match but does not match
|
||||
{
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Regex: "us-east-1",
|
||||
},
|
||||
},
|
||||
tags: []string{
|
||||
"us-east-2",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
// simple test: must not match
|
||||
{
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: false,
|
||||
Regex: "us-east-1",
|
||||
},
|
||||
},
|
||||
tags: []string{
|
||||
"us-east-1",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
// complex test: globbing
|
||||
{
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Regex: "us-east-*",
|
||||
},
|
||||
},
|
||||
tags: []string{
|
||||
"us-east-1",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
// complex test: multiple constraints
|
||||
{
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Regex: "us-east-*",
|
||||
},
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: false,
|
||||
Regex: "api",
|
||||
},
|
||||
},
|
||||
tags: []string{
|
||||
"api",
|
||||
"us-east-1",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
provider := myProvider{
|
||||
BaseProvider{
|
||||
Constraints: c.constraints,
|
||||
},
|
||||
}
|
||||
actual, _ := provider.MatchConstraints(c.tags)
|
||||
if actual != c.expected {
|
||||
t.Fatalf("test #%v: expected %q, got %q, for %q", i, c.expected, actual, c.constraints)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue