2017-03-15 19:16:06 +01:00
package server
import (
"fmt"
2017-05-09 15:31:16 -05:00
"net/http"
2017-03-15 19:16:06 +01:00
"net/url"
"reflect"
"testing"
"time"
2017-03-24 09:36:33 +01:00
"github.com/containous/flaeg"
2017-05-09 15:31:16 -05:00
"github.com/containous/mux"
2017-03-15 19:16:06 +01:00
"github.com/containous/traefik/healthcheck"
2017-05-09 15:31:16 -05:00
"github.com/containous/traefik/testhelpers"
2017-03-15 19:16:06 +01:00
"github.com/containous/traefik/types"
2017-05-11 00:34:47 +02:00
"github.com/davecgh/go-spew/spew"
2017-03-15 19:16:06 +01:00
"github.com/vulcand/oxy/roundrobin"
)
type testLoadBalancer struct { }
func ( lb * testLoadBalancer ) RemoveServer ( u * url . URL ) error {
return nil
}
func ( lb * testLoadBalancer ) UpsertServer ( u * url . URL , options ... roundrobin . ServerOption ) error {
return nil
}
func ( lb * testLoadBalancer ) Servers ( ) [ ] * url . URL {
return [ ] * url . URL { }
}
2017-05-09 15:31:16 -05:00
func TestServerMultipleFrontendRules ( t * testing . T ) {
cases := [ ] struct {
expression string
requestURL string
expectedURL string
} {
{
expression : "Host:foo.bar" ,
requestURL : "http://foo.bar" ,
expectedURL : "http://foo.bar" ,
} ,
{
expression : "PathPrefix:/management;ReplacePath:/health" ,
requestURL : "http://foo.bar/management" ,
expectedURL : "http://foo.bar/health" ,
} ,
{
expression : "Host:foo.bar;AddPrefix:/blah" ,
requestURL : "http://foo.bar/baz" ,
expectedURL : "http://foo.bar/blah/baz" ,
} ,
{
expression : "PathPrefixStripRegex:/one/{two}/{three:[0-9]+}" ,
requestURL : "http://foo.bar/one/some/12345/four" ,
expectedURL : "http://foo.bar/four" ,
} ,
{
expression : "PathPrefixStripRegex:/one/{two}/{three:[0-9]+};AddPrefix:/zero" ,
requestURL : "http://foo.bar/one/some/12345/four" ,
expectedURL : "http://foo.bar/zero/four" ,
} ,
{
expression : "AddPrefix:/blah;ReplacePath:/baz" ,
requestURL : "http://foo.bar/hello" ,
expectedURL : "http://foo.bar/baz" ,
} ,
{
expression : "PathPrefixStrip:/management;ReplacePath:/health" ,
requestURL : "http://foo.bar/management" ,
expectedURL : "http://foo.bar/health" ,
} ,
}
for _ , test := range cases {
test := test
t . Run ( test . expression , func ( t * testing . T ) {
t . Parallel ( )
router := mux . NewRouter ( )
route := router . NewRoute ( )
serverRoute := & serverRoute { route : route }
rules := & Rules { route : serverRoute }
expression := test . expression
routeResult , err := rules . Parse ( expression )
if err != nil {
t . Fatalf ( "Error while building route for %s: %+v" , expression , err )
}
request := testhelpers . MustNewRequest ( http . MethodGet , test . requestURL , nil )
routeMatch := routeResult . Match ( request , & mux . RouteMatch { Route : routeResult } )
if ! routeMatch {
t . Fatalf ( "Rule %s doesn't match" , expression )
}
server := new ( Server )
server . wireFrontendBackend ( serverRoute , http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
if r . URL . String ( ) != test . expectedURL {
t . Fatalf ( "got URL %s, expected %s" , r . URL . String ( ) , test . expectedURL )
}
} ) )
serverRoute . route . GetHandler ( ) . ServeHTTP ( nil , request )
} )
}
}
2017-03-15 19:16:06 +01:00
func TestServerLoadConfigHealthCheckOptions ( t * testing . T ) {
healthChecks := [ ] * types . HealthCheck {
nil ,
{
Path : "/path" ,
} ,
}
for _ , lbMethod := range [ ] string { "Wrr" , "Drr" } {
for _ , healthCheck := range healthChecks {
t . Run ( fmt . Sprintf ( "%s/hc=%t" , lbMethod , healthCheck != nil ) , func ( t * testing . T ) {
globalConfig := GlobalConfiguration {
EntryPoints : EntryPoints {
"http" : & EntryPoint { } ,
} ,
2017-03-24 09:36:33 +01:00
HealthCheck : & HealthCheckConfig { Interval : flaeg . Duration ( 5 * time . Second ) } ,
2017-03-15 19:16:06 +01:00
}
dynamicConfigs := configs {
"config" : & types . Configuration {
Frontends : map [ string ] * types . Frontend {
"frontend" : {
EntryPoints : [ ] string { "http" } ,
Backend : "backend" ,
} ,
} ,
Backends : map [ string ] * types . Backend {
"backend" : {
Servers : map [ string ] types . Server {
"server" : {
URL : "http://localhost" ,
} ,
} ,
LoadBalancer : & types . LoadBalancer {
Method : lbMethod ,
} ,
HealthCheck : healthCheck ,
} ,
} ,
} ,
}
srv := NewServer ( globalConfig )
if _ , err := srv . loadConfig ( dynamicConfigs , globalConfig ) ; err != nil {
t . Fatalf ( "got error: %s" , err )
}
wantNumHealthCheckBackends := 0
if healthCheck != nil {
wantNumHealthCheckBackends = 1
}
gotNumHealthCheckBackends := len ( healthcheck . GetHealthCheck ( ) . Backends )
if gotNumHealthCheckBackends != wantNumHealthCheckBackends {
t . Errorf ( "got %d health check backends, want %d" , gotNumHealthCheckBackends , wantNumHealthCheckBackends )
}
} )
}
}
}
func TestServerParseHealthCheckOptions ( t * testing . T ) {
lb := & testLoadBalancer { }
2017-03-24 09:36:33 +01:00
globalInterval := 15 * time . Second
2017-03-15 19:16:06 +01:00
tests := [ ] struct {
desc string
hc * types . HealthCheck
wantOpts * healthcheck . Options
} {
{
desc : "nil health check" ,
hc : nil ,
wantOpts : nil ,
} ,
{
desc : "empty path" ,
hc : & types . HealthCheck {
Path : "" ,
} ,
wantOpts : nil ,
} ,
{
desc : "unparseable interval" ,
hc : & types . HealthCheck {
Path : "/path" ,
Interval : "unparseable" ,
} ,
wantOpts : & healthcheck . Options {
Path : "/path" ,
2017-03-24 09:36:33 +01:00
Interval : globalInterval ,
2017-03-15 19:16:06 +01:00
LB : lb ,
} ,
} ,
{
desc : "sub-zero interval" ,
hc : & types . HealthCheck {
Path : "/path" ,
2017-03-24 09:36:33 +01:00
Interval : "-42s" ,
2017-03-15 19:16:06 +01:00
} ,
wantOpts : & healthcheck . Options {
Path : "/path" ,
2017-03-24 09:36:33 +01:00
Interval : globalInterval ,
2017-03-15 19:16:06 +01:00
LB : lb ,
} ,
} ,
{
desc : "parseable interval" ,
hc : & types . HealthCheck {
Path : "/path" ,
Interval : "5m" ,
} ,
wantOpts : & healthcheck . Options {
Path : "/path" ,
Interval : 5 * time . Minute ,
LB : lb ,
} ,
} ,
}
for _ , test := range tests {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
2017-05-15 09:02:32 +02:00
gotOpts := parseHealthCheckOptions ( lb , "backend" , test . hc , & HealthCheckConfig { Interval : flaeg . Duration ( globalInterval ) } )
2017-03-15 19:16:06 +01:00
if ! reflect . DeepEqual ( gotOpts , test . wantOpts ) {
t . Errorf ( "got health check options %+v, want %+v" , gotOpts , test . wantOpts )
}
} )
}
}
2017-05-15 09:02:32 +02:00
func TestServerLoadConfigEmptyBasicAuth ( t * testing . T ) {
globalConfig := GlobalConfiguration {
EntryPoints : EntryPoints {
"http" : & EntryPoint { } ,
} ,
}
dynamicConfigs := configs {
"config" : & types . Configuration {
Frontends : map [ string ] * types . Frontend {
"frontend" : {
EntryPoints : [ ] string { "http" } ,
Backend : "backend" ,
BasicAuth : [ ] string { "" } ,
} ,
} ,
Backends : map [ string ] * types . Backend {
"backend" : {
Servers : map [ string ] types . Server {
"server" : {
URL : "http://localhost" ,
} ,
} ,
LoadBalancer : & types . LoadBalancer {
Method : "Wrr" ,
} ,
} ,
} ,
} ,
}
srv := NewServer ( globalConfig )
if _ , err := srv . loadConfig ( dynamicConfigs , globalConfig ) ; err != nil {
t . Fatalf ( "got error: %s" , err )
}
}
2017-05-11 00:34:47 +02:00
func TestConfigureBackends ( t * testing . T ) {
validMethod := "Drr"
defaultMethod := "wrr"
tests := [ ] struct {
desc string
lb * types . LoadBalancer
wantMethod string
wantSticky bool
} {
{
desc : "valid load balancer method with sticky enabled" ,
lb : & types . LoadBalancer {
Method : validMethod ,
Sticky : true ,
} ,
wantMethod : validMethod ,
wantSticky : true ,
} ,
{
desc : "valid load balancer method with sticky disabled" ,
lb : & types . LoadBalancer {
Method : validMethod ,
Sticky : false ,
} ,
wantMethod : validMethod ,
wantSticky : false ,
} ,
{
desc : "invalid load balancer method with sticky enabled" ,
lb : & types . LoadBalancer {
Method : "Invalid" ,
Sticky : true ,
} ,
wantMethod : defaultMethod ,
wantSticky : true ,
} ,
{
desc : "invalid load balancer method with sticky disabled" ,
lb : & types . LoadBalancer {
Method : "Invalid" ,
Sticky : false ,
} ,
wantMethod : defaultMethod ,
wantSticky : false ,
} ,
{
desc : "missing load balancer" ,
lb : nil ,
wantMethod : defaultMethod ,
wantSticky : false ,
} ,
}
for _ , test := range tests {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
backend := & types . Backend {
LoadBalancer : test . lb ,
}
2017-05-15 23:53:35 +02:00
srv := Server { }
srv . configureBackends ( map [ string ] * types . Backend {
2017-05-11 00:34:47 +02:00
"backend" : backend ,
} )
wantLB := types . LoadBalancer {
Method : test . wantMethod ,
Sticky : test . wantSticky ,
}
if ! reflect . DeepEqual ( * backend . LoadBalancer , wantLB ) {
t . Errorf ( "got backend load-balancer\n%v\nwant\n%v\n" , spew . Sdump ( backend . LoadBalancer ) , spew . Sdump ( wantLB ) )
}
} )
}
}