266 lines
6.7 KiB
Go
266 lines
6.7 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
|
"github.com/traefik/traefik/v3/pkg/config/static"
|
|
)
|
|
|
|
func TestHandler_EntryPoints(t *testing.T) {
|
|
type expected struct {
|
|
statusCode int
|
|
nextPage string
|
|
jsonFile string
|
|
}
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
path string
|
|
conf static.Configuration
|
|
expected expected
|
|
}{
|
|
{
|
|
desc: "all entry points, but no config",
|
|
path: "/api/entrypoints",
|
|
conf: static.Configuration{API: &static.API{}, Global: &static.Global{}},
|
|
expected: expected{
|
|
statusCode: http.StatusOK,
|
|
nextPage: "1",
|
|
jsonFile: "testdata/entrypoints-empty.json",
|
|
},
|
|
},
|
|
{
|
|
desc: "all entry points",
|
|
path: "/api/entrypoints",
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: map[string]*static.EntryPoint{
|
|
"web": {
|
|
Address: ":80",
|
|
Transport: &static.EntryPointsTransport{
|
|
LifeCycle: &static.LifeCycle{
|
|
RequestAcceptGraceTimeout: 1,
|
|
GraceTimeOut: 2,
|
|
},
|
|
RespondingTimeouts: &static.RespondingTimeouts{
|
|
ReadTimeout: 3,
|
|
WriteTimeout: 4,
|
|
IdleTimeout: 5,
|
|
},
|
|
},
|
|
ProxyProtocol: &static.ProxyProtocol{
|
|
Insecure: true,
|
|
TrustedIPs: []string{"192.168.1.1", "192.168.1.2"},
|
|
},
|
|
ForwardedHeaders: &static.ForwardedHeaders{
|
|
Insecure: true,
|
|
TrustedIPs: []string{"192.168.1.3", "192.168.1.4"},
|
|
},
|
|
},
|
|
"websecure": {
|
|
Address: ":443",
|
|
Transport: &static.EntryPointsTransport{
|
|
LifeCycle: &static.LifeCycle{
|
|
RequestAcceptGraceTimeout: 10,
|
|
GraceTimeOut: 20,
|
|
},
|
|
RespondingTimeouts: &static.RespondingTimeouts{
|
|
ReadTimeout: 30,
|
|
WriteTimeout: 40,
|
|
IdleTimeout: 50,
|
|
},
|
|
},
|
|
ProxyProtocol: &static.ProxyProtocol{
|
|
Insecure: true,
|
|
TrustedIPs: []string{"192.168.1.10", "192.168.1.20"},
|
|
},
|
|
ForwardedHeaders: &static.ForwardedHeaders{
|
|
Insecure: true,
|
|
TrustedIPs: []string{"192.168.1.30", "192.168.1.40"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusOK,
|
|
nextPage: "1",
|
|
jsonFile: "testdata/entrypoints.json",
|
|
},
|
|
},
|
|
{
|
|
desc: "all entry points, pagination, 1 res per page, want page 2",
|
|
path: "/api/entrypoints?page=2&per_page=1",
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: map[string]*static.EntryPoint{
|
|
"web1": {Address: ":81"},
|
|
"web2": {Address: ":82"},
|
|
"web3": {Address: ":83"},
|
|
},
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusOK,
|
|
nextPage: "3",
|
|
jsonFile: "testdata/entrypoints-page2.json",
|
|
},
|
|
},
|
|
{
|
|
desc: "all entry points, pagination, 19 results overall, 7 res per page, want page 3",
|
|
path: "/api/entrypoints?page=3&per_page=7",
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: generateEntryPoints(19),
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusOK,
|
|
nextPage: "1",
|
|
jsonFile: "testdata/entrypoints-many-lastpage.json",
|
|
},
|
|
},
|
|
{
|
|
desc: "all entry points, pagination, 5 results overall, 10 res per page, want page 2",
|
|
path: "/api/entrypoints?page=2&per_page=10",
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: generateEntryPoints(5),
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusBadRequest,
|
|
},
|
|
},
|
|
{
|
|
desc: "all entry points, pagination, 10 results overall, 10 res per page, want page 2",
|
|
path: "/api/entrypoints?page=2&per_page=10",
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: generateEntryPoints(10),
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusBadRequest,
|
|
},
|
|
},
|
|
{
|
|
desc: "one entry point by id",
|
|
path: "/api/entrypoints/bar",
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: map[string]*static.EntryPoint{
|
|
"bar": {Address: ":81"},
|
|
},
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusOK,
|
|
jsonFile: "testdata/entrypoint-bar.json",
|
|
},
|
|
},
|
|
{
|
|
desc: "one entry point by id containing slash",
|
|
path: "/api/entrypoints/" + url.PathEscape("foo / bar"),
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: map[string]*static.EntryPoint{
|
|
"foo / bar": {Address: ":81"},
|
|
},
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusOK,
|
|
jsonFile: "testdata/entrypoint-foo-slash-bar.json",
|
|
},
|
|
},
|
|
{
|
|
desc: "one entry point by id, that does not exist",
|
|
path: "/api/entrypoints/foo",
|
|
conf: static.Configuration{
|
|
Global: &static.Global{},
|
|
API: &static.API{},
|
|
EntryPoints: map[string]*static.EntryPoint{
|
|
"bar": {Address: ":81"},
|
|
},
|
|
},
|
|
expected: expected{
|
|
statusCode: http.StatusNotFound,
|
|
},
|
|
},
|
|
{
|
|
desc: "one entry point by id, but no config",
|
|
path: "/api/entrypoints/foo",
|
|
conf: static.Configuration{API: &static.API{}, Global: &static.Global{}},
|
|
expected: expected{
|
|
statusCode: http.StatusNotFound,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test := test
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
handler := New(test.conf, &runtime.Configuration{})
|
|
server := httptest.NewServer(handler.createRouter())
|
|
|
|
resp, err := http.DefaultClient.Get(server.URL + test.path)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, test.expected.statusCode, resp.StatusCode)
|
|
|
|
assert.Equal(t, test.expected.nextPage, resp.Header.Get(nextPageHeader))
|
|
|
|
if test.expected.jsonFile == "" {
|
|
return
|
|
}
|
|
|
|
assert.Equal(t, "application/json", resp.Header.Get("Content-Type"))
|
|
contents, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
err = resp.Body.Close()
|
|
require.NoError(t, err)
|
|
|
|
if *updateExpected {
|
|
var results interface{}
|
|
err := json.Unmarshal(contents, &results)
|
|
require.NoError(t, err)
|
|
|
|
newJSON, err := json.MarshalIndent(results, "", "\t")
|
|
require.NoError(t, err)
|
|
|
|
err = os.WriteFile(test.expected.jsonFile, newJSON, 0o644)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
data, err := os.ReadFile(test.expected.jsonFile)
|
|
require.NoError(t, err)
|
|
assert.JSONEq(t, string(data), string(contents))
|
|
})
|
|
}
|
|
}
|
|
|
|
func generateEntryPoints(nb int) map[string]*static.EntryPoint {
|
|
eps := make(map[string]*static.EntryPoint, nb)
|
|
for i := range nb {
|
|
eps[fmt.Sprintf("ep%2d", i)] = &static.EntryPoint{
|
|
Address: ":" + strconv.Itoa(i),
|
|
}
|
|
}
|
|
|
|
return eps
|
|
}
|