From ba636b0de331db7f9d8c0bb3715bd2e4648d5370 Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Thu, 7 Dec 2023 10:44:51 +0100 Subject: [PATCH] test(unit): groupPaths func tested Signed-off-by: Mattia Lavacca --- go.mod | 9 +- go.sum | 1 + pkg/i2gw/providers/common/converter.go | 5 - pkg/i2gw/providers/common/utils.go | 5 + pkg/i2gw/providers/common/utils_test.go | 527 ++++++++++++++++++++++++ 5 files changed, 540 insertions(+), 7 deletions(-) create mode 100644 pkg/i2gw/providers/common/utils_test.go diff --git a/go.mod b/go.mod index ea9120f3..dbed8540 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/google/go-cmp v0.6.0 github.com/spf13/cobra v1.8.0 - istio.io/api v1.20.0 + github.com/stretchr/testify v1.8.4 k8s.io/api v0.28.4 k8s.io/apimachinery v0.28.4 k8s.io/cli-runtime v0.28.4 @@ -15,6 +15,11 @@ require ( sigs.k8s.io/gateway-api v0.5.0 ) +require ( + github.com/pmezard/go-difflib v1.0.0 // indirect + istio.io/api v1.20.0 // indirect +) + require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect @@ -63,7 +68,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - istio.io/client-go v1.19.0-alpha.1.0.20231130185426-9f1859c8ff42 // indirect + istio.io/client-go v1.19.0-alpha.1.0.20231130185426-9f1859c8ff42 k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20231113174909-778a5567bc1e // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect diff --git a/go.sum b/go.sum index 6857a044..f5210f33 100644 --- a/go.sum +++ b/go.sum @@ -109,6 +109,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/pkg/i2gw/providers/common/converter.go b/pkg/i2gw/providers/common/converter.go index 5e02b547..fe1de6cc 100644 --- a/pkg/i2gw/providers/common/converter.go +++ b/pkg/i2gw/providers/common/converter.go @@ -268,11 +268,6 @@ func (a *ingressAggregator) toHTTPRoutesAndGateways(options i2gw.ProviderImpleme return httpRoutes, gateways, errors } -type pathsByMatchGroupType struct { - key string - paths []ingressPath -} - func (rg *ingressRuleGroup) toHTTPRoute(options i2gw.ProviderImplementationSpecificOptions) (gatewayv1beta1.HTTPRoute, field.ErrorList) { pathsByMatchGroup := groupPaths(rg.rules) httpRoute := gatewayv1beta1.HTTPRoute{ diff --git a/pkg/i2gw/providers/common/utils.go b/pkg/i2gw/providers/common/utils.go index 533892bc..ad70041f 100644 --- a/pkg/i2gw/providers/common/utils.go +++ b/pkg/i2gw/providers/common/utils.go @@ -127,6 +127,11 @@ func ToBackendRef(ib networkingv1.IngressBackend, path *field.Path) (*gatewayv1b }, nil } +type pathsByMatchGroupType struct { + key string + paths []ingressPath +} + func groupPaths(rules []ingressRule) []pathsByMatchGroupType { // we use a slice instead of a map to preserve rules order pathsByMatchGroup := []pathsByMatchGroupType{} diff --git a/pkg/i2gw/providers/common/utils_test.go b/pkg/i2gw/providers/common/utils_test.go new file mode 100644 index 00000000..ff30adb7 --- /dev/null +++ b/pkg/i2gw/providers/common/utils_test.go @@ -0,0 +1,527 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "testing" + + "github.com/stretchr/testify/require" + networkingv1 "k8s.io/api/networking/v1" +) + +func TestGroupPaths(t *testing.T) { + iPrefix := networkingv1.PathTypePrefix + + testCases := []struct { + name string + rules []ingressRule + expected []pathsByMatchGroupType + }{ + { + name: "no rules", + rules: []ingressRule{}, + expected: []pathsByMatchGroupType{}, + }, + { + name: "1 rule with 1 match", + rules: []ingressRule{ + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + expected: []pathsByMatchGroupType{ + { + key: "Prefix//test", + paths: []ingressPath{ + { + ruleIdx: 0, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "1 rule, multiple matches, different path", + rules: []ingressRule{ + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test1", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test1", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + { + Path: "/test2", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test2", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + expected: []pathsByMatchGroupType{ + { + key: "Prefix//test1", + paths: []ingressPath{ + { + ruleIdx: 0, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test1", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test1", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + { + key: "Prefix//test2", + paths: []ingressPath{ + { + ruleIdx: 0, + pathIdx: 1, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test2", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test2", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "multiple rules with single matches, same path", + rules: []ingressRule{ + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + expected: []pathsByMatchGroupType{ + { + key: "Prefix//test", + paths: []ingressPath{ + { + ruleIdx: 0, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + { + ruleIdx: 1, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "multiple rules with single matches, different path", + rules: []ingressRule{ + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test2", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test2", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + expected: []pathsByMatchGroupType{ + { + key: "Prefix//test", + paths: []ingressPath{ + { + ruleIdx: 0, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + { + key: "Prefix//test2", + paths: []ingressPath{ + { + ruleIdx: 1, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test2", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test2", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "multiple rules with multiple matches, mixed paths", + rules: []ingressRule{ + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test11", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test11", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + { + Path: "/test12", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test12", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + networkingv1.IngressRule{ + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/test21", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test21", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + { + Path: "/test11", + PathType: PtrTo(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test11", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + expected: []pathsByMatchGroupType{ + { + key: "Prefix//test11", + paths: []ingressPath{ + { + ruleIdx: 0, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test11", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test11", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + { + ruleIdx: 1, + pathIdx: 1, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test11", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test11", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + }, + }, + }, + { + key: "Prefix//test12", + paths: []ingressPath{ + { + ruleIdx: 0, + pathIdx: 1, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test12", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test12", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + { + key: "Prefix//test21", + paths: []ingressPath{ + { + ruleIdx: 1, + pathIdx: 0, + ruleType: "http", + path: networkingv1.HTTPIngressPath{ + Path: "/test21", + PathType: &iPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test21", + Port: networkingv1.ServiceBackendPort{ + Number: 81, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + want := groupPaths(tc.rules) + require.Equal(t, want, tc.expected) + }) + } +}