traefik/pkg/server/aggregator_test.go
2024-05-14 09:42:04 +02:00

714 lines
18 KiB
Go

package server
import (
"testing"
"github.com/go-acme/lego/v4/challenge/tlsalpn01"
"github.com/stretchr/testify/assert"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/tls"
)
func Test_mergeConfiguration(t *testing.T) {
testCases := []struct {
desc string
given dynamic.Configurations
expected *dynamic.HTTPConfiguration
}{
{
desc: "Nil returns an empty configuration",
given: nil,
expected: &dynamic.HTTPConfiguration{
Routers: make(map[string]*dynamic.Router),
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: make(map[string]*dynamic.Model),
ServersTransports: make(map[string]*dynamic.ServersTransport),
},
},
{
desc: "Returns fully qualified elements from a mono-provider configuration map",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"router-1": {},
},
Middlewares: map[string]*dynamic.Middleware{
"middleware-1": {},
},
Services: map[string]*dynamic.Service{
"service-1": {},
},
},
},
},
expected: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"router-1@provider-1": {
EntryPoints: []string{"defaultEP"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"middleware-1@provider-1": {},
},
Services: map[string]*dynamic.Service{
"service-1@provider-1": {},
},
Models: make(map[string]*dynamic.Model),
ServersTransports: make(map[string]*dynamic.ServersTransport),
},
},
{
desc: "Returns fully qualified elements from a multi-provider configuration map",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"router-1": {},
},
Middlewares: map[string]*dynamic.Middleware{
"middleware-1": {},
},
Services: map[string]*dynamic.Service{
"service-1": {},
},
},
},
"provider-2": &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"router-1": {},
},
Middlewares: map[string]*dynamic.Middleware{
"middleware-1": {},
},
Services: map[string]*dynamic.Service{
"service-1": {},
},
},
},
},
expected: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"router-1@provider-1": {
EntryPoints: []string{"defaultEP"},
},
"router-1@provider-2": {
EntryPoints: []string{"defaultEP"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"middleware-1@provider-1": {},
"middleware-1@provider-2": {},
},
Services: map[string]*dynamic.Service{
"service-1@provider-1": {},
"service-1@provider-2": {},
},
Models: make(map[string]*dynamic.Model),
ServersTransports: make(map[string]*dynamic.ServersTransport),
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := mergeConfiguration(test.given, []string{"defaultEP"})
assert.Equal(t, test.expected, actual.HTTP)
})
}
}
func Test_mergeConfiguration_tlsCertificates(t *testing.T) {
testCases := []struct {
desc string
given dynamic.Configurations
expected []*tls.CertAndStores
}{
{
desc: "Skip temp certificates from another provider than tlsalpn",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{Certificate: tls.Certificate{}, Stores: []string{tlsalpn01.ACMETLS1Protocol}},
},
},
},
},
expected: nil,
},
{
desc: "Allows tlsalpn provider to give certificates",
given: dynamic.Configurations{
"tlsalpn.acme": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{{
Certificate: tls.Certificate{CertFile: "foo", KeyFile: "bar"},
Stores: []string{tlsalpn01.ACMETLS1Protocol},
}},
},
},
},
expected: []*tls.CertAndStores{{
Certificate: tls.Certificate{CertFile: "foo", KeyFile: "bar"},
Stores: []string{tlsalpn01.ACMETLS1Protocol},
}},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := mergeConfiguration(test.given, []string{"defaultEP"})
assert.Equal(t, test.expected, actual.TLS.Certificates)
})
}
}
func Test_mergeConfiguration_tlsOptions(t *testing.T) {
testCases := []struct {
desc string
given dynamic.Configurations
expected map[string]tls.Options
}{
{
desc: "Nil returns an empty configuration",
given: nil,
expected: map[string]tls.Options{
"default": tls.DefaultTLSOptions,
},
},
{
desc: "Returns fully qualified elements from a mono-provider configuration map",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS12",
},
},
},
},
},
expected: map[string]tls.Options{
"default": tls.DefaultTLSOptions,
"foo@provider-1": {
MinVersion: "VersionTLS12",
},
},
},
{
desc: "Returns fully qualified elements from a multi-provider configuration map",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS13",
},
},
},
},
"provider-2": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS12",
},
},
},
},
},
expected: map[string]tls.Options{
"default": tls.DefaultTLSOptions,
"foo@provider-1": {
MinVersion: "VersionTLS13",
},
"foo@provider-2": {
MinVersion: "VersionTLS12",
},
},
},
{
desc: "Create a valid default tls option when appears only in one provider",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS13",
},
"default": {
MinVersion: "VersionTLS11",
},
},
},
},
"provider-2": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS12",
},
},
},
},
},
expected: map[string]tls.Options{
"default": {
MinVersion: "VersionTLS11",
},
"foo@provider-1": {
MinVersion: "VersionTLS13",
},
"foo@provider-2": {
MinVersion: "VersionTLS12",
},
},
},
{
desc: "No default tls option if it is defined in multiple providers",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS12",
},
"default": {
MinVersion: "VersionTLS11",
},
},
},
},
"provider-2": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS13",
},
"default": {
MinVersion: "VersionTLS12",
},
},
},
},
},
expected: map[string]tls.Options{
"foo@provider-1": {
MinVersion: "VersionTLS12",
},
"foo@provider-2": {
MinVersion: "VersionTLS13",
},
},
},
{
desc: "Create a default TLS Options configuration if none was provided",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS12",
},
},
},
},
"provider-2": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"foo": {
MinVersion: "VersionTLS13",
},
},
},
},
},
expected: map[string]tls.Options{
"default": tls.DefaultTLSOptions,
"foo@provider-1": {
MinVersion: "VersionTLS12",
},
"foo@provider-2": {
MinVersion: "VersionTLS13",
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := mergeConfiguration(test.given, []string{"defaultEP"})
assert.Equal(t, test.expected, actual.TLS.Options)
})
}
}
func Test_mergeConfiguration_tlsStore(t *testing.T) {
testCases := []struct {
desc string
given dynamic.Configurations
expected map[string]tls.Store
}{
{
desc: "Create a valid default tls store when appears only in one provider",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{
"default": {
DefaultCertificate: &tls.Certificate{
CertFile: "foo",
KeyFile: "bar",
},
},
},
},
},
"provider-2": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{
"foo": {
DefaultCertificate: &tls.Certificate{
CertFile: "foo",
KeyFile: "bar",
},
},
},
},
},
},
expected: map[string]tls.Store{
"default": {
DefaultCertificate: &tls.Certificate{
CertFile: "foo",
KeyFile: "bar",
},
},
"foo@provider-2": {
DefaultCertificate: &tls.Certificate{
CertFile: "foo",
KeyFile: "bar",
},
},
},
},
{
desc: "Don't default tls store when appears two times",
given: dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{
"default": {
DefaultCertificate: &tls.Certificate{
CertFile: "foo",
KeyFile: "bar",
},
},
},
},
},
"provider-2": &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{
"default": {
DefaultCertificate: &tls.Certificate{
CertFile: "foo",
KeyFile: "bar",
},
},
},
},
},
},
expected: map[string]tls.Store{},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := mergeConfiguration(test.given, []string{"defaultEP"})
assert.Equal(t, test.expected, actual.TLS.Stores)
})
}
}
func Test_mergeConfiguration_defaultTCPEntryPoint(t *testing.T) {
given := dynamic.Configurations{
"provider-1": &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"router-1": {},
},
Services: map[string]*dynamic.TCPService{
"service-1": {},
},
},
},
}
expected := &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"router-1@provider-1": {
EntryPoints: []string{"defaultEP"},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"service-1@provider-1": {},
},
Models: map[string]*dynamic.TCPModel{},
ServersTransports: make(map[string]*dynamic.TCPServersTransport),
}
actual := mergeConfiguration(given, []string{"defaultEP"})
assert.Equal(t, expected, actual.TCP)
}
func Test_applyModel(t *testing.T) {
testCases := []struct {
desc string
input dynamic.Configuration
expected dynamic.Configuration
}{
{
desc: "empty configuration",
input: dynamic.Configuration{},
expected: dynamic.Configuration{},
},
{
desc: "without model",
input: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: make(map[string]*dynamic.Router),
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: make(map[string]*dynamic.Model),
},
},
expected: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: make(map[string]*dynamic.Router),
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: make(map[string]*dynamic.Model),
},
},
},
{
desc: "with model, not used",
input: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: make(map[string]*dynamic.Router),
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"ep@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
},
},
expected: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: make(map[string]*dynamic.Router),
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"ep@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
},
},
},
{
desc: "with model, one entry point",
input: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"test": {
EntryPoints: []string{"websecure"},
},
},
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"websecure@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
},
},
expected: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"test": {
EntryPoints: []string{"websecure"},
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"websecure@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
},
},
},
{
desc: "with model, one entry point, and router with tls",
input: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"test": {
EntryPoints: []string{"websecure"},
TLS: &dynamic.RouterTLSConfig{CertResolver: "router"},
},
},
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"websecure@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{CertResolver: "ep"},
},
},
},
},
expected: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"test": {
EntryPoints: []string{"websecure"},
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{CertResolver: "router"},
},
},
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"websecure@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{CertResolver: "ep"},
},
},
},
},
},
{
desc: "with model, two entry points",
input: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"test": {
EntryPoints: []string{"websecure", "web"},
},
},
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"websecure@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
},
},
expected: dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"test": {
EntryPoints: []string{"web"},
},
"websecure-test": {
EntryPoints: []string{"websecure"},
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: make(map[string]*dynamic.Middleware),
Services: make(map[string]*dynamic.Service),
Models: map[string]*dynamic.Model{
"websecure@internal": {
Middlewares: []string{"test"},
TLS: &dynamic.RouterTLSConfig{},
},
},
},
},
},
{
desc: "with TCP model, two entry points",
input: dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"test": {
EntryPoints: []string{"websecure", "web"},
},
"test2": {
EntryPoints: []string{"web"},
RuleSyntax: "barfoo",
},
},
Middlewares: make(map[string]*dynamic.TCPMiddleware),
Services: make(map[string]*dynamic.TCPService),
Models: map[string]*dynamic.TCPModel{
"websecure@internal": {
DefaultRuleSyntax: "foobar",
},
},
},
},
expected: dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"test": {
EntryPoints: []string{"websecure", "web"},
RuleSyntax: "foobar",
},
"test2": {
EntryPoints: []string{"web"},
RuleSyntax: "barfoo",
},
},
Middlewares: make(map[string]*dynamic.TCPMiddleware),
Services: make(map[string]*dynamic.TCPService),
Models: map[string]*dynamic.TCPModel{
"websecure@internal": {
DefaultRuleSyntax: "foobar",
},
},
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := applyModel(test.input)
assert.Equal(t, test.expected, actual)
})
}
}