2017-04-17 10:50:02 +00:00
|
|
|
package kv
|
2015-11-13 10:50:32 +00:00
|
|
|
|
|
|
|
import (
|
2016-12-30 08:21:13 +00:00
|
|
|
"reflect"
|
|
|
|
"sort"
|
2015-11-13 10:50:32 +00:00
|
|
|
"testing"
|
2016-03-04 22:52:08 +00:00
|
|
|
"time"
|
2015-11-13 10:50:32 +00:00
|
|
|
|
2016-12-30 08:21:13 +00:00
|
|
|
"github.com/containous/traefik/types"
|
2015-11-13 10:50:32 +00:00
|
|
|
"github.com/docker/libkv/store"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestKvList(t *testing.T) {
|
|
|
|
cases := []struct {
|
2017-04-17 10:50:02 +00:00
|
|
|
provider *Provider
|
2015-11-13 10:50:32 +00:00
|
|
|
keys []string
|
|
|
|
expected []string
|
|
|
|
}{
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{},
|
2015-11-13 10:50:32 +00:00
|
|
|
},
|
|
|
|
keys: []string{},
|
|
|
|
expected: []string{},
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{},
|
2015-11-13 10:50:32 +00:00
|
|
|
},
|
|
|
|
keys: []string{"traefik"},
|
|
|
|
expected: []string{},
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2015-11-13 10:50:32 +00:00
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "foo",
|
|
|
|
Value: []byte("bar"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
keys: []string{"bar"},
|
|
|
|
expected: []string{},
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2015-11-13 10:50:32 +00:00
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "foo",
|
|
|
|
Value: []byte("bar"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
keys: []string{"foo"},
|
|
|
|
expected: []string{"foo"},
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2015-11-13 10:50:32 +00:00
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "foo/baz/1",
|
|
|
|
Value: []byte("bar"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "foo/baz/2",
|
|
|
|
Value: []byte("bar"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "foo/baz/biz/1",
|
|
|
|
Value: []byte("bar"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
keys: []string{"foo", "/baz/"},
|
2016-04-19 17:23:08 +00:00
|
|
|
expected: []string{"foo/baz/1", "foo/baz/2"},
|
2015-11-13 10:50:32 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
actual := c.provider.list(c.keys...)
|
|
|
|
sort.Strings(actual)
|
|
|
|
sort.Strings(c.expected)
|
|
|
|
if !reflect.DeepEqual(actual, c.expected) {
|
|
|
|
t.Fatalf("expected %v, got %v for %v and %v", c.expected, actual, c.keys, c.provider)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error case
|
2017-04-17 10:50:02 +00:00
|
|
|
provider := &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2017-03-11 23:22:39 +00:00
|
|
|
Error: KvError{
|
|
|
|
List: store.ErrKeyNotFound,
|
|
|
|
},
|
2015-11-13 10:50:32 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
actual := provider.list("anything")
|
|
|
|
if actual != nil {
|
|
|
|
t.Fatalf("Should have return nil, got %v", actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestKvGet(t *testing.T) {
|
|
|
|
cases := []struct {
|
2017-04-17 10:50:02 +00:00
|
|
|
provider *Provider
|
2015-11-13 10:50:32 +00:00
|
|
|
keys []string
|
|
|
|
expected string
|
|
|
|
}{
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{},
|
2015-11-13 10:50:32 +00:00
|
|
|
},
|
|
|
|
keys: []string{},
|
|
|
|
expected: "",
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{},
|
2015-11-13 10:50:32 +00:00
|
|
|
},
|
|
|
|
keys: []string{"traefik"},
|
|
|
|
expected: "",
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2015-11-13 10:50:32 +00:00
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "foo",
|
|
|
|
Value: []byte("bar"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
keys: []string{"bar"},
|
|
|
|
expected: "",
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2015-11-13 10:50:32 +00:00
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "foo",
|
|
|
|
Value: []byte("bar"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
keys: []string{"foo"},
|
|
|
|
expected: "bar",
|
|
|
|
},
|
|
|
|
{
|
2017-04-17 10:50:02 +00:00
|
|
|
provider: &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2015-11-13 10:50:32 +00:00
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "foo/baz/1",
|
|
|
|
Value: []byte("bar1"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "foo/baz/2",
|
|
|
|
Value: []byte("bar2"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "foo/baz/biz/1",
|
|
|
|
Value: []byte("bar3"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
keys: []string{"foo", "/baz/", "2"},
|
|
|
|
expected: "bar2",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
2016-02-01 10:07:05 +00:00
|
|
|
actual := c.provider.get("", c.keys...)
|
2015-11-13 10:50:32 +00:00
|
|
|
if actual != c.expected {
|
|
|
|
t.Fatalf("expected %v, got %v for %v and %v", c.expected, actual, c.keys, c.provider)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error case
|
2017-04-17 10:50:02 +00:00
|
|
|
provider := &Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2017-03-11 23:22:39 +00:00
|
|
|
Error: KvError{
|
|
|
|
Get: store.ErrKeyNotFound,
|
|
|
|
},
|
2015-11-13 10:50:32 +00:00
|
|
|
},
|
|
|
|
}
|
2016-02-01 10:07:05 +00:00
|
|
|
actual := provider.get("", "anything")
|
2015-11-13 10:50:32 +00:00
|
|
|
if actual != "" {
|
|
|
|
t.Fatalf("Should have return nil, got %v", actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestKvLast(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
key string
|
|
|
|
expected string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
key: "",
|
|
|
|
expected: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: "foo",
|
|
|
|
expected: "foo",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: "foo/bar",
|
|
|
|
expected: "bar",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: "foo/bar/baz",
|
|
|
|
expected: "baz",
|
|
|
|
},
|
|
|
|
// FIXME is this wanted ?
|
|
|
|
{
|
|
|
|
key: "foo/bar/",
|
|
|
|
expected: "",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-04-17 10:50:02 +00:00
|
|
|
provider := &Provider{}
|
2015-11-13 10:50:32 +00:00
|
|
|
for _, c := range cases {
|
|
|
|
actual := provider.last(c.key)
|
|
|
|
if actual != c.expected {
|
|
|
|
t.Fatalf("expected %s, got %s", c.expected, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-04 22:52:08 +00:00
|
|
|
func TestKvWatchTree(t *testing.T) {
|
|
|
|
returnedChans := make(chan chan []*store.KVPair)
|
|
|
|
provider := &KvMock{
|
2017-04-17 10:50:02 +00:00
|
|
|
Provider{
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2016-03-04 22:52:08 +00:00
|
|
|
WatchTreeMethod: func() <-chan []*store.KVPair {
|
|
|
|
c := make(chan []*store.KVPair, 10)
|
|
|
|
returnedChans <- c
|
|
|
|
return c
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
configChan := make(chan types.ConfigMessage)
|
2016-04-19 17:23:08 +00:00
|
|
|
go func() {
|
2016-04-13 18:36:23 +00:00
|
|
|
provider.watchKv(configChan, "prefix", make(chan bool, 1))
|
2016-04-19 17:23:08 +00:00
|
|
|
}()
|
2016-03-04 22:52:08 +00:00
|
|
|
|
|
|
|
select {
|
|
|
|
case c1 := <-returnedChans:
|
|
|
|
c1 <- []*store.KVPair{}
|
|
|
|
<-configChan
|
|
|
|
close(c1) // WatchTree chans can close due to error
|
|
|
|
case <-time.After(1 * time.Second):
|
2016-03-05 20:43:44 +00:00
|
|
|
t.Fatalf("Failed to create a new WatchTree chan")
|
2016-03-04 22:52:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case c2 := <-returnedChans:
|
|
|
|
c2 <- []*store.KVPair{}
|
|
|
|
<-configChan
|
|
|
|
case <-time.After(1 * time.Second):
|
2016-03-05 20:43:44 +00:00
|
|
|
t.Fatalf("Failed to create a new WatchTree chan")
|
2016-03-04 22:52:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
2017-08-18 00:18:02 +00:00
|
|
|
case <-configChan:
|
2016-03-04 22:52:08 +00:00
|
|
|
t.Fatalf("configChan should be empty")
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-19 17:23:08 +00:00
|
|
|
func TestKVLoadConfig(t *testing.T) {
|
2017-04-17 10:50:02 +00:00
|
|
|
provider := &Provider{
|
2016-04-19 17:23:08 +00:00
|
|
|
Prefix: "traefik",
|
2017-05-11 17:09:06 +00:00
|
|
|
kvclient: &Mock{
|
2016-04-19 17:23:08 +00:00
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "traefik/frontends/frontend.with.dot",
|
|
|
|
Value: []byte(""),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/frontends/frontend.with.dot/backend",
|
|
|
|
Value: []byte("backend.with.dot.too"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/frontends/frontend.with.dot/routes",
|
|
|
|
Value: []byte(""),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/frontends/frontend.with.dot/routes/route.with.dot",
|
|
|
|
Value: []byte(""),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/frontends/frontend.with.dot/routes/route.with.dot/rule",
|
|
|
|
Value: []byte("Host:test.localhost"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/backends/backend.with.dot.too",
|
|
|
|
Value: []byte(""),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/backends/backend.with.dot.too/servers",
|
|
|
|
Value: []byte(""),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot",
|
|
|
|
Value: []byte(""),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot/url",
|
|
|
|
Value: []byte("http://172.17.0.2:80"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot/weight",
|
2016-11-23 13:49:55 +00:00
|
|
|
Value: []byte("0"),
|
2016-04-19 17:23:08 +00:00
|
|
|
},
|
2017-03-07 14:56:35 +00:00
|
|
|
{
|
|
|
|
Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot.without.url",
|
|
|
|
Value: []byte(""),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot.without.url/weight",
|
|
|
|
Value: []byte("0"),
|
|
|
|
},
|
2016-04-19 17:23:08 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
actual := provider.loadConfig()
|
|
|
|
expected := &types.Configuration{
|
|
|
|
Backends: map[string]*types.Backend{
|
|
|
|
"backend.with.dot.too": {
|
|
|
|
Servers: map[string]types.Server{
|
|
|
|
"server.with.dot": {
|
|
|
|
URL: "http://172.17.0.2:80",
|
2016-11-23 13:49:55 +00:00
|
|
|
Weight: 0,
|
2016-04-19 17:23:08 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
CircuitBreaker: nil,
|
|
|
|
LoadBalancer: nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Frontends: map[string]*types.Frontend{
|
|
|
|
"frontend.with.dot": {
|
|
|
|
Backend: "backend.with.dot.too",
|
2016-05-10 11:43:24 +00:00
|
|
|
PassHostHeader: true,
|
2016-04-19 17:23:08 +00:00
|
|
|
EntryPoints: []string{},
|
|
|
|
Routes: map[string]types.Route{
|
|
|
|
"route.with.dot": {
|
|
|
|
Rule: "Host:test.localhost",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(actual.Backends, expected.Backends) {
|
|
|
|
t.Fatalf("expected %+v, got %+v", expected.Backends, actual.Backends)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(actual.Frontends, expected.Frontends) {
|
|
|
|
t.Fatalf("expected %+v, got %+v", expected.Frontends, actual.Frontends)
|
|
|
|
}
|
|
|
|
}
|
2017-10-12 15:50:03 +00:00
|
|
|
|
|
|
|
func TestKVHasStickinessLabel(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
KVPairs []*store.KVPair
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "without option",
|
|
|
|
expected: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "with cookie name without stickiness=true",
|
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/stickiness/cookiename",
|
|
|
|
Value: []byte("foo"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "stickiness=true",
|
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/stickiness",
|
|
|
|
Value: []byte("true"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "stickiness=true and sticky=true",
|
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/stickiness",
|
|
|
|
Value: []byte("true"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/sticky",
|
|
|
|
Value: []byte("true"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "stickiness=false and sticky=true",
|
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/stickiness",
|
|
|
|
Value: []byte("false"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/sticky",
|
|
|
|
Value: []byte("true"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "stickiness=true and sticky=false",
|
|
|
|
KVPairs: []*store.KVPair{
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/stickiness",
|
|
|
|
Value: []byte("true"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "loadbalancer/sticky",
|
|
|
|
Value: []byte("false"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
p := &Provider{
|
|
|
|
kvclient: &Mock{
|
|
|
|
KVPairs: test.KVPairs,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
actual := p.hasStickinessLabel("")
|
|
|
|
|
|
|
|
if actual != test.expected {
|
|
|
|
t.Fatalf("expected %v, got %v", test.expected, actual)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|