2019-07-12 12:10:03 +03:00
package api
import (
"encoding/json"
"fmt"
2021-03-04 22:08:03 +03:00
"io"
2019-07-12 12:10:03 +03:00
"net/http"
"net/http/httptest"
2024-01-25 11:56:05 +03:00
"net/url"
2021-03-04 22:08:03 +03:00
"os"
2019-07-12 12:10:03 +03:00
"strconv"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2023-02-03 17:24:05 +03:00
"github.com/traefik/traefik/v3/pkg/config/runtime"
"github.com/traefik/traefik/v3/pkg/config/static"
2019-07-12 12:10:03 +03:00
)
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" } ,
} ,
} ,
2020-01-23 18:36:08 +03:00
"websecure" : {
2019-07-12 12:10:03 +03:00
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" ,
} ,
} ,
2024-01-25 11:56:05 +03:00
{
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" ,
} ,
} ,
2019-07-12 12:10:03 +03:00
{
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 {
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
2019-07-15 18:04:04 +03:00
handler := New ( test . conf , & runtime . Configuration { } )
2019-11-14 18:40:05 +03:00
server := httptest . NewServer ( handler . createRouter ( ) )
2019-07-12 12:10:03 +03:00
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
}
2023-11-17 03:50:06 +03:00
assert . Equal ( t , "application/json" , resp . Header . Get ( "Content-Type" ) )
2021-03-04 22:08:03 +03:00
contents , err := io . ReadAll ( resp . Body )
2019-07-12 12:10:03 +03:00
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 )
2021-03-04 22:08:03 +03:00
err = os . WriteFile ( test . expected . jsonFile , newJSON , 0 o644 )
2019-07-12 12:10:03 +03:00
require . NoError ( t , err )
}
2021-03-04 22:08:03 +03:00
data , err := os . ReadFile ( test . expected . jsonFile )
2019-07-12 12:10:03 +03:00
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 )
2024-02-19 17:44:03 +03:00
for i := range nb {
2019-07-12 12:10:03 +03:00
eps [ fmt . Sprintf ( "ep%2d" , i ) ] = & static . EntryPoint {
Address : ":" + strconv . Itoa ( i ) ,
}
}
return eps
}