traefik/pkg/config/runtime/runtime_test.go
2024-04-03 17:54:11 +02:00

690 lines
18 KiB
Go

package runtime_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/config/runtime"
)
// all the Routers/Middlewares/Services are considered fully qualified.
func TestPopulateUsedBy(t *testing.T) {
testCases := []struct {
desc string
conf *runtime.Configuration
expected runtime.Configuration
}{
{
desc: "nil config",
conf: nil,
expected: runtime.Configuration{},
},
{
desc: "One service used by two routers",
conf: &runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"foo@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`bar.foo`)",
},
},
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{URL: "http://127.0.0.1:8085"},
{URL: "http://127.0.0.1:8086"},
},
HealthCheck: &dynamic.ServerHealthCheck{
Interval: ptypes.Duration(500 * time.Millisecond),
Path: "/health",
},
},
},
},
},
},
expected: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"foo@myprovider": {},
"bar@myprovider": {},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider", "foo@myprovider"},
},
},
},
},
{
desc: "One service used by two routers, but one router with wrong rule",
conf: &runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{URL: "http://127.0.0.1"},
},
},
},
},
},
Routers: map[string]*runtime.RouterInfo{
"foo@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "WrongRule(`bar.foo`)",
},
},
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
},
expected: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"foo@myprovider": {},
"bar@myprovider": {},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider", "foo@myprovider"},
},
},
},
},
{
desc: "Broken Service used by one Router",
conf: &runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: nil,
},
},
},
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
},
expected: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
},
},
{
desc: "2 different Services each used by a distinct router.",
conf: &runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1:8085",
},
{
URL: "http://127.0.0.1:8086",
},
},
HealthCheck: &dynamic.ServerHealthCheck{
Interval: ptypes.Duration(500 * time.Millisecond),
Path: "/health",
},
},
},
},
"bar-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1:8087",
},
{
URL: "http://127.0.0.1:8088",
},
},
HealthCheck: &dynamic.ServerHealthCheck{
Interval: ptypes.Duration(500 * time.Millisecond),
Path: "/health",
},
},
},
},
},
Routers: map[string]*runtime.RouterInfo{
"foo@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`bar.foo`)",
},
},
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "bar-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
},
expected: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {},
"foo@myprovider": {},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"foo@myprovider"},
},
"bar-service@myprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
},
},
{
desc: "2 middlewares both used by 2 Routers",
conf: &runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
},
},
},
},
},
},
Middlewares: map[string]*runtime.MiddlewareInfo{
"auth@myprovider": {
Middleware: &dynamic.Middleware{
BasicAuth: &dynamic.BasicAuth{
Users: []string{"admin:admin"},
},
},
},
"addPrefixTest@myprovider": {
Middleware: &dynamic.Middleware{
AddPrefix: &dynamic.AddPrefix{
Prefix: "/toto",
},
},
},
},
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
Middlewares: []string{"auth", "addPrefixTest"},
},
},
"test@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar.other`)",
Middlewares: []string{"addPrefixTest", "auth"},
},
},
},
},
expected: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {},
"test@myprovider": {},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider", "test@myprovider"},
},
},
Middlewares: map[string]*runtime.MiddlewareInfo{
"auth@myprovider": {
UsedBy: []string{"bar@myprovider", "test@myprovider"},
},
"addPrefixTest@myprovider": {
UsedBy: []string{"bar@myprovider", "test@myprovider"},
},
},
},
},
{
desc: "Unknown middleware is not used by the Router",
conf: &runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
},
},
},
},
},
},
Middlewares: map[string]*runtime.MiddlewareInfo{
"auth@myprovider": {
Middleware: &dynamic.Middleware{
BasicAuth: &dynamic.BasicAuth{
Users: []string{"admin:admin"},
},
},
},
},
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
Middlewares: []string{"unknown"},
},
},
},
},
expected: runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
},
},
{
desc: "Broken middleware is used by Router",
conf: &runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
},
},
},
},
},
},
Middlewares: map[string]*runtime.MiddlewareInfo{
"auth@myprovider": {
Middleware: &dynamic.Middleware{
BasicAuth: &dynamic.BasicAuth{
Users: []string{"badConf"},
},
},
},
},
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
Middlewares: []string{"auth@myprovider"},
},
},
},
},
expected: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
Middlewares: map[string]*runtime.MiddlewareInfo{
"auth@myprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
},
},
{
desc: "2 middlewares from 2 distinct providers both used by 2 Routers",
conf: &runtime.Configuration{
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
},
},
},
},
},
},
Middlewares: map[string]*runtime.MiddlewareInfo{
"auth@myprovider": {
Middleware: &dynamic.Middleware{
BasicAuth: &dynamic.BasicAuth{
Users: []string{"admin:admin"},
},
},
},
"addPrefixTest@myprovider": {
Middleware: &dynamic.Middleware{
AddPrefix: &dynamic.AddPrefix{
Prefix: "/titi",
},
},
},
"addPrefixTest@anotherprovider": {
Middleware: &dynamic.Middleware{
AddPrefix: &dynamic.AddPrefix{
Prefix: "/toto",
},
},
},
},
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
},
},
"test@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar.other`)",
Middlewares: []string{"addPrefixTest", "auth"},
},
},
},
},
expected: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"bar@myprovider": {},
"test@myprovider": {},
},
Services: map[string]*runtime.ServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider", "test@myprovider"},
},
},
Middlewares: map[string]*runtime.MiddlewareInfo{
"auth@myprovider": {
UsedBy: []string{"bar@myprovider", "test@myprovider"},
},
"addPrefixTest@myprovider": {
UsedBy: []string{"test@myprovider"},
},
"addPrefixTest@anotherprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
},
},
// TCP tests from hereon
{
desc: "TCP, One service used by two routers",
conf: &runtime.Configuration{
TCPRouters: map[string]*runtime.TCPRouterInfo{
"foo@myprovider": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`bar.foo`)",
},
},
"bar@myprovider": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "127.0.0.1",
Port: "8085",
},
{
Address: "127.0.0.1",
Port: "8086",
},
},
},
},
},
},
},
expected: runtime.Configuration{
TCPRouters: map[string]*runtime.TCPRouterInfo{
"foo@myprovider": {},
"bar@myprovider": {},
},
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider", "foo@myprovider"},
},
},
},
},
{
desc: "TCP, One service used by two routers, but one router with wrong rule",
conf: &runtime.Configuration{
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "127.0.0.1",
},
},
},
},
},
},
TCPRouters: map[string]*runtime.TCPRouterInfo{
"foo@myprovider": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "WrongRule(`bar.foo`)",
},
},
"bar@myprovider": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
},
expected: runtime.Configuration{
TCPRouters: map[string]*runtime.TCPRouterInfo{
"foo@myprovider": {},
"bar@myprovider": {},
},
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider", "foo@myprovider"},
},
},
},
},
{
desc: "TCP, Broken Service used by one Router",
conf: &runtime.Configuration{
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
TCPService: &dynamic.TCPService{
LoadBalancer: nil,
},
},
},
TCPRouters: map[string]*runtime.TCPRouterInfo{
"bar@myprovider": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
},
expected: runtime.Configuration{
TCPRouters: map[string]*runtime.TCPRouterInfo{
"bar@myprovider": {},
},
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
},
},
{
desc: "TCP, 2 different Services each used by a distinct router.",
conf: &runtime.Configuration{
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "127.0.0.1",
Port: "8085",
},
{
Address: "127.0.0.1",
Port: "8086",
},
},
},
},
},
"bar-service@myprovider": {
TCPService: &dynamic.TCPService{
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "127.0.0.1",
Port: "8087",
},
{
Address: "127.0.0.1",
Port: "8088",
},
},
},
},
},
},
TCPRouters: map[string]*runtime.TCPRouterInfo{
"foo@myprovider": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`bar.foo`)",
},
},
"bar@myprovider": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "bar-service@myprovider",
Rule: "Host(`foo.bar`)",
},
},
},
},
expected: runtime.Configuration{
TCPRouters: map[string]*runtime.TCPRouterInfo{
"bar@myprovider": {},
"foo@myprovider": {},
},
TCPServices: map[string]*runtime.TCPServiceInfo{
"foo-service@myprovider": {
UsedBy: []string{"foo@myprovider"},
},
"bar-service@myprovider": {
UsedBy: []string{"bar@myprovider"},
},
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
runtimeConf := test.conf
runtimeConf.PopulateUsedBy()
for key, expectedService := range test.expected.Services {
require.NotNil(t, runtimeConf.Services[key])
assert.Equal(t, expectedService.UsedBy, runtimeConf.Services[key].UsedBy)
}
for key, expectedMiddleware := range test.expected.Middlewares {
require.NotNil(t, runtimeConf.Middlewares[key])
assert.Equal(t, expectedMiddleware.UsedBy, runtimeConf.Middlewares[key].UsedBy)
}
for key, expectedTCPService := range test.expected.TCPServices {
require.NotNil(t, runtimeConf.TCPServices[key])
assert.Equal(t, expectedTCPService.UsedBy, runtimeConf.TCPServices[key].UsedBy)
}
})
}
}