2019-07-12 12:10:03 +03:00
package api
import (
2019-09-02 12:38:04 +03:00
"context"
2019-07-12 12:10:03 +03:00
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
2019-08-03 04:58:23 +03:00
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/config/static"
"github.com/gorilla/mux"
2019-07-12 12:10:03 +03:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestHandler_TCP ( t * testing . T ) {
type expected struct {
statusCode int
nextPage string
jsonFile string
}
testCases := [ ] struct {
desc string
path string
2019-07-15 18:04:04 +03:00
conf runtime . Configuration
2019-07-12 12:10:03 +03:00
expected expected
} {
{
desc : "all TCP routers, but no config" ,
path : "/api/tcp/routers" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration { } ,
2019-07-12 12:10:03 +03:00
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcprouters-empty.json" ,
} ,
} ,
{
desc : "all TCP routers" ,
path : "/api/tcp/routers" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPRouters : map [ string ] * runtime . TCPRouterInfo {
2019-07-12 12:10:03 +03:00
"test@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar.other`)" ,
TLS : & dynamic . RouterTCPTLSConfig {
Passthrough : false ,
} ,
} ,
2019-07-18 16:56:04 +03:00
Status : runtime . StatusEnabled ,
2019-07-12 12:10:03 +03:00
} ,
"bar@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
2019-07-18 16:56:04 +03:00
Status : runtime . StatusWarning ,
} ,
"foo@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
Status : runtime . StatusDisabled ,
2019-07-12 12:10:03 +03:00
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcprouters.json" ,
} ,
} ,
{
desc : "all TCP routers, pagination, 1 res per page, want page 2" ,
path : "/api/tcp/routers?page=2&per_page=1" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPRouters : map [ string ] * runtime . TCPRouterInfo {
2019-07-12 12:10:03 +03:00
"bar@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
} ,
"baz@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`toto.bar`)" ,
} ,
} ,
"test@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar.other`)" ,
} ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "3" ,
jsonFile : "testdata/tcprouters-page2.json" ,
} ,
} ,
2019-09-02 12:38:04 +03:00
{
desc : "TCP routers filtered by status" ,
path : "/api/tcp/routers?status=enabled" ,
conf : runtime . Configuration {
TCPRouters : map [ string ] * runtime . TCPRouterInfo {
"test@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar.other`)" ,
TLS : & dynamic . RouterTCPTLSConfig {
Passthrough : false ,
} ,
} ,
Status : runtime . StatusEnabled ,
} ,
"bar@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
Status : runtime . StatusWarning ,
} ,
"foo@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
Status : runtime . StatusDisabled ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcprouters-filtered-status.json" ,
} ,
} ,
{
desc : "TCP routers filtered by search" ,
path : "/api/tcp/routers?search=bar@my" ,
conf : runtime . Configuration {
TCPRouters : map [ string ] * runtime . TCPRouterInfo {
"test@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar.other`)" ,
TLS : & dynamic . RouterTCPTLSConfig {
Passthrough : false ,
} ,
} ,
Status : runtime . StatusEnabled ,
} ,
"bar@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
Status : runtime . StatusWarning ,
} ,
"foo@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
Status : runtime . StatusDisabled ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcprouters-filtered-search.json" ,
} ,
} ,
2019-07-12 12:10:03 +03:00
{
desc : "one TCP router by id" ,
path : "/api/tcp/routers/bar@myprovider" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPRouters : map [ string ] * runtime . TCPRouterInfo {
2019-07-12 12:10:03 +03:00
"bar@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
jsonFile : "testdata/tcprouter-bar.json" ,
} ,
} ,
{
desc : "one TCP router by id, that does not exist" ,
path : "/api/tcp/routers/foo@myprovider" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPRouters : map [ string ] * runtime . TCPRouterInfo {
2019-07-12 12:10:03 +03:00
"bar@myprovider" : {
TCPRouter : & dynamic . TCPRouter {
EntryPoints : [ ] string { "web" } ,
Service : "foo-service@myprovider" ,
Rule : "Host(`foo.bar`)" ,
} ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusNotFound ,
} ,
} ,
{
desc : "one TCP router by id, but no config" ,
path : "/api/tcp/routers/bar@myprovider" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration { } ,
2019-07-12 12:10:03 +03:00
expected : expected {
statusCode : http . StatusNotFound ,
} ,
} ,
{
desc : "all tcp services, but no config" ,
path : "/api/tcp/services" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration { } ,
2019-07-12 12:10:03 +03:00
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcpservices-empty.json" ,
} ,
} ,
{
desc : "all tcp services" ,
path : "/api/tcp/services" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPServices : map [ string ] * runtime . TCPServiceInfo {
2019-07-12 12:10:03 +03:00
"bar@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.1:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" , "test@myprovider" } ,
2019-07-18 16:56:04 +03:00
Status : runtime . StatusEnabled ,
2019-07-12 12:10:03 +03:00
} ,
"baz@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.2:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" } ,
2019-07-18 16:56:04 +03:00
Status : runtime . StatusWarning ,
} ,
"foz@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.2:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" } ,
Status : runtime . StatusDisabled ,
2019-07-12 12:10:03 +03:00
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcpservices.json" ,
} ,
} ,
2019-09-02 12:38:04 +03:00
{
desc : "tcp services filtered by status" ,
path : "/api/tcp/services?status=enabled" ,
conf : runtime . Configuration {
TCPServices : map [ string ] * runtime . TCPServiceInfo {
"bar@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.1:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" , "test@myprovider" } ,
Status : runtime . StatusEnabled ,
} ,
"baz@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.2:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" } ,
Status : runtime . StatusWarning ,
} ,
"foz@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.2:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" } ,
Status : runtime . StatusDisabled ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcpservices-filtered-status.json" ,
} ,
} ,
{
desc : "tcp services filtered by search" ,
path : "/api/tcp/services?search=baz@my" ,
conf : runtime . Configuration {
TCPServices : map [ string ] * runtime . TCPServiceInfo {
"bar@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.1:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" , "test@myprovider" } ,
Status : runtime . StatusEnabled ,
} ,
"baz@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.2:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" } ,
Status : runtime . StatusWarning ,
} ,
"foz@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.2:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" } ,
Status : runtime . StatusDisabled ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "1" ,
jsonFile : "testdata/tcpservices-filtered-search.json" ,
} ,
} ,
2019-07-12 12:10:03 +03:00
{
desc : "all tcp services, 1 res per page, want page 2" ,
path : "/api/tcp/services?page=2&per_page=1" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPServices : map [ string ] * runtime . TCPServiceInfo {
2019-07-12 12:10:03 +03:00
"bar@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.1:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" , "test@myprovider" } ,
} ,
"baz@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.2:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" } ,
} ,
"test@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.3:2345" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
nextPage : "3" ,
jsonFile : "testdata/tcpservices-page2.json" ,
} ,
} ,
{
desc : "one tcp service by id" ,
path : "/api/tcp/services/bar@myprovider" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPServices : map [ string ] * runtime . TCPServiceInfo {
2019-07-12 12:10:03 +03:00
"bar@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.1:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" , "test@myprovider" } ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusOK ,
jsonFile : "testdata/tcpservice-bar.json" ,
} ,
} ,
{
desc : "one tcp service by id, that does not exist" ,
path : "/api/tcp/services/nono@myprovider" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration {
TCPServices : map [ string ] * runtime . TCPServiceInfo {
2019-07-12 12:10:03 +03:00
"bar@myprovider" : {
TCPService : & dynamic . TCPService {
LoadBalancer : & dynamic . TCPLoadBalancerService {
Servers : [ ] dynamic . TCPServer {
{
Address : "127.0.0.1:2345" ,
} ,
} ,
} ,
} ,
UsedBy : [ ] string { "foo@myprovider" , "test@myprovider" } ,
} ,
} ,
} ,
expected : expected {
statusCode : http . StatusNotFound ,
} ,
} ,
{
desc : "one tcp service by id, but no config" ,
path : "/api/tcp/services/foo@myprovider" ,
2019-07-15 18:04:04 +03:00
conf : runtime . Configuration { } ,
2019-07-12 12:10:03 +03:00
expected : expected {
statusCode : http . StatusNotFound ,
} ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
rtConf := & test . conf
2019-09-02 12:38:04 +03:00
// To lazily initialize the Statuses.
rtConf . PopulateUsedBy ( )
rtConf . GetTCPRoutersByEntryPoints ( context . Background ( ) , [ ] string { "web" } )
2019-07-12 12:10:03 +03:00
handler := New ( static . Configuration { API : & static . API { } , Global : & static . Global { } } , rtConf )
router := mux . NewRouter ( )
handler . Append ( router )
server := httptest . NewServer ( router )
resp , err := http . DefaultClient . Get ( server . URL + test . path )
require . NoError ( t , err )
assert . Equal ( t , test . expected . nextPage , resp . Header . Get ( nextPageHeader ) )
require . Equal ( t , test . expected . statusCode , resp . StatusCode )
if test . expected . jsonFile == "" {
return
}
assert . Equal ( t , resp . Header . Get ( "Content-Type" ) , "application/json" )
contents , err := ioutil . 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 = ioutil . WriteFile ( test . expected . jsonFile , newJSON , 0644 )
require . NoError ( t , err )
}
data , err := ioutil . ReadFile ( test . expected . jsonFile )
require . NoError ( t , err )
assert . JSONEq ( t , string ( data ) , string ( contents ) )
} )
}
}