mirror of
				https://github.com/traefik/traefik.git
				synced 2025-10-31 00:11:38 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			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 {
 | |
| 		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
 | |
| }
 |