traefik/pkg/server/server_test.go

269 lines
7.8 KiB
Go
Raw Normal View History

package server
import (
"context"
"net/http"
2017-07-10 10:11:44 +00:00
"net/http/httptest"
"testing"
"time"
2019-08-03 01:58:23 +00:00
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/config/static"
th "github.com/containous/traefik/v2/pkg/testhelpers"
"github.com/containous/traefik/v2/pkg/types"
"github.com/stretchr/testify/assert"
)
2017-11-17 09:26:03 +00:00
func TestListenProvidersSkipsEmptyConfigs(t *testing.T) {
server, stop, invokeStopChan := setupListenProvider(10 * time.Millisecond)
defer invokeStopChan()
go func() {
for {
select {
case <-stop:
return
case <-server.configurationValidatedChan:
t.Error("An empty configuration was published but it should not")
}
}
}()
server.configurationChan <- dynamic.Message{ProviderName: "kubernetes"}
2017-11-17 09:26:03 +00:00
// give some time so that the configuration can be processed
time.Sleep(100 * time.Millisecond)
}
func TestListenProvidersSkipsSameConfigurationForProvider(t *testing.T) {
server, stop, invokeStopChan := setupListenProvider(10 * time.Millisecond)
defer invokeStopChan()
publishedConfigCount := 0
go func() {
for {
select {
case <-stop:
return
2018-11-14 09:18:03 +00:00
case conf := <-server.configurationValidatedChan:
2017-11-17 09:26:03 +00:00
// set the current configuration
// this is usually done in the processing part of the published configuration
2018-08-06 18:00:03 +00:00
// so we have to emulate the behavior here
currentConfigurations := server.currentConfigurations.Get().(dynamic.Configurations)
2018-11-14 09:18:03 +00:00
currentConfigurations[conf.ProviderName] = conf.Configuration
2017-11-17 09:26:03 +00:00
server.currentConfigurations.Set(currentConfigurations)
publishedConfigCount++
if publishedConfigCount > 1 {
t.Error("Same configuration should not be published multiple times")
}
}
}
}()
conf := &dynamic.Configuration{}
conf.HTTP = th.BuildConfiguration(
2018-11-14 09:18:03 +00:00
th.WithRouters(th.WithRouter("foo")),
th.WithLoadBalancerServices(th.WithService("bar")),
2017-11-17 09:26:03 +00:00
)
// provide a configuration
server.configurationChan <- dynamic.Message{ProviderName: "kubernetes", Configuration: conf}
2017-11-17 09:26:03 +00:00
// give some time so that the configuration can be processed
time.Sleep(20 * time.Millisecond)
// provide the same configuration a second time
server.configurationChan <- dynamic.Message{ProviderName: "kubernetes", Configuration: conf}
2017-11-17 09:26:03 +00:00
// give some time so that the configuration can be processed
time.Sleep(100 * time.Millisecond)
}
func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
server, stop, invokeStopChan := setupListenProvider(10 * time.Millisecond)
defer invokeStopChan()
publishedProviderConfigCount := map[string]int{}
publishedConfigCount := 0
consumePublishedConfigsDone := make(chan bool)
go func() {
for {
select {
case <-stop:
return
case newConfig := <-server.configurationValidatedChan:
publishedProviderConfigCount[newConfig.ProviderName]++
publishedConfigCount++
if publishedConfigCount == 2 {
consumePublishedConfigsDone <- true
return
}
}
}
}()
conf := &dynamic.Configuration{}
conf.HTTP = th.BuildConfiguration(
2018-11-14 09:18:03 +00:00
th.WithRouters(th.WithRouter("foo")),
th.WithLoadBalancerServices(th.WithService("bar")),
2017-11-17 09:26:03 +00:00
)
server.configurationChan <- dynamic.Message{ProviderName: "kubernetes", Configuration: conf}
server.configurationChan <- dynamic.Message{ProviderName: "marathon", Configuration: conf}
2017-11-17 09:26:03 +00:00
select {
case <-consumePublishedConfigsDone:
if val := publishedProviderConfigCount["kubernetes"]; val != 1 {
t.Errorf("Got %d configuration publication(s) for provider %q, want 1", val, "kubernetes")
}
if val := publishedProviderConfigCount["marathon"]; val != 1 {
t.Errorf("Got %d configuration publication(s) for provider %q, want 1", val, "marathon")
}
case <-time.After(100 * time.Millisecond):
t.Errorf("Published configurations were not consumed in time")
}
}
// setupListenProvider configures the Server and starts listenProviders
func setupListenProvider(throttleDuration time.Duration) (server *Server, stop chan bool, invokeStopChan func()) {
stop = make(chan bool)
invokeStopChan = func() {
stop <- true
}
staticConfiguration := static.Configuration{
Providers: &static.Providers{
ProvidersThrottleDuration: types.Duration(throttleDuration),
2017-11-17 09:26:03 +00:00
},
}
server = NewServer(staticConfiguration, nil, nil, nil)
2017-11-17 09:26:03 +00:00
go server.listenProviders(stop)
return server, stop, invokeStopChan
}
2017-07-10 10:11:44 +00:00
func TestServerResponseEmptyBackend(t *testing.T) {
const requestPath = "/path"
const routeRule = "Path(`" + requestPath + "`)"
2017-07-10 10:11:44 +00:00
testCases := []struct {
desc string
config func(testServerURL string) *dynamic.HTTPConfiguration
expectedStatusCode int
2017-07-10 10:11:44 +00:00
}{
{
desc: "Ok",
config: func(testServerURL string) *dynamic.HTTPConfiguration {
2018-06-05 10:32:03 +00:00
return th.BuildConfiguration(
2018-11-14 09:18:03 +00:00
th.WithRouters(th.WithRouter("foo",
2018-06-05 10:32:03 +00:00
th.WithEntryPoints("http"),
2018-11-14 09:18:03 +00:00
th.WithServiceName("bar"),
th.WithRule(routeRule)),
2018-06-05 10:32:03 +00:00
),
2018-11-14 09:18:03 +00:00
th.WithLoadBalancerServices(th.WithService("bar",
th.WithServers(th.WithServer(testServerURL))),
2018-06-05 10:32:03 +00:00
),
2017-07-10 10:11:44 +00:00
)
},
expectedStatusCode: http.StatusOK,
2017-07-10 10:11:44 +00:00
},
{
desc: "No Frontend",
config: func(testServerURL string) *dynamic.HTTPConfiguration {
2018-06-05 10:32:03 +00:00
return th.BuildConfiguration()
2017-07-10 10:11:44 +00:00
},
expectedStatusCode: http.StatusNotFound,
2017-07-10 10:11:44 +00:00
},
{
2019-06-05 20:18:06 +00:00
desc: "Empty Backend LB",
config: func(testServerURL string) *dynamic.HTTPConfiguration {
2018-06-05 10:32:03 +00:00
return th.BuildConfiguration(
2018-11-14 09:18:03 +00:00
th.WithRouters(th.WithRouter("foo",
2018-06-05 10:32:03 +00:00
th.WithEntryPoints("http"),
2018-11-14 09:18:03 +00:00
th.WithServiceName("bar"),
th.WithRule(routeRule)),
2018-06-05 10:32:03 +00:00
),
2019-06-05 20:18:06 +00:00
th.WithLoadBalancerServices(th.WithService("bar")),
2017-07-10 10:11:44 +00:00
)
},
expectedStatusCode: http.StatusServiceUnavailable,
2017-07-10 10:11:44 +00:00
},
{
2019-06-05 20:18:06 +00:00
desc: "Empty Backend LB Sticky",
config: func(testServerURL string) *dynamic.HTTPConfiguration {
2018-06-05 10:32:03 +00:00
return th.BuildConfiguration(
2018-11-14 09:18:03 +00:00
th.WithRouters(th.WithRouter("foo",
2018-06-05 10:32:03 +00:00
th.WithEntryPoints("http"),
2018-11-14 09:18:03 +00:00
th.WithServiceName("bar"),
th.WithRule(routeRule)),
2018-06-05 10:32:03 +00:00
),
2018-11-14 09:18:03 +00:00
th.WithLoadBalancerServices(th.WithService("bar",
th.WithSticky("test")),
2018-06-05 10:32:03 +00:00
),
2017-07-10 10:11:44 +00:00
)
},
expectedStatusCode: http.StatusServiceUnavailable,
2017-07-10 10:11:44 +00:00
},
{
2019-06-05 20:18:06 +00:00
desc: "Empty Backend LB",
config: func(testServerURL string) *dynamic.HTTPConfiguration {
2018-06-05 10:32:03 +00:00
return th.BuildConfiguration(
2018-11-14 09:18:03 +00:00
th.WithRouters(th.WithRouter("foo",
2018-06-05 10:32:03 +00:00
th.WithEntryPoints("http"),
2018-11-14 09:18:03 +00:00
th.WithServiceName("bar"),
th.WithRule(routeRule)),
2018-06-05 10:32:03 +00:00
),
2019-06-05 20:18:06 +00:00
th.WithLoadBalancerServices(th.WithService("bar")),
2017-07-10 10:11:44 +00:00
)
},
expectedStatusCode: http.StatusServiceUnavailable,
2017-07-10 10:11:44 +00:00
},
{
2019-06-05 20:18:06 +00:00
desc: "Empty Backend LB Sticky",
config: func(testServerURL string) *dynamic.HTTPConfiguration {
2018-06-05 10:32:03 +00:00
return th.BuildConfiguration(
2018-11-14 09:18:03 +00:00
th.WithRouters(th.WithRouter("foo",
2018-06-05 10:32:03 +00:00
th.WithEntryPoints("http"),
2018-11-14 09:18:03 +00:00
th.WithServiceName("bar"),
th.WithRule(routeRule)),
2018-06-05 10:32:03 +00:00
),
2018-11-14 09:18:03 +00:00
th.WithLoadBalancerServices(th.WithService("bar",
th.WithSticky("test")),
2018-06-05 10:32:03 +00:00
),
2017-07-10 10:11:44 +00:00
)
},
expectedStatusCode: http.StatusServiceUnavailable,
2017-07-10 10:11:44 +00:00
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
}))
defer testServer.Close()
globalConfig := static.Configuration{}
entryPointsConfig := TCPEntryPoints{
"http": &TCPEntryPoint{},
2017-07-10 10:11:44 +00:00
}
srv := NewServer(globalConfig, nil, entryPointsConfig, nil)
rtConf := runtime.NewConfig(dynamic.Configuration{HTTP: test.config(testServer.URL)})
entryPoints, _ := srv.createHTTPHandlers(context.Background(), rtConf, []string{"http"})
2017-07-10 10:11:44 +00:00
responseRecorder := &httptest.ResponseRecorder{}
request := httptest.NewRequest(http.MethodGet, testServer.URL+requestPath, nil)
2018-11-14 09:18:03 +00:00
entryPoints["http"].ServeHTTP(responseRecorder, request)
2017-07-10 10:11:44 +00:00
assert.Equal(t, test.expectedStatusCode, responseRecorder.Result().StatusCode, "status code")
2017-07-10 10:11:44 +00:00
})
}
}