consul/agent/structs/config_entry_routes_test.go
hashicorp-copywrite[bot] 5fb9df1640
[COMPLIANCE] License changes (#18443)
* Adding explicit MPL license for sub-package

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Adding explicit MPL license for sub-package

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Updating the license from MPL to Business Source License

Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at <Blog URL>, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl.

* add missing license headers

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

* Update copyright file headers to BUSL-1.1

---------

Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-08-11 09:12:13 -04:00

440 lines
10 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package structs
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/acl"
)
func TestTCPRoute(t *testing.T) {
t.Parallel()
cases := map[string]configEntryTestcase{
"multiple services": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-one",
Services: []TCPService{{
Name: "foo",
}, {
Name: "bar",
}},
},
validateErr: "tcp-route currently only supports one service",
},
"normalize parent kind": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Services: []TCPService{{
Name: "foo",
}},
},
normalizeOnly: true,
check: func(t *testing.T, entry ConfigEntry) {
expectedParent := ResourceReference{
Kind: APIGateway,
Name: "gateway",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
}
route := entry.(*TCPRouteConfigEntry)
require.Len(t, route.Parents, 1)
require.Equal(t, expectedParent, route.Parents[0])
},
},
"invalid parent kind": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Kind: "route",
Name: "gateway",
}},
},
validateErr: "unsupported parent kind",
},
"duplicate parents with no listener specified": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
},
},
},
validateErr: "route parents must be unique",
},
"duplicate parents with listener specified": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
validateErr: "route parents must be unique",
},
"almost duplicate parents with one not specifying a listener": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
check: func(t *testing.T, entry ConfigEntry) {
expectedParents := []ResourceReference{
{
Kind: APIGateway,
Name: "gateway",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
{
Kind: APIGateway,
Name: "gateway",
SectionName: "same",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
}
route := entry.(*TCPRouteConfigEntry)
require.Len(t, route.Parents, 2)
require.Equal(t, expectedParents[0], route.Parents[0])
require.Equal(t, expectedParents[1], route.Parents[1])
},
},
}
testConfigEntryNormalizeAndValidate(t, cases)
}
func TestHTTPRoute(t *testing.T) {
t.Parallel()
cases := map[string]configEntryTestcase{
"normalize parent kind": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-one",
Parents: []ResourceReference{{
Name: "gateway",
}},
},
normalizeOnly: true,
check: func(t *testing.T, entry ConfigEntry) {
expectedParent := ResourceReference{
Kind: APIGateway,
Name: "gateway",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
}
route := entry.(*HTTPRouteConfigEntry)
require.Len(t, route.Parents, 1)
require.Equal(t, expectedParent, route.Parents[0])
},
},
"invalid parent kind": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Kind: "route",
Name: "gateway",
}},
},
validateErr: "unsupported parent kind",
},
"wildcard hostnames": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Hostnames: []string{"*"},
},
validateErr: "host \"*\" must not be a wildcard",
},
"wildcard subdomain": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Hostnames: []string{"*.consul.example"},
},
validateErr: "host \"*.consul.example\" must not be a wildcard",
},
"valid dns hostname": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Hostnames: []string{"...not legal"},
},
validateErr: "host \"...not legal\" must be a valid DNS hostname",
},
"rule matches invalid header match type": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Headers: []HTTPHeaderMatch{{
Match: HTTPHeaderMatchType("foo"),
Name: "foo",
}},
}},
}},
},
validateErr: "Rule[0], Match[0], Headers[0], match type should be one of present, exact, prefix, suffix, or regex",
},
"rule matches invalid header match name": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Headers: []HTTPHeaderMatch{{
Match: HTTPHeaderMatchPresent,
}},
}},
}},
},
validateErr: "Rule[0], Match[0], Headers[0], missing required Name field",
},
"rule matches invalid query match type": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Query: []HTTPQueryMatch{{
Match: HTTPQueryMatchType("foo"),
Name: "foo",
}},
}},
}},
},
validateErr: "Rule[0], Match[0], Query[0], match type should be one of present, exact, or regex",
},
"rule matches invalid query match name": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Query: []HTTPQueryMatch{{
Match: HTTPQueryMatchPresent,
}},
}},
}},
},
validateErr: "Rule[0], Match[0], Query[0], missing required Name field",
},
"rule matches invalid path match type": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Path: HTTPPathMatch{
Match: HTTPPathMatchType("foo"),
},
}},
}},
},
validateErr: "Rule[0], Match[0], Path, match type should be one of exact, prefix, or regex",
},
"rule matches invalid path match prefix": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Path: HTTPPathMatch{
Match: HTTPPathMatchPrefix,
},
}},
}},
},
validateErr: "Rule[0], Match[0], Path, prefix type match doesn't start with '/': \"\"",
},
"rule matches invalid method": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Method: HTTPMatchMethod("foo"),
}},
}},
},
validateErr: "Rule[0], Match[0], Method contains an invalid method \"FOO\"",
},
"rule normalizes method casing and path matches": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{{
Name: "gateway",
}},
Rules: []HTTPRouteRule{{
Matches: []HTTPMatch{{
Method: HTTPMatchMethod("trace"),
}},
}},
},
},
"rule normalizes service weight": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-one",
Rules: []HTTPRouteRule{{
Services: []HTTPService{
{
Name: "test",
Weight: 0,
},
{
Name: "test2",
Weight: -1,
},
},
}},
},
check: func(t *testing.T, entry ConfigEntry) {
route := entry.(*HTTPRouteConfigEntry)
require.Equal(t, 1, route.Rules[0].Services[0].Weight)
require.Equal(t, 1, route.Rules[0].Services[1].Weight)
},
},
"duplicate parents with no listener specified": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
},
},
},
validateErr: "route parents must be unique",
},
"duplicate parents with listener specified": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
validateErr: "route parents must be unique",
},
"almost duplicate parents with one not specifying a listener": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
check: func(t *testing.T, entry ConfigEntry) {
expectedParents := []ResourceReference{
{
Kind: APIGateway,
Name: "gateway",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
{
Kind: APIGateway,
Name: "gateway",
SectionName: "same",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
}
route := entry.(*HTTPRouteConfigEntry)
require.Len(t, route.Parents, 2)
require.Equal(t, expectedParents[0], route.Parents[0])
require.Equal(t, expectedParents[1], route.Parents[1])
},
},
}
testConfigEntryNormalizeAndValidate(t, cases)
}