traefik/provider/label/label_test.go
2018-03-23 13:30:03 +01:00

1227 lines
25 KiB
Go

package label
import (
"testing"
"time"
"github.com/containous/flaeg"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
)
func TestSplitAndTrimString(t *testing.T) {
testCases := []struct {
desc string
input string
expected []string
}{
{
desc: "empty string",
input: "",
expected: nil,
}, {
desc: "one piece",
input: "foo",
expected: []string{"foo"},
}, {
desc: "two pieces",
input: "foo,bar",
expected: []string{"foo", "bar"},
}, {
desc: "three pieces",
input: "foo,bar,zoo",
expected: []string{"foo", "bar", "zoo"},
}, {
desc: "two pieces with whitespace",
input: " foo , bar ",
expected: []string{"foo", "bar"},
}, {
desc: "consecutive commas",
input: " foo ,, bar ",
expected: []string{"foo", "bar"},
}, {
desc: "consecutive commas with whitespace",
input: " foo , , bar ",
expected: []string{"foo", "bar"},
}, {
desc: "leading and trailing commas",
input: ",, foo , , bar,, , ",
expected: []string{"foo", "bar"},
}, {
desc: "no valid pieces",
input: ", , , ,, ,",
expected: nil,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := SplitAndTrimString(test.input, ",")
assert.Equal(t, test.expected, actual)
})
}
}
func TestGetStringValue(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelName string
defaultValue string
expected string
}{
{
desc: "empty labels map",
labelName: "foo",
defaultValue: "default",
expected: "default",
},
{
desc: "existing label",
labels: map[string]string{
"foo": "bar",
},
labelName: "foo",
defaultValue: "default",
expected: "bar",
},
{
desc: "non existing label",
labels: map[string]string{
"foo": "bar",
},
labelName: "fii",
defaultValue: "default",
expected: "default",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetStringValue(test.labels, test.labelName, test.defaultValue)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetStringValueP(t *testing.T) {
testCases := []struct {
desc string
labels *map[string]string
labelName string
defaultValue string
expected string
}{
{
desc: "nil labels map",
labels: nil,
labelName: "foo",
defaultValue: "default",
expected: "default",
},
{
desc: "existing label",
labels: &map[string]string{
"foo": "bar",
},
labelName: "foo",
defaultValue: "default",
expected: "bar",
},
{
desc: "non existing label",
labels: &map[string]string{
"foo": "bar",
},
labelName: "fii",
defaultValue: "default",
expected: "default",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetStringValueP(test.labels, test.labelName, test.defaultValue)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetBoolValue(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelName string
defaultValue bool
expected bool
}{
{
desc: "empty map",
labelName: "foo",
},
{
desc: "invalid boolean value",
labels: map[string]string{
"foo": "bar",
},
labelName: "foo",
defaultValue: true,
expected: true,
},
{
desc: "valid boolean value: true",
labels: map[string]string{
"foo": "true",
},
labelName: "foo",
defaultValue: false,
expected: true,
},
{
desc: "valid boolean value: false",
labels: map[string]string{
"foo": "false",
},
labelName: "foo",
defaultValue: true,
expected: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetBoolValue(test.labels, test.labelName, test.defaultValue)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetIntValue(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelName string
defaultValue int
expected int
}{
{
desc: "empty map",
labelName: "foo",
},
{
desc: "invalid int value",
labelName: "foo",
labels: map[string]string{
"foo": "bar",
},
defaultValue: 666,
expected: 666,
},
{
desc: "negative int value",
labelName: "foo",
labels: map[string]string{
"foo": "-1",
},
defaultValue: 666,
expected: -1,
},
{
desc: "positive int value",
labelName: "foo",
labels: map[string]string{
"foo": "1",
},
defaultValue: 666,
expected: 1,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetIntValue(test.labels, test.labelName, test.defaultValue)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetIntValueP(t *testing.T) {
testCases := []struct {
desc string
labels *map[string]string
labelName string
defaultValue int
expected int
}{
{
desc: "nil map",
labels: nil,
labelName: "foo",
defaultValue: 666,
expected: 666,
},
{
desc: "invalid int value",
labelName: "foo",
labels: &map[string]string{
"foo": "bar",
},
defaultValue: 666,
expected: 666,
},
{
desc: "negative int value",
labelName: "foo",
labels: &map[string]string{
"foo": "-1",
},
defaultValue: 666,
expected: -1,
},
{
desc: "positive int value",
labelName: "foo",
labels: &map[string]string{
"foo": "1",
},
defaultValue: 666,
expected: 1,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetIntValueP(test.labels, test.labelName, test.defaultValue)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetInt64Value(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelName string
defaultValue int64
expected int64
}{
{
desc: "empty map",
labelName: "foo",
},
{
desc: "invalid int value",
labelName: "foo",
labels: map[string]string{
"foo": "bar",
},
defaultValue: 666,
expected: 666,
},
{
desc: "negative int value",
labelName: "foo",
labels: map[string]string{
"foo": "-1",
},
defaultValue: 666,
expected: -1,
},
{
desc: "positive int value",
labelName: "foo",
labels: map[string]string{
"foo": "1",
},
defaultValue: 666,
expected: 1,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetInt64Value(test.labels, test.labelName, test.defaultValue)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetInt64ValueP(t *testing.T) {
testCases := []struct {
desc string
labels *map[string]string
labelName string
defaultValue int64
expected int64
}{
{
desc: "nil map",
labels: nil,
labelName: "foo",
defaultValue: 666,
expected: 666,
},
{
desc: "invalid int value",
labelName: "foo",
labels: &map[string]string{
"foo": "bar",
},
defaultValue: 666,
expected: 666,
},
{
desc: "negative int value",
labelName: "foo",
labels: &map[string]string{
"foo": "-1",
},
defaultValue: 666,
expected: -1,
},
{
desc: "positive int value",
labelName: "foo",
labels: &map[string]string{
"foo": "1",
},
defaultValue: 666,
expected: 1,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetInt64ValueP(test.labels, test.labelName, test.defaultValue)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetSliceStringValue(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelName string
expected []string
}{
{
desc: "empty map",
labelName: "foo",
},
{
desc: "empty value",
labels: map[string]string{
"foo": "",
},
labelName: "foo",
expected: nil,
},
{
desc: "one value, not split",
labels: map[string]string{
"foo": "bar",
},
labelName: "foo",
expected: []string{"bar"},
},
{
desc: "several values",
labels: map[string]string{
"foo": "bar,bir ,bur",
},
labelName: "foo",
expected: []string{"bar", "bir", "bur"},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetSliceStringValue(test.labels, test.labelName)
assert.EqualValues(t, test.expected, got)
})
}
}
func TestGetSliceStringValueP(t *testing.T) {
testCases := []struct {
desc string
labels *map[string]string
labelName string
expected []string
}{
{
desc: "nil map",
labels: nil,
labelName: "foo",
expected: nil,
},
{
desc: "one value, not split",
labels: &map[string]string{
"foo": "bar",
},
labelName: "foo",
expected: []string{"bar"},
},
{
desc: "several values",
labels: &map[string]string{
"foo": "bar,bir ,bur",
},
labelName: "foo",
expected: []string{"bar", "bir", "bur"},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetSliceStringValueP(test.labels, test.labelName)
assert.EqualValues(t, test.expected, got)
})
}
}
func TestGetMapValue(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelName string
expected map[string]string
}{
{
desc: "empty map",
labelName: "foo",
},
{
desc: "existent label with empty entry",
labelName: "foo",
labels: map[string]string{
"foo": "",
},
expected: nil,
},
{
desc: "existent label with invalid entry",
labelName: "foo",
labels: map[string]string{
"foo": "bar",
},
expected: nil,
},
{
desc: "existent label with empty value",
labelName: "foo",
labels: map[string]string{
"foo": "bar:",
},
expected: map[string]string{
"Bar": "",
},
},
{
desc: "one entry",
labelName: "foo",
labels: map[string]string{
"foo": " Access-Control-Allow-Methods:POST,GET,OPTIONS ",
},
expected: map[string]string{
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
},
},
{
desc: "several entry",
labelName: "foo",
labels: map[string]string{
"foo": "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
},
expected: map[string]string{
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
"Content-Type": "application/json; charset=utf-8",
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetMapValue(test.labels, test.labelName)
assert.EqualValues(t, test.expected, got)
})
}
}
func TestGetStringMultipleStrict(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelNames []string
expected map[string]string
expectedErr bool
}{
{
desc: "empty labels names and empty labels map",
labels: map[string]string{},
expected: map[string]string{},
},
{
desc: "empty labels names",
labels: map[string]string{
"foo": "bar",
"fii": "bir",
},
expected: map[string]string{},
},
{
desc: "one label missing",
labels: map[string]string{
"foo": "bar",
"fii": "bir",
"fyy": "byr",
},
labelNames: []string{"foo", "fii", "fuu"},
expected: nil,
expectedErr: true,
},
{
desc: "all labels are present",
labels: map[string]string{
"foo": "bar",
"fii": "bir",
"fyy": "byr",
},
labelNames: []string{"foo", "fii"},
expected: map[string]string{
"foo": "bar",
"fii": "bir",
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got, err := GetStringMultipleStrict(test.labels, test.labelNames...)
if (err != nil) != test.expectedErr {
t.Errorf("error = %v, wantErr %v", err, test.expectedErr)
return
}
assert.EqualValues(t, test.expected, got)
})
}
}
func TestHas(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
labelName string
expected bool
}{
{
desc: "nil labels map",
labelName: "foo",
},
{
desc: "nonexistent label",
labels: map[string]string{
"foo": "bar",
},
labelName: "fii",
expected: false,
},
{
desc: "existent label",
labels: map[string]string{
"foo": "bar",
},
labelName: "foo",
expected: true,
},
{
desc: "existent label with empty value",
labels: map[string]string{
"foo": "",
},
labelName: "foo",
expected: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := Has(test.labels, test.labelName)
assert.Equal(t, test.expected, got)
})
}
}
func TestHasP(t *testing.T) {
testCases := []struct {
desc string
labels *map[string]string
labelName string
expected bool
}{
{
desc: "nil labels map",
labelName: "foo",
},
{
desc: "nonexistent label",
labels: &map[string]string{
"foo": "bar",
},
labelName: "fii",
expected: false,
},
{
desc: "existent label",
labels: &map[string]string{
"foo": "bar",
},
labelName: "foo",
expected: true,
},
{
desc: "existent label with empty value",
labels: &map[string]string{
"foo": "",
},
labelName: "foo",
expected: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := HasP(test.labels, test.labelName)
assert.Equal(t, test.expected, got)
})
}
}
func TestExtractServiceProperties(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
expected SegmentProperties
}{
{
desc: "empty labels map",
expected: SegmentProperties{},
},
{
desc: "valid label names",
labels: map[string]string{
"traefik.foo.port": "bar",
"traefik.foo.frontend.bar": "1bar",
"traefik.foo.backend": "3bar",
},
expected: SegmentProperties{
"foo": SegmentPropertyValues{
"port": "bar",
"frontend.bar": "1bar",
"backend": "3bar",
},
},
},
{
desc: "invalid label names",
labels: map[string]string{
"foo.frontend.bar": "1bar",
"traefik.foo.frontend.": "2bar",
"traefik.foo.port.bar": "barbar",
"traefik.foo.frontend": "0bar",
"traefik.frontend.foo.backend": "0bar",
},
expected: SegmentProperties{},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := ExtractServiceProperties(test.labels)
assert.EqualValues(t, test.expected, got)
})
}
}
func TestExtractServicePropertiesP(t *testing.T) {
testCases := []struct {
desc string
labels *map[string]string
expected SegmentProperties
}{
{
desc: "nil labels map",
expected: SegmentProperties{},
},
{
desc: "valid label names",
labels: &map[string]string{
"traefik.foo.port": "bar",
"traefik.foo.frontend.bar": "1bar",
"traefik.foo.backend": "3bar",
},
expected: SegmentProperties{
"foo": SegmentPropertyValues{
"port": "bar",
"frontend.bar": "1bar",
"backend": "3bar",
},
},
},
{
desc: "invalid label names",
labels: &map[string]string{
"foo.frontend.bar": "1bar",
"traefik.foo.frontend.": "2bar",
"traefik.foo.port.bar": "barbar",
"traefik.foo.frontend": "0bar",
"traefik.frontend.foo.backend": "0bar",
},
expected: SegmentProperties{},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := ExtractServicePropertiesP(test.labels)
assert.EqualValues(t, test.expected, got)
})
}
}
func TestIsEnabled(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
exposedByDefault bool
expected bool
}{
{
desc: "empty labels map & exposedByDefault true",
exposedByDefault: true,
expected: true,
},
{
desc: "empty labels map & exposedByDefault false",
exposedByDefault: false,
expected: false,
},
{
desc: "exposedByDefault false and label enable true",
labels: map[string]string{
TraefikEnable: "true",
},
exposedByDefault: false,
expected: true,
},
{
desc: "exposedByDefault false and label enable false",
labels: map[string]string{
TraefikEnable: "false",
},
exposedByDefault: false,
expected: false,
},
{
desc: "exposedByDefault true and label enable false",
labels: map[string]string{
TraefikEnable: "false",
},
exposedByDefault: true,
expected: false,
},
{
desc: "exposedByDefault true and label enable true",
labels: map[string]string{
TraefikEnable: "true",
},
exposedByDefault: true,
expected: true,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := IsEnabled(test.labels, test.exposedByDefault)
assert.Equal(t, test.expected, got)
})
}
}
func TestIsEnabledP(t *testing.T) {
testCases := []struct {
desc string
labels *map[string]string
exposedByDefault bool
expected bool
}{
{
desc: "nil labels map & exposedByDefault true",
exposedByDefault: true,
expected: true,
},
{
desc: "nil labels map & exposedByDefault false",
exposedByDefault: false,
expected: false,
},
{
desc: "exposedByDefault false and label enable true",
labels: &map[string]string{
TraefikEnable: "true",
},
exposedByDefault: false,
expected: true,
},
{
desc: "exposedByDefault false and label enable false",
labels: &map[string]string{
TraefikEnable: "false",
},
exposedByDefault: false,
expected: false,
},
{
desc: "exposedByDefault true and label enable false",
labels: &map[string]string{
TraefikEnable: "false",
},
exposedByDefault: true,
expected: false,
},
{
desc: "exposedByDefault true and label enable true",
labels: &map[string]string{
TraefikEnable: "true",
},
exposedByDefault: true,
expected: true,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := IsEnabledP(test.labels, test.exposedByDefault)
assert.Equal(t, test.expected, got)
})
}
}
func TestGetServiceLabel(t *testing.T) {
testCases := []struct {
desc string
labelName string
serviceName string
expected string
}{
{
desc: "without service name",
labelName: TraefikPort,
expected: TraefikPort,
},
{
desc: "with service name",
labelName: TraefikPort,
serviceName: "bar",
expected: "traefik.bar.port",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := GetServiceLabel(test.labelName, test.serviceName)
assert.Equal(t, test.expected, got)
})
}
}
func TestHasPrefix(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
prefix string
expected bool
}{
{
desc: "nil labels map",
prefix: "foo",
expected: false,
},
{
desc: "nonexistent prefix",
labels: map[string]string{
"foo.carotte": "bar",
},
prefix: "fii",
expected: false,
},
{
desc: "existent prefix",
labels: map[string]string{
"foo.carotte": "bar",
},
prefix: "foo",
expected: true,
},
{
desc: "existent prefix with empty value",
labels: map[string]string{
"foo.carotte": "",
},
prefix: "foo",
expected: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := HasPrefix(test.labels, test.prefix)
assert.Equal(t, test.expected, got)
})
}
}
func TestParseErrorPages(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
expected map[string]*types.ErrorPage
}{
{
desc: "2 errors pages",
labels: map[string]string{
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageBackend: "foo_backend",
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageQuery: "foo_query",
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageStatus: "500,600",
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageBackend: "bar_backend",
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageQuery: "bar_query",
},
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
Query: "foo_query",
Backend: "foo_backend",
},
"bar": {
Status: []string{"500", "600"},
Query: "bar_query",
Backend: "bar_backend",
},
},
},
{
desc: "only status field",
labels: map[string]string{
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
},
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
},
},
},
{
desc: "invalid field",
labels: map[string]string{
Prefix + BaseFrontendErrorPage + "foo." + "courgette": "404",
},
expected: map[string]*types.ErrorPage{"foo": {}},
},
{
desc: "no error pages labels",
labels: map[string]string{},
expected: nil,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
pages := ParseErrorPages(test.labels, Prefix+BaseFrontendErrorPage, RegexpFrontendErrorPage)
assert.EqualValues(t, test.expected, pages)
})
}
}
func TestParseRateSets(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
expected map[string]*types.Rate
}{
{
desc: "2 rate limits",
labels: map[string]string{
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitPeriod: "6",
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitAverage: "12",
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitBurst: "18",
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitPeriod: "3",
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitAverage: "6",
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitBurst: "9",
},
expected: map[string]*types.Rate{
"foo": {
Period: flaeg.Duration(6 * time.Second),
Average: 12,
Burst: 18,
},
"bar": {
Period: flaeg.Duration(3 * time.Second),
Average: 6,
Burst: 9,
},
},
},
{
desc: "no rate limits labels",
labels: map[string]string{},
expected: nil,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
rateSets := ParseRateSets(test.labels, Prefix+BaseFrontendRateLimit, RegexpFrontendRateLimit)
assert.EqualValues(t, test.expected, rateSets)
})
}
}
func TestExtractTraefikLabels(t *testing.T) {
testCases := []struct {
desc string
prefix string
originLabels map[string]string
expected SegmentProperties
}{
{
desc: "nil labels map",
prefix: "traefik",
originLabels: nil,
expected: SegmentProperties{"": {}},
},
{
desc: "container labels",
prefix: "traefik",
originLabels: map[string]string{
"frontend.priority": "foo", // missing prefix: skip
"traefik.port": "bar",
},
expected: SegmentProperties{
"": {
"traefik.port": "bar",
},
},
},
{
desc: "segment labels: only segment no default",
prefix: "traefik",
originLabels: map[string]string{
"traefik.goo.frontend.priority": "A",
"traefik.goo.port": "D",
"traefik.port": "C",
},
expected: SegmentProperties{
"goo": {
"traefik.frontend.priority": "A",
"traefik.port": "D",
},
},
},
{
desc: "segment labels: use default",
prefix: "traefik",
originLabels: map[string]string{
"traefik.guu.frontend.priority": "B",
"traefik.port": "C",
},
expected: SegmentProperties{
"guu": {
"traefik.frontend.priority": "B",
"traefik.port": "C",
},
},
},
{
desc: "segment labels: several segments",
prefix: "traefik",
originLabels: map[string]string{
"traefik.goo.frontend.priority": "A",
"traefik.goo.port": "D",
"traefik.guu.frontend.priority": "B",
"traefik.port": "C",
},
expected: SegmentProperties{
"goo": {
"traefik.frontend.priority": "A",
"traefik.port": "D",
},
"guu": {
"traefik.frontend.priority": "B",
"traefik.port": "C",
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := ExtractTraefikLabels(test.originLabels)
assert.Equal(t, test.expected, actual)
})
}
}