2020-07-15 14:56:03 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2024-10-29 14:30:38 +00:00
|
|
|
"strings"
|
2020-07-15 14:56:03 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2020-08-17 16:04:03 +00:00
|
|
|
ptypes "github.com/traefik/paerser/types"
|
2023-02-03 14:24:05 +00:00
|
|
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/safe"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/tls"
|
2020-07-15 14:56:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestProvider_Init(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
desc string
|
|
|
|
endpoint string
|
2020-08-17 16:04:03 +00:00
|
|
|
pollInterval ptypes.Duration
|
2020-07-15 14:56:03 +00:00
|
|
|
expErr bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "should return an error if no endpoint is configured",
|
|
|
|
expErr: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "should return an error if pollInterval is equal to 0",
|
|
|
|
endpoint: "http://localhost:8080",
|
|
|
|
expErr: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "should not return an error",
|
|
|
|
endpoint: "http://localhost:8080",
|
2020-08-17 16:04:03 +00:00
|
|
|
pollInterval: ptypes.Duration(time.Second),
|
2020-07-15 14:56:03 +00:00
|
|
|
expErr: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
provider := &Provider{
|
|
|
|
Endpoint: test.endpoint,
|
|
|
|
PollInterval: test.pollInterval,
|
|
|
|
}
|
|
|
|
|
|
|
|
err := provider.Init()
|
|
|
|
if test.expErr {
|
|
|
|
require.Error(t, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvider_SetDefaults(t *testing.T) {
|
|
|
|
provider := &Provider{}
|
|
|
|
|
|
|
|
provider.SetDefaults()
|
|
|
|
|
2020-08-17 16:04:03 +00:00
|
|
|
assert.Equal(t, provider.PollInterval, ptypes.Duration(5*time.Second))
|
|
|
|
assert.Equal(t, provider.PollTimeout, ptypes.Duration(5*time.Second))
|
2020-07-15 14:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvider_fetchConfigurationData(t *testing.T) {
|
|
|
|
tests := []struct {
|
2022-10-14 13:10:10 +00:00
|
|
|
desc string
|
|
|
|
statusCode int
|
|
|
|
headers map[string]string
|
|
|
|
expData []byte
|
|
|
|
expErr require.ErrorAssertionFunc
|
2020-07-15 14:56:03 +00:00
|
|
|
}{
|
|
|
|
{
|
2022-10-14 13:10:10 +00:00
|
|
|
desc: "should return the fetched configuration data",
|
|
|
|
statusCode: http.StatusOK,
|
|
|
|
expData: []byte("{}"),
|
|
|
|
expErr: require.NoError,
|
2020-07-15 14:56:03 +00:00
|
|
|
},
|
|
|
|
{
|
2022-10-14 13:10:10 +00:00
|
|
|
desc: "should send configured headers",
|
|
|
|
statusCode: http.StatusOK,
|
|
|
|
headers: map[string]string{
|
2024-10-29 14:30:38 +00:00
|
|
|
"Foo": "bar",
|
|
|
|
"Bar": "baz",
|
|
|
|
"Host": "localhost",
|
2020-07-15 14:56:03 +00:00
|
|
|
},
|
2022-10-14 13:10:10 +00:00
|
|
|
expData: []byte("{}"),
|
|
|
|
expErr: require.NoError,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "should return an error if endpoint does not return an OK status code",
|
|
|
|
statusCode: http.StatusInternalServerError,
|
|
|
|
expErr: require.Error,
|
2020-07-15 14:56:03 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
2022-10-14 13:10:10 +00:00
|
|
|
handlerCalled := false
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
handlerCalled = true
|
|
|
|
|
|
|
|
for k, v := range test.headers {
|
2024-10-29 14:30:38 +00:00
|
|
|
if strings.EqualFold(k, "Host") {
|
|
|
|
assert.Equal(t, v, req.Host)
|
|
|
|
} else {
|
|
|
|
assert.Equal(t, v, req.Header.Get(k))
|
|
|
|
}
|
2022-10-14 13:10:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rw.WriteHeader(test.statusCode)
|
|
|
|
_, _ = rw.Write([]byte("{}"))
|
|
|
|
}))
|
|
|
|
defer srv.Close()
|
2020-07-15 14:56:03 +00:00
|
|
|
|
|
|
|
provider := Provider{
|
2022-10-14 13:10:10 +00:00
|
|
|
Endpoint: srv.URL,
|
|
|
|
Headers: test.headers,
|
2020-08-17 16:04:03 +00:00
|
|
|
PollInterval: ptypes.Duration(1 * time.Second),
|
|
|
|
PollTimeout: ptypes.Duration(1 * time.Second),
|
2020-07-15 14:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err := provider.Init()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
configData, err := provider.fetchConfigurationData()
|
2022-10-14 13:10:10 +00:00
|
|
|
test.expErr(t, err)
|
2020-07-15 14:56:03 +00:00
|
|
|
|
2022-10-14 13:10:10 +00:00
|
|
|
assert.True(t, handlerCalled)
|
2020-07-15 14:56:03 +00:00
|
|
|
assert.Equal(t, test.expData, configData)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvider_decodeConfiguration(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
desc string
|
|
|
|
configData []byte
|
|
|
|
expConfig *dynamic.Configuration
|
|
|
|
expErr bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "should return an error if the configuration data cannot be decoded",
|
|
|
|
expErr: true,
|
|
|
|
configData: []byte("{"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "should return the decoded dynamic configuration",
|
2022-11-30 08:50:05 +00:00
|
|
|
configData: []byte(`{"tcp":{"routers":{"foo":{}}}}`),
|
2020-07-15 14:56:03 +00:00
|
|
|
expConfig: &dynamic.Configuration{
|
|
|
|
HTTP: &dynamic.HTTPConfiguration{
|
2020-09-11 13:40:03 +00:00
|
|
|
Routers: make(map[string]*dynamic.Router),
|
|
|
|
Middlewares: make(map[string]*dynamic.Middleware),
|
|
|
|
Services: make(map[string]*dynamic.Service),
|
|
|
|
ServersTransports: make(map[string]*dynamic.ServersTransport),
|
2020-07-15 14:56:03 +00:00
|
|
|
},
|
|
|
|
TCP: &dynamic.TCPConfiguration{
|
|
|
|
Routers: map[string]*dynamic.TCPRouter{
|
|
|
|
"foo": {},
|
|
|
|
},
|
2022-12-09 08:58:05 +00:00
|
|
|
Services: make(map[string]*dynamic.TCPService),
|
|
|
|
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
2020-07-15 14:56:03 +00:00
|
|
|
},
|
|
|
|
TLS: &dynamic.TLSConfiguration{
|
|
|
|
Stores: make(map[string]tls.Store),
|
|
|
|
Options: make(map[string]tls.Options),
|
|
|
|
},
|
|
|
|
UDP: &dynamic.UDPConfiguration{
|
|
|
|
Routers: make(map[string]*dynamic.UDPRouter),
|
|
|
|
Services: make(map[string]*dynamic.UDPService),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
configuration, err := decodeConfiguration(test.configData)
|
|
|
|
if test.expErr {
|
|
|
|
require.Error(t, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, test.expConfig, configuration)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvider_Provide(t *testing.T) {
|
|
|
|
handler := func(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
rw.WriteHeader(http.StatusOK)
|
|
|
|
_, _ = fmt.Fprintf(rw, "{}")
|
|
|
|
}
|
|
|
|
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(handler))
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
provider := Provider{
|
|
|
|
Endpoint: server.URL,
|
2020-08-17 16:04:03 +00:00
|
|
|
PollTimeout: ptypes.Duration(1 * time.Second),
|
|
|
|
PollInterval: ptypes.Duration(100 * time.Millisecond),
|
2020-07-15 14:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err := provider.Init()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
configurationChan := make(chan dynamic.Message)
|
|
|
|
|
|
|
|
expConfiguration := &dynamic.Configuration{
|
|
|
|
HTTP: &dynamic.HTTPConfiguration{
|
2020-09-11 13:40:03 +00:00
|
|
|
Routers: make(map[string]*dynamic.Router),
|
|
|
|
Middlewares: make(map[string]*dynamic.Middleware),
|
|
|
|
Services: make(map[string]*dynamic.Service),
|
|
|
|
ServersTransports: make(map[string]*dynamic.ServersTransport),
|
2020-07-15 14:56:03 +00:00
|
|
|
},
|
|
|
|
TCP: &dynamic.TCPConfiguration{
|
2022-12-09 08:58:05 +00:00
|
|
|
Routers: make(map[string]*dynamic.TCPRouter),
|
|
|
|
Services: make(map[string]*dynamic.TCPService),
|
|
|
|
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
2020-07-15 14:56:03 +00:00
|
|
|
},
|
|
|
|
TLS: &dynamic.TLSConfiguration{
|
|
|
|
Stores: make(map[string]tls.Store),
|
|
|
|
Options: make(map[string]tls.Options),
|
|
|
|
},
|
|
|
|
UDP: &dynamic.UDPConfiguration{
|
|
|
|
Routers: make(map[string]*dynamic.UDPRouter),
|
|
|
|
Services: make(map[string]*dynamic.UDPService),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err = provider.Provide(configurationChan, safe.NewPool(context.Background()))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
timeout := time.After(time.Second)
|
|
|
|
|
|
|
|
select {
|
|
|
|
case configuration := <-configurationChan:
|
|
|
|
assert.NotNil(t, configuration.Configuration)
|
|
|
|
assert.Equal(t, expConfiguration, configuration.Configuration)
|
|
|
|
case <-timeout:
|
|
|
|
t.Errorf("timeout while waiting for config")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProvider_ProvideConfigurationOnlyOnceIfUnchanged(t *testing.T) {
|
|
|
|
handler := func(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
rw.WriteHeader(http.StatusOK)
|
|
|
|
_, _ = fmt.Fprintf(rw, "{}")
|
|
|
|
}
|
|
|
|
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(handler))
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
provider := Provider{
|
|
|
|
Endpoint: server.URL + "/endpoint",
|
2020-08-17 16:04:03 +00:00
|
|
|
PollTimeout: ptypes.Duration(1 * time.Second),
|
|
|
|
PollInterval: ptypes.Duration(100 * time.Millisecond),
|
2020-07-15 14:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err := provider.Init()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
configurationChan := make(chan dynamic.Message, 10)
|
|
|
|
|
|
|
|
err = provider.Provide(configurationChan, safe.NewPool(context.Background()))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
|
2023-11-17 00:50:06 +00:00
|
|
|
assert.Len(t, configurationChan, 1)
|
2020-07-15 14:56:03 +00:00
|
|
|
}
|