2019-11-14 15:40:05 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2024-09-26 09:00:05 +00:00
|
|
|
"net/url"
|
2019-11-14 15:40:05 +00:00
|
|
|
"testing"
|
2024-09-26 09:00:05 +00:00
|
|
|
"time"
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2023-02-03 14:24:05 +00:00
|
|
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/config/static"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/server/middleware"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/server/service"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/tcp"
|
|
|
|
th "github.com/traefik/traefik/v3/pkg/testhelpers"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/tls"
|
2019-11-14 15:40:05 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestReuseService(t *testing.T) {
|
|
|
|
testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
rw.WriteHeader(http.StatusOK)
|
|
|
|
}))
|
|
|
|
defer testServer.Close()
|
|
|
|
|
|
|
|
staticConfig := static.Configuration{
|
|
|
|
EntryPoints: map[string]*static.EntryPoint{
|
2020-03-05 11:46:05 +00:00
|
|
|
"web": {},
|
2019-11-14 15:40:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
dynamicConfigs := th.BuildConfiguration(
|
|
|
|
th.WithRouters(
|
|
|
|
th.WithRouter("foo",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithServiceName("bar"),
|
|
|
|
th.WithRule("Path(`/ok`)")),
|
|
|
|
th.WithRouter("foo2",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithRule("Path(`/unauthorized`)"),
|
|
|
|
th.WithServiceName("bar"),
|
|
|
|
th.WithRouterMiddlewares("basicauth")),
|
|
|
|
),
|
|
|
|
th.WithMiddlewares(th.WithMiddleware("basicauth",
|
|
|
|
th.WithBasicAuth(&dynamic.BasicAuth{Users: []string{"foo:bar"}}),
|
|
|
|
)),
|
|
|
|
th.WithLoadBalancerServices(th.WithService("bar",
|
|
|
|
th.WithServers(th.WithServer(testServer.URL))),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2024-09-26 09:00:05 +00:00
|
|
|
transportManager := service.NewTransportManager(nil)
|
|
|
|
transportManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
|
|
|
|
|
|
|
managerFactory := service.NewManagerFactory(staticConfig, nil, nil, transportManager, proxyBuilderMock{}, nil)
|
2019-11-14 15:40:05 +00:00
|
|
|
tlsManager := tls.NewManager()
|
|
|
|
|
2022-12-09 08:58:05 +00:00
|
|
|
dialerManager := tcp.NewDialerManager(nil)
|
|
|
|
dialerManager.Update(map[string]*dynamic.TCPServersTransport{"default@internal": {}})
|
2024-01-30 15:28:05 +00:00
|
|
|
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, nil, nil, dialerManager)
|
2019-11-14 15:40:05 +00:00
|
|
|
|
2020-05-04 09:40:46 +00:00
|
|
|
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
// Test that the /ok path returns a status 200.
|
|
|
|
responseRecorderOk := &httptest.ResponseRecorder{}
|
|
|
|
requestOk := httptest.NewRequest(http.MethodGet, testServer.URL+"/ok", nil)
|
2020-03-05 11:46:05 +00:00
|
|
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorderOk, requestOk)
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
assert.Equal(t, http.StatusOK, responseRecorderOk.Result().StatusCode, "status code")
|
|
|
|
|
|
|
|
// Test that the /unauthorized path returns a 401 because of
|
|
|
|
// the basic authentication defined on the frontend.
|
|
|
|
responseRecorderUnauthorized := &httptest.ResponseRecorder{}
|
|
|
|
requestUnauthorized := httptest.NewRequest(http.MethodGet, testServer.URL+"/unauthorized", nil)
|
2020-03-05 11:46:05 +00:00
|
|
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorderUnauthorized, requestUnauthorized)
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
assert.Equal(t, http.StatusUnauthorized, responseRecorderUnauthorized.Result().StatusCode, "status code")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestServerResponseEmptyBackend(t *testing.T) {
|
|
|
|
const requestPath = "/path"
|
|
|
|
const routeRule = "Path(`" + requestPath + "`)"
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
config func(testServerURL string) *dynamic.HTTPConfiguration
|
|
|
|
expectedStatusCode int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "Ok",
|
|
|
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
|
|
|
return th.BuildConfiguration(
|
|
|
|
th.WithRouters(th.WithRouter("foo",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithServiceName("bar"),
|
|
|
|
th.WithRule(routeRule)),
|
|
|
|
),
|
|
|
|
th.WithLoadBalancerServices(th.WithService("bar",
|
|
|
|
th.WithServers(th.WithServer(testServerURL))),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
expectedStatusCode: http.StatusOK,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "No Frontend",
|
|
|
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
|
|
|
return th.BuildConfiguration()
|
|
|
|
},
|
|
|
|
expectedStatusCode: http.StatusNotFound,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "Empty Backend LB",
|
|
|
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
|
|
|
return th.BuildConfiguration(
|
|
|
|
th.WithRouters(th.WithRouter("foo",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithServiceName("bar"),
|
|
|
|
th.WithRule(routeRule)),
|
|
|
|
),
|
|
|
|
th.WithLoadBalancerServices(th.WithService("bar")),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
expectedStatusCode: http.StatusServiceUnavailable,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "Empty Backend LB Sticky",
|
|
|
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
|
|
|
return th.BuildConfiguration(
|
|
|
|
th.WithRouters(th.WithRouter("foo",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithServiceName("bar"),
|
|
|
|
th.WithRule(routeRule)),
|
|
|
|
),
|
|
|
|
th.WithLoadBalancerServices(th.WithService("bar",
|
|
|
|
th.WithSticky("test")),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
expectedStatusCode: http.StatusServiceUnavailable,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "Empty Backend LB",
|
|
|
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
|
|
|
return th.BuildConfiguration(
|
|
|
|
th.WithRouters(th.WithRouter("foo",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithServiceName("bar"),
|
|
|
|
th.WithRule(routeRule)),
|
|
|
|
),
|
|
|
|
th.WithLoadBalancerServices(th.WithService("bar")),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
expectedStatusCode: http.StatusServiceUnavailable,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "Empty Backend LB Sticky",
|
|
|
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
|
|
|
return th.BuildConfiguration(
|
|
|
|
th.WithRouters(th.WithRouter("foo",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithServiceName("bar"),
|
|
|
|
th.WithRule(routeRule)),
|
|
|
|
),
|
|
|
|
th.WithLoadBalancerServices(th.WithService("bar",
|
|
|
|
th.WithSticky("test")),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
expectedStatusCode: http.StatusServiceUnavailable,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
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()
|
|
|
|
|
|
|
|
staticConfig := static.Configuration{
|
|
|
|
EntryPoints: map[string]*static.EntryPoint{
|
2020-03-05 11:46:05 +00:00
|
|
|
"web": {},
|
2019-11-14 15:40:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2024-09-26 09:00:05 +00:00
|
|
|
transportManager := service.NewTransportManager(nil)
|
|
|
|
transportManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
|
|
|
|
|
|
|
managerFactory := service.NewManagerFactory(staticConfig, nil, nil, transportManager, proxyBuilderMock{}, nil)
|
2019-11-14 15:40:05 +00:00
|
|
|
tlsManager := tls.NewManager()
|
|
|
|
|
2022-12-09 08:58:05 +00:00
|
|
|
dialerManager := tcp.NewDialerManager(nil)
|
|
|
|
dialerManager.Update(map[string]*dynamic.TCPServersTransport{"default@internal": {}})
|
2024-03-12 08:48:04 +00:00
|
|
|
observabiltyMgr := middleware.NewObservabilityMgr(staticConfig, nil, nil, nil, nil, nil)
|
2024-01-30 15:28:05 +00:00
|
|
|
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, observabiltyMgr, nil, dialerManager)
|
2019-11-14 15:40:05 +00:00
|
|
|
|
2020-05-04 09:40:46 +00:00
|
|
|
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: test.config(testServer.URL)}))
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
responseRecorder := &httptest.ResponseRecorder{}
|
|
|
|
request := httptest.NewRequest(http.MethodGet, testServer.URL+requestPath, nil)
|
|
|
|
|
2020-03-05 11:46:05 +00:00
|
|
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorder, request)
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
assert.Equal(t, test.expectedStatusCode, responseRecorder.Result().StatusCode, "status code")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalServices(t *testing.T) {
|
|
|
|
testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
rw.WriteHeader(http.StatusOK)
|
|
|
|
}))
|
|
|
|
defer testServer.Close()
|
|
|
|
|
|
|
|
staticConfig := static.Configuration{
|
|
|
|
API: &static.API{},
|
|
|
|
EntryPoints: map[string]*static.EntryPoint{
|
2020-03-05 11:46:05 +00:00
|
|
|
"web": {},
|
2019-11-14 15:40:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
dynamicConfigs := th.BuildConfiguration(
|
|
|
|
th.WithRouters(
|
|
|
|
th.WithRouter("foo",
|
2020-03-05 11:46:05 +00:00
|
|
|
th.WithEntryPoints("web"),
|
2019-11-14 15:40:05 +00:00
|
|
|
th.WithServiceName("api@internal"),
|
|
|
|
th.WithRule("PathPrefix(`/api`)")),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2024-09-26 09:00:05 +00:00
|
|
|
transportManager := service.NewTransportManager(nil)
|
|
|
|
transportManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
|
|
|
|
|
|
|
managerFactory := service.NewManagerFactory(staticConfig, nil, nil, transportManager, nil, nil)
|
2019-11-14 15:40:05 +00:00
|
|
|
tlsManager := tls.NewManager()
|
|
|
|
|
2022-12-09 08:58:05 +00:00
|
|
|
dialerManager := tcp.NewDialerManager(nil)
|
|
|
|
dialerManager.Update(map[string]*dynamic.TCPServersTransport{"default@internal": {}})
|
2024-01-30 15:28:05 +00:00
|
|
|
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, nil, nil, dialerManager)
|
2019-11-14 15:40:05 +00:00
|
|
|
|
2020-05-04 09:40:46 +00:00
|
|
|
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
// Test that the /ok path returns a status 200.
|
|
|
|
responseRecorderOk := &httptest.ResponseRecorder{}
|
|
|
|
requestOk := httptest.NewRequest(http.MethodGet, testServer.URL+"/api/rawdata", nil)
|
2020-03-05 11:46:05 +00:00
|
|
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorderOk, requestOk)
|
2019-11-14 15:40:05 +00:00
|
|
|
|
|
|
|
assert.Equal(t, http.StatusOK, responseRecorderOk.Result().StatusCode, "status code")
|
|
|
|
}
|
2024-09-26 09:00:05 +00:00
|
|
|
|
|
|
|
type proxyBuilderMock struct{}
|
|
|
|
|
|
|
|
func (p proxyBuilderMock) Build(_ string, _ *url.URL, _, _ bool, _ time.Duration) (http.Handler, error) {
|
|
|
|
return http.HandlerFunc(func(responseWriter http.ResponseWriter, req *http.Request) {}), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p proxyBuilderMock) Update(_ map[string]*dynamic.ServersTransport) {
|
|
|
|
panic("implement me")
|
|
|
|
}
|