traefik/pkg/provider/kubernetes/gateway/httproute_test.go
Kevin Pollet c0a2e6b4b6
Compute HTTPRoute priorities
Co-authored-by: Romain <rtribotte@users.noreply.github.com>
2024-05-30 09:14:04 +02:00

280 lines
6.4 KiB
Go

package gateway
import (
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/utils/ptr"
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
)
func Test_buildHostRule(t *testing.T) {
testCases := []struct {
desc string
hostnames []gatev1.Hostname
expectedRule string
expectedPriority int
expectErr bool
}{
{
desc: "Empty (should not happen)",
expectedRule: "",
},
{
desc: "One Host",
hostnames: []gatev1.Hostname{
"Foo",
},
expectedRule: "Host(`Foo`)",
expectedPriority: 3,
},
{
desc: "Multiple Hosts",
hostnames: []gatev1.Hostname{
"Foo",
"Bar",
"Bir",
},
expectedRule: "(Host(`Foo`) || Host(`Bar`) || Host(`Bir`))",
expectedPriority: 3,
},
{
desc: "Several Host and wildcard",
hostnames: []gatev1.Hostname{
"*.bar.foo",
"bar.foo",
"foo.foo",
},
expectedRule: "(HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.foo$`) || Host(`bar.foo`) || Host(`foo.foo`))",
expectedPriority: 9,
},
{
desc: "Host with wildcard",
hostnames: []gatev1.Hostname{
"*.bar.foo",
},
expectedRule: "HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.foo$`)",
expectedPriority: 9,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
rule, priority := buildHostRule(test.hostnames)
assert.Equal(t, test.expectedRule, rule)
assert.Equal(t, test.expectedPriority, priority)
})
}
}
func Test_buildRouterRule(t *testing.T) {
testCases := []struct {
desc string
routeMatches []gatev1.HTTPRouteMatch
hostnames []gatev1.Hostname
expectedRule string
expectedPriority int
expectedError bool
}{
{
desc: "Empty rule and matches ",
expectedRule: "PathPrefix(`/`)",
expectedPriority: 1,
},
{
desc: "One Host rule without matches",
hostnames: []gatev1.Hostname{"foo.com"},
expectedRule: "Host(`foo.com`)",
expectedPriority: 7,
},
{
desc: "One HTTPRouteMatch with nil HTTPHeaderMatch",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: ptr.To(gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchPathPrefix),
Value: ptr.To("/"),
}),
Headers: nil,
},
},
expectedRule: "PathPrefix(`/`)",
expectedPriority: 1,
},
{
desc: "One HTTPRouteMatch with nil HTTPHeaderMatch Type",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: ptr.To(gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchPathPrefix),
Value: ptr.To("/"),
}),
Headers: []gatev1.HTTPHeaderMatch{
{Name: "foo", Value: "bar"},
},
},
},
expectedRule: "PathPrefix(`/`) && Header(`foo`,`bar`)",
expectedPriority: 91,
},
{
desc: "One HTTPRouteMatch with nil HTTPPathMatch",
routeMatches: []gatev1.HTTPRouteMatch{
{Path: nil},
},
expectedRule: "PathPrefix(`/`)",
expectedPriority: 1,
},
{
desc: "One HTTPRouteMatch with nil HTTPPathMatch Type",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: nil,
Value: ptr.To("/foo/"),
},
},
},
expectedRule: "(Path(`/foo`) || PathPrefix(`/foo/`))",
expectedPriority: 10490,
},
{
desc: "One HTTPRouteMatch with nil HTTPPathMatch Values",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchExact),
Value: nil,
},
},
},
expectedRule: "Path(`/`)",
expectedPriority: 99990,
},
{
desc: "One Path in matches",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchExact),
Value: ptr.To("/foo/"),
},
},
},
expectedRule: "Path(`/foo/`)",
expectedPriority: 99990,
},
{
desc: "One Path in matches and another empty",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchExact),
Value: ptr.To("/foo/"),
},
},
{},
},
expectedRule: "Path(`/foo/`) || PathPrefix(`/`)",
expectedPriority: 99980,
},
{
desc: "Path OR Header rules",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchExact),
Value: ptr.To("/foo/"),
},
},
{
Headers: []gatev1.HTTPHeaderMatch{
{
Type: ptr.To(gatev1.HeaderMatchExact),
Name: "my-header",
Value: "foo",
},
},
},
},
expectedRule: "Path(`/foo/`) || PathPrefix(`/`) && Header(`my-header`,`foo`)",
expectedPriority: 99980,
},
{
desc: "Path && Header rules",
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchExact),
Value: ptr.To("/foo/"),
},
Headers: []gatev1.HTTPHeaderMatch{
{
Type: ptr.To(gatev1.HeaderMatchExact),
Name: "my-header",
Value: "foo",
},
},
},
},
expectedRule: "Path(`/foo/`) && Header(`my-header`,`foo`)",
expectedPriority: 100090,
},
{
desc: "Host && Path && Header rules",
hostnames: []gatev1.Hostname{"foo.com"},
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchExact),
Value: ptr.To("/foo/"),
},
Headers: []gatev1.HTTPHeaderMatch{
{
Type: ptr.To(gatev1.HeaderMatchExact),
Name: "my-header",
Value: "foo",
},
},
},
},
expectedRule: "Host(`foo.com`) && (Path(`/foo/`) && Header(`my-header`,`foo`))",
expectedPriority: 100097,
},
{
desc: "Host && (Path || Header) rules",
hostnames: []gatev1.Hostname{"foo.com"},
routeMatches: []gatev1.HTTPRouteMatch{
{
Path: &gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchExact),
Value: ptr.To("/foo/"),
},
},
{
Headers: []gatev1.HTTPHeaderMatch{
{
Type: ptr.To(gatev1.HeaderMatchExact),
Name: "my-header",
Value: "foo",
},
},
},
},
expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || PathPrefix(`/`) && Header(`my-header`,`foo`))",
expectedPriority: 99987,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
rule, priority := buildRouterRule(test.hostnames, test.routeMatches)
assert.Equal(t, test.expectedRule, rule)
assert.Equal(t, test.expectedPriority, priority)
})
}
}