2018-02-26 17:34:04 +03:00
package rules
2016-06-06 16:27:16 +03:00
import (
"net/http"
2016-06-06 23:40:42 +03:00
"net/url"
2016-06-06 16:27:16 +03:00
"testing"
2017-04-17 23:47:53 +03:00
"github.com/containous/mux"
2018-07-09 16:08:04 +03:00
"github.com/containous/traefik/middlewares"
2017-06-03 15:58:35 +03:00
"github.com/containous/traefik/testhelpers"
2018-02-26 17:34:04 +03:00
"github.com/containous/traefik/types"
2017-05-28 06:50:03 +03:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2016-06-06 16:27:16 +03:00
)
func TestParseOneRule ( t * testing . T ) {
2018-07-09 16:08:04 +03:00
reqHostMid := & middlewares . RequestHost { }
rules := & Rules {
Route : & types . ServerRoute {
Route : mux . NewRouter ( ) . NewRoute ( ) ,
} ,
}
2016-06-06 16:27:16 +03:00
expression := "Host:foo.bar"
2018-07-09 16:08:04 +03:00
2016-06-06 16:27:16 +03:00
routeResult , err := rules . Parse ( expression )
2017-05-28 06:50:03 +03:00
require . NoError ( t , err , "Error while building route for %s" , expression )
2016-06-06 16:27:16 +03:00
2017-06-03 15:58:35 +03:00
request := testhelpers . MustNewRequest ( http . MethodGet , "http://foo.bar" , nil )
2016-06-06 16:27:16 +03:00
2018-07-09 16:08:04 +03:00
reqHostMid . ServeHTTP ( nil , request , func ( w http . ResponseWriter , r * http . Request ) {
routeMatch := routeResult . Match ( r , & mux . RouteMatch { Route : routeResult } )
assert . True ( t , routeMatch , "Rule %s don't match." , expression )
} )
2016-06-06 16:27:16 +03:00
}
func TestParseTwoRules ( t * testing . T ) {
2018-07-09 16:08:04 +03:00
reqHostMid := & middlewares . RequestHost { }
rules := & Rules {
Route : & types . ServerRoute {
Route : mux . NewRouter ( ) . NewRoute ( ) ,
} ,
}
2016-06-06 16:27:16 +03:00
2016-10-14 17:04:09 +03:00
expression := "Host: Foo.Bar ; Path:/FOObar"
2016-06-06 16:27:16 +03:00
2018-07-09 16:08:04 +03:00
routeResult , err := rules . Parse ( expression )
2017-05-28 06:50:03 +03:00
require . NoError ( t , err , "Error while building route for %s." , expression )
2016-06-06 16:27:16 +03:00
2017-06-03 15:58:35 +03:00
request := testhelpers . MustNewRequest ( http . MethodGet , "http://foo.bar/foobar" , nil )
2018-07-09 16:08:04 +03:00
reqHostMid . ServeHTTP ( nil , request , func ( w http . ResponseWriter , r * http . Request ) {
routeMatch := routeResult . Match ( r , & mux . RouteMatch { Route : routeResult } )
assert . False ( t , routeMatch , "Rule %s don't match." , expression )
} )
2016-11-17 17:36:10 +03:00
2017-06-03 15:58:35 +03:00
request = testhelpers . MustNewRequest ( http . MethodGet , "http://foo.bar/FOObar" , nil )
2018-07-09 16:08:04 +03:00
reqHostMid . ServeHTTP ( nil , request , func ( w http . ResponseWriter , r * http . Request ) {
routeMatch := routeResult . Match ( r , & mux . RouteMatch { Route : routeResult } )
assert . True ( t , routeMatch , "Rule %s don't match." , expression )
} )
2016-06-06 16:27:16 +03:00
}
2016-06-06 15:54:45 +03:00
2016-08-05 21:42:45 +03:00
func TestParseDomains ( t * testing . T ) {
rules := & Rules { }
2017-05-28 06:50:03 +03:00
tests := [ ] struct {
2018-09-04 18:14:04 +03:00
description string
expression string
domain [ ] string
errorExpected bool
2017-05-28 06:50:03 +03:00
} {
{
2018-09-04 18:14:04 +03:00
description : "Many host rules" ,
expression : "Host:foo.bar,test.bar" ,
domain : [ ] string { "foo.bar" , "test.bar" } ,
errorExpected : false ,
2017-05-28 06:50:03 +03:00
} ,
{
2018-09-04 18:14:04 +03:00
description : "No host rule" ,
expression : "Path:/test" ,
errorExpected : false ,
2017-05-28 06:50:03 +03:00
} ,
{
2018-09-04 18:14:04 +03:00
description : "Host rule and another rule" ,
expression : "Host:foo.bar;Path:/test" ,
domain : [ ] string { "foo.bar" } ,
errorExpected : false ,
2017-05-28 06:50:03 +03:00
} ,
{
2018-09-04 18:14:04 +03:00
description : "Host rule to trim and another rule" ,
expression : "Host: Foo.Bar ;Path:/test" ,
domain : [ ] string { "foo.bar" } ,
errorExpected : false ,
} ,
{
description : "Host rule with no domain" ,
expression : "Host: ;Path:/test" ,
errorExpected : true ,
2017-05-28 06:50:03 +03:00
} ,
}
for _ , test := range tests {
test := test
t . Run ( test . expression , func ( t * testing . T ) {
t . Parallel ( )
domains , err := rules . ParseDomains ( test . expression )
2018-09-04 18:14:04 +03:00
if test . errorExpected {
require . Errorf ( t , err , "unable to parse correctly the domains in the Host rule from %q" , test . expression )
} else {
require . NoError ( t , err , "%s: Error while parsing domain." , test . expression )
}
2017-05-28 06:50:03 +03:00
assert . EqualValues ( t , test . domain , domains , "%s: Error parsing domains from expression." , test . expression )
} )
2016-08-05 21:42:45 +03:00
}
}
2016-06-06 15:54:45 +03:00
func TestPriorites ( t * testing . T ) {
router := mux . NewRouter ( )
router . StrictSlash ( true )
2018-07-09 16:08:04 +03:00
2018-02-26 17:34:04 +03:00
rules := & Rules { Route : & types . ServerRoute { Route : router . NewRoute ( ) } }
2017-05-28 06:50:03 +03:00
expression01 := "PathPrefix:/foo"
routeFoo , err := rules . Parse ( expression01 )
require . NoError ( t , err , "Error while building route for %s" , expression01 )
2016-06-06 15:54:45 +03:00
fooHandler := & fakeHandler { name : "fooHandler" }
routeFoo . Handler ( fooHandler )
2017-05-28 06:50:03 +03:00
routeMatch := router . Match ( & http . Request { URL : & url . URL { Path : "/foo" } } , & mux . RouteMatch { } )
assert . True ( t , routeMatch , "Error matching route" )
2016-06-06 15:54:45 +03:00
2017-05-28 06:50:03 +03:00
routeMatch = router . Match ( & http . Request { URL : & url . URL { Path : "/fo" } } , & mux . RouteMatch { } )
assert . False ( t , routeMatch , "Error matching route" )
2016-06-06 15:54:45 +03:00
2018-02-26 17:34:04 +03:00
multipleRules := & Rules { Route : & types . ServerRoute { Route : router . NewRoute ( ) } }
2017-05-28 06:50:03 +03:00
expression02 := "PathPrefix:/foobar"
routeFoobar , err := multipleRules . Parse ( expression02 )
require . NoError ( t , err , "Error while building route for %s" , expression02 )
2016-06-06 15:54:45 +03:00
foobarHandler := & fakeHandler { name : "foobarHandler" }
routeFoobar . Handler ( foobarHandler )
2017-05-28 06:50:03 +03:00
routeMatch = router . Match ( & http . Request { URL : & url . URL { Path : "/foo" } } , & mux . RouteMatch { } )
2016-06-06 15:54:45 +03:00
2017-05-28 06:50:03 +03:00
assert . True ( t , routeMatch , "Error matching route" )
2016-06-06 15:54:45 +03:00
2017-05-28 06:50:03 +03:00
fooMatcher := & mux . RouteMatch { }
routeMatch = router . Match ( & http . Request { URL : & url . URL { Path : "/foobar" } } , fooMatcher )
assert . True ( t , routeMatch , "Error matching route" )
assert . NotEqual ( t , fooMatcher . Handler , foobarHandler , "Error matching priority" )
assert . Equal ( t , fooMatcher . Handler , fooHandler , "Error matching priority" )
2016-06-06 15:54:45 +03:00
routeFoo . Priority ( 1 )
routeFoobar . Priority ( 10 )
router . SortRoutes ( )
foobarMatcher := & mux . RouteMatch { }
2017-05-28 06:50:03 +03:00
routeMatch = router . Match ( & http . Request { URL : & url . URL { Path : "/foobar" } } , foobarMatcher )
2016-06-06 15:54:45 +03:00
2017-05-28 06:50:03 +03:00
assert . True ( t , routeMatch , "Error matching route" )
assert . Equal ( t , foobarMatcher . Handler , foobarHandler , "Error matching priority" )
assert . NotEqual ( t , foobarMatcher . Handler , fooHandler , "Error matching priority" )
2016-06-06 15:54:45 +03:00
}
2017-10-23 11:20:02 +03:00
func TestHostRegexp ( t * testing . T ) {
testCases := [ ] struct {
desc string
hostExp string
urls map [ string ] bool
} {
{
desc : "capturing group" ,
hostExp : "{subdomain:(foo\\.)?bar\\.com}" ,
urls : map [ string ] bool {
"http://foo.bar.com" : true ,
"http://bar.com" : true ,
"http://fooubar.com" : false ,
"http://barucom" : false ,
"http://barcom" : false ,
} ,
} ,
{
desc : "non capturing group" ,
hostExp : "{subdomain:(?:foo\\.)?bar\\.com}" ,
urls : map [ string ] bool {
"http://foo.bar.com" : true ,
"http://bar.com" : true ,
"http://fooubar.com" : false ,
"http://barucom" : false ,
"http://barcom" : false ,
} ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
rls := & Rules {
2018-02-26 17:34:04 +03:00
Route : & types . ServerRoute {
Route : & mux . Route { } ,
2017-10-23 11:20:02 +03:00
} ,
}
rt := rls . hostRegexp ( test . hostExp )
for testURL , match := range test . urls {
req := testhelpers . MustNewRequest ( http . MethodGet , testURL , nil )
assert . Equal ( t , match , rt . Match ( req , & mux . RouteMatch { } ) )
}
} )
}
}
2018-10-04 11:20:03 +03:00
func TestParseInvalidSyntax ( t * testing . T ) {
router := mux . NewRouter ( )
router . StrictSlash ( true )
2016-06-06 15:54:45 +03:00
2018-10-04 11:20:03 +03:00
rules := & Rules { Route : & types . ServerRoute { Route : router . NewRoute ( ) } }
expression01 := "Path: /path1;Query:param_one=true, /path2"
routeFoo , err := rules . Parse ( expression01 )
require . Error ( t , err )
assert . Nil ( t , routeFoo )
}
2017-12-19 19:00:12 +03:00
func TestPathPrefix ( t * testing . T ) {
testCases := [ ] struct {
desc string
path string
urls map [ string ] bool
} {
{
desc : "leading slash" ,
path : "/bar" ,
urls : map [ string ] bool {
"http://foo.com/bar" : true ,
"http://foo.com/bar/" : true ,
} ,
} ,
{
desc : "leading trailing slash" ,
path : "/bar/" ,
urls : map [ string ] bool {
"http://foo.com/bar" : false ,
"http://foo.com/bar/" : true ,
} ,
} ,
{
desc : "no slash" ,
path : "bar" ,
urls : map [ string ] bool {
"http://foo.com/bar" : false ,
"http://foo.com/bar/" : false ,
} ,
} ,
{
desc : "trailing slash" ,
path : "bar/" ,
urls : map [ string ] bool {
"http://foo.com/bar" : false ,
"http://foo.com/bar/" : false ,
} ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
rls := & Rules {
2018-02-26 17:34:04 +03:00
Route : & types . ServerRoute {
Route : & mux . Route { } ,
2017-12-19 19:00:12 +03:00
} ,
}
rt := rls . pathPrefix ( test . path )
for testURL , expectedMatch := range test . urls {
req := testhelpers . MustNewRequest ( http . MethodGet , testURL , nil )
match := rt . Match ( req , & mux . RouteMatch { } )
if match != expectedMatch {
t . Errorf ( "Error matching %s with %s, got %v expected %v" , test . path , testURL , match , expectedMatch )
}
}
} )
}
}
2018-10-04 11:20:03 +03:00
type fakeHandler struct {
name string
}
func ( h * fakeHandler ) ServeHTTP ( http . ResponseWriter , * http . Request ) { }