Skip to content

Commit

Permalink
support filter format map[string]map[string]bool and change multi lab…
Browse files Browse the repository at this point in the history
…el filter to AND match

Signed-off-by: allen.wang <allen.wq@alipay.com>
  • Loading branch information
wangforthinker committed Apr 28, 2019
1 parent 4ad5f91 commit 6897026
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 17 deletions.
28 changes: 15 additions & 13 deletions daemon/mgr/container_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,23 +108,25 @@ func (fc *filterContext) matchKVFilter(field string, value map[string]string) bo
return false
}

match := false
for k, v := range value {
// filter equal condition
if equalValue, exist := equalKV[k]; exist {
if equalValue == "" || equalValue == v {
match = true
break
}
// filter equal condition
for k, equalValue := range equalKV {
// if not find equal (k, v) pair, return false
if v, exist := value[k]; !exist || (equalValue != "" && equalValue != v) {
return false
}
// filter unequal condition
if unequalValue, exist := unequalKV[k]; exist && unequalValue != v {
match = true
break
}

// filter unequal condition
for k, unequalValue := range unequalKV {
// if key not exist or pair (k, v) found, return false
if v, exist := value[k]; exist && unequalValue != v {
continue
}

return false
}

return match
return true
}

// filter does all select container work.
Expand Down
11 changes: 8 additions & 3 deletions daemon/mgr/container_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,17 @@ func TestMatchKVFilter(t *testing.T) {
{
field: "label",
value: map[string]string{"foo": "a"},
isFilter: false,
},
{
field: "label",
value: map[string]string{"foo": "a", "hello": "word"},
isFilter: true,
},
{
field: "label",
value: map[string]string{"hello": "word"},
isFilter: true,
isFilter: false,
},
} {
assert.Equal(t.isFilter, fc.matchKVFilter(t.field, t.value), fmt.Sprintf("%+v", t.value))
Expand Down Expand Up @@ -165,7 +170,7 @@ func TestMatchKVFilter(t *testing.T) {
},
{
field: "label",
value: map[string]string{"a": "c"},
value: map[string]string{"a": "c", "d": "b"},
isFilter: true,
},
{
Expand All @@ -176,7 +181,7 @@ func TestMatchKVFilter(t *testing.T) {
{
field: "label",
value: map[string]string{"d": "word"},
isFilter: true,
isFilter: false,
},
} {
assert.Equal(t.isFilter, fc.matchKVFilter(t.field, t.value), fmt.Sprintf("%+v", t.value))
Expand Down
23 changes: 22 additions & 1 deletion pkg/utils/filters/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,28 @@ func FromURLParam(param string) (map[string][]string, error) {
var filter map[string][]string
err := json.NewDecoder(strings.NewReader(param)).Decode(&filter)
if err != nil {
return nil, err
// support filters as map[string]map[string]bool
var otherFilters map[string]map[string]bool
err2 := json.NewDecoder(strings.NewReader(param)).Decode(&otherFilters)
if err2 != nil {
return nil, err
}

filter = make(map[string][]string)
for key, innerMap := range otherFilters {
if len(innerMap) == 0 {
continue
}

value := []string{}
for k, v := range innerMap {
if v {
value = append(value, k)
}
}

filter[key] = value
}
}

// params from url may not passed through api, so we need validate here
Expand Down
83 changes: 83 additions & 0 deletions pkg/utils/filters/filter_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package filters

import (
"encoding/json"
"sort"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -98,3 +101,83 @@ func TestValidate(t *testing.T) {
})
}
}

type sortString []string

func (s sortString) Len() int {
return len(s)
}

func (s sortString) Swap(i, j int) {
tmp := s[i]
s[i] = s[j]
s[j] = tmp
}

func (s sortString) Less(i, j int) bool {
return strings.Compare(s[i], s[j]) < 0
}

func TestFromURLParam(t *testing.T) {
f := func(i interface{}) string {
data, _ := json.Marshal(i)
return string(data)
}

tests := []struct {
name string
params string
wantErr bool
expected map[string][]string
}{
{
name: "normal successful case",
params: f(map[string][]string{
"label": {"a=a", "b=b"},
"id": {"id1"},
}),
wantErr: false,
expected: map[string][]string{
"label": {"a=a", "b=b"},
"id": {"id1"},
},
},
{
name: "normal successful case2",
params: f(map[string]map[string]bool{
"label": {"a=a": true, "b=b": true},
"id": {"id1": true},
}),
wantErr: false,
expected: map[string][]string{
"label": {"a=a", "b=b"},
"id": {"id1"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
res, err := FromURLParam(tt.params)
if (err != nil) != tt.wantErr {
t.Errorf("FromURLParam() error = %v, wantErr %v", err, tt.wantErr)
}

for k, v := range tt.expected {
compV, exist := res[k]
if !exist || len(compV) != len(v) {
t.Errorf("FromURLParam() return %v, want %v", res, tt.expected)
}

sort.Sort(sortString(compV))
sort.Sort(sortString(v))

for i := range compV {
if v[i] != compV[i] {
t.Errorf("FromURLParam() return %v, want %v", res, tt.expected)
}
}
}

})
}
}
76 changes: 76 additions & 0 deletions test/api_container_list_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"encoding/json"
"fmt"
"net/url"
"strings"
Expand Down Expand Up @@ -179,3 +180,78 @@ func getContainerListOK(c *check.C, filters string, all bool) (success bool, got

return success, got, errResp
}

// TestListFilterMapMapFormat test label filter format of map[string]map[string]bool
func (suite *APIContainerListSuite) TestListFilterMapMapFormat(c *check.C) {
containerA := "TestListFilterMapMapFormatContainerA"
resA := command.PouchRun("run", "-d", "--name", containerA, "-l", "label="+containerA, busyboxImage125, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, containerA)
containerAID := strings.TrimSpace(resA.Combined())

containerB := "TestListFilterMapMapFormatContainerB"
resB := command.PouchRun("run", "-d", "--name", containerB, "-l", "label="+containerB, busyboxImage125, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, containerB)
containerBID := strings.TrimSpace(resB.Combined())

filterA := map[string]map[string]bool{
"label": {
fmt.Sprintf("label=%s", containerA): true,
},
}

filterB := map[string]map[string]bool{
"label": {
fmt.Sprintf("label!=%s", containerA): true,
},
}

filterAStr, _ := json.Marshal(filterA)
filterBStr, _ := json.Marshal(filterB)

success, got, _ := getContainerListOK(c, string(filterAStr), true)
c.Assert(success, check.Equals, true)
c.Assert(len(got), check.Equals, 1)
c.Assert(got[0].ID, check.Equals, containerAID)

success, got, _ = getContainerListOK(c, string(filterBStr), true)
c.Assert(success, check.Equals, true)
c.Assert(len(got), check.Equals, 1)
c.Assert(got[0].ID, check.Equals, containerBID)
}

// TestListFilterMultiLabel test multi label filter
func (suite *APIContainerListSuite) TestListFilterMultiLabel(c *check.C) {
containerA := "TestListFilterMultiLabelContainerA"
resA := command.PouchRun("run", "-d", "--name", containerA, "-l", "label1="+containerA, "-l", "label2=v1", busyboxImage125, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, containerA)
containerAID := strings.TrimSpace(resA.Combined())

containerB := "TestListFilterMultiLabelContainerB"
resB := command.PouchRun("run", "-d", "--name", containerB, "-l", "label1="+containerB, "-l", "label2=v1", busyboxImage125, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, containerB)
containerBID := strings.TrimSpace(resB.Combined())

filterA := map[string]map[string]bool{
"label": {
fmt.Sprintf("label1=%s", containerA): true,
"label2=v1": true,
},
}

filterB := map[string][]string{
"label": {fmt.Sprintf("label1!=%s", containerA), "label2=v1"},
}

filterAStr, _ := json.Marshal(filterA)
filterBStr, _ := json.Marshal(filterB)

success, got, _ := getContainerListOK(c, string(filterAStr), true)
c.Assert(success, check.Equals, true)
c.Assert(len(got), check.Equals, 1)
c.Assert(got[0].ID, check.Equals, containerAID)

success, got, _ = getContainerListOK(c, string(filterBStr), true)
c.Assert(success, check.Equals, true)
c.Assert(len(got), check.Equals, 1)
c.Assert(got[0].ID, check.Equals, containerBID)
}

0 comments on commit 6897026

Please sign in to comment.