Skip to content

Commit 5bd5b0d

Browse files
committed
some unit tests
1 parent f33b808 commit 5bd5b0d

File tree

16 files changed

+1142
-64
lines changed

16 files changed

+1142
-64
lines changed

pkg/gateway/routeutils/backend.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,38 @@ import (
1111
)
1212

1313
type Backend struct {
14-
Service *corev1.Service
15-
ServicePort *corev1.ServicePort
16-
Weight int
14+
Service *corev1.Service
15+
ServicePort *corev1.ServicePort
16+
TypeSpecificBackend interface{}
17+
Weight int
1718
// Add TG config here //
1819
}
1920

20-
func commonBackendLoader(ctx context.Context, k8sClient client.Client, backendRef gwv1.BackendRef, routeIdentifier types.NamespacedName, routeKind string) (*Backend, error) {
21+
// NOTE: Currently routeKind is not used, however, we will need it to load TG specific configuration.
22+
func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpecificBackend interface{}, backendRef gwv1.BackendRef, routeIdentifier types.NamespacedName, routeKind string) (*Backend, error) {
23+
24+
// We only support references of type service.
25+
if backendRef.Kind != nil && *backendRef.Kind != "Service" {
26+
return nil, nil
27+
}
28+
29+
if backendRef.Weight != nil && *backendRef.Weight == 0 {
30+
return nil, nil
31+
}
32+
2133
if backendRef.Port == nil {
2234
return nil, errors.Errorf("Missing port in backend reference")
2335
}
36+
2437
var namespace string
2538
if backendRef.Namespace == nil {
2639
namespace = routeIdentifier.Namespace
2740
} else {
2841
namespace = string(*backendRef.Namespace)
2942
}
3043

44+
// TODO - Need to implement reference grant check here
45+
3146
svcName := types.NamespacedName{
3247
Namespace: namespace,
3348
Name: string(backendRef.Name),
@@ -38,7 +53,6 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, backendRe
3853
return nil, errors.Wrap(err, fmt.Sprintf("Unable to fetch svc object %+v", svcName))
3954
}
4055

41-
// TODO -- Is this correct?
4256
var servicePort *corev1.ServicePort
4357

4458
for _, svcPort := range svc.Spec.Ports {
@@ -52,7 +66,7 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, backendRe
5266
return nil, errors.Errorf("Unable to find service port for port %d", *backendRef.Port)
5367
}
5468

55-
// look up target group config here
69+
// TODO - Need to TG CRD look up here
5670

5771
// Weight specifies the proportion of requests forwarded to the referenced
5872
// backend. This is computed as weight/(sum of all weights in this
@@ -61,7 +75,7 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, backendRe
6175
// implementation supports. Weight is not a percentage and the sum of
6276
// weights does not need to equal 100.
6377
//
64-
// If only one backend is specified and it has a weight greater than 0, 100%
78+
// If only one backend is specified, and it has a weight greater than 0, 100%
6579
// of the traffic is forwarded to that backend. If weight is set to 0, no
6680
// traffic should be forwarded for this entry. If unspecified, weight
6781
// defaults to 1.
@@ -70,8 +84,9 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, backendRe
7084
weight = int(*backendRef.Weight)
7185
}
7286
return &Backend{
73-
Service: svc,
74-
ServicePort: servicePort,
75-
Weight: weight,
87+
Service: svc,
88+
ServicePort: servicePort,
89+
Weight: weight,
90+
TypeSpecificBackend: typeSpecificBackend,
7691
}, nil
7792
}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package routeutils
2+
3+
import (
4+
"context"
5+
awssdk "github.com/aws/aws-sdk-go-v2/aws"
6+
"github.com/stretchr/testify/assert"
7+
corev1 "k8s.io/api/core/v1"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/apimachinery/pkg/runtime"
10+
"k8s.io/apimachinery/pkg/types"
11+
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
12+
elbv2api "sigs.k8s.io/aws-load-balancer-controller/apis/elbv2/v1beta1"
13+
testclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
14+
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
15+
"testing"
16+
)
17+
18+
func TestCommonBackendLoader(t *testing.T) {
19+
20+
kind := HTTPRouteKind
21+
22+
namespaceToUse := "current-namespace"
23+
svcNameToUse := "current-svc"
24+
routeNameToUse := "my-route"
25+
26+
portConverter := func(port int) *gwv1.PortNumber {
27+
pn := gwv1.PortNumber(port)
28+
return &pn
29+
}
30+
31+
testCases := []struct {
32+
name string
33+
storedService *corev1.Service
34+
backendRef gwv1.BackendRef
35+
routeIdentifier types.NamespacedName
36+
weight int
37+
servicePort int32
38+
expectErr bool
39+
expectNoResult bool
40+
}{
41+
{
42+
name: "backend ref without namespace",
43+
routeIdentifier: types.NamespacedName{
44+
Namespace: "backend-ref-ns",
45+
Name: routeNameToUse,
46+
},
47+
backendRef: gwv1.BackendRef{
48+
BackendObjectReference: gwv1.BackendObjectReference{
49+
Name: gwv1.ObjectName(svcNameToUse),
50+
Port: portConverter(80),
51+
},
52+
},
53+
storedService: &corev1.Service{
54+
ObjectMeta: metav1.ObjectMeta{
55+
Namespace: "backend-ref-ns",
56+
Name: svcNameToUse,
57+
},
58+
Spec: corev1.ServiceSpec{
59+
Ports: []corev1.ServicePort{
60+
{
61+
Name: "port-80",
62+
Port: 80,
63+
},
64+
},
65+
},
66+
},
67+
weight: 1,
68+
servicePort: 80,
69+
},
70+
{
71+
name: "backend ref, fill in weight",
72+
routeIdentifier: types.NamespacedName{
73+
Namespace: "backend-ref-ns",
74+
Name: routeNameToUse,
75+
},
76+
backendRef: gwv1.BackendRef{
77+
BackendObjectReference: gwv1.BackendObjectReference{
78+
Name: gwv1.ObjectName(svcNameToUse),
79+
Port: portConverter(80),
80+
},
81+
Weight: awssdk.Int32(100),
82+
},
83+
storedService: &corev1.Service{
84+
ObjectMeta: metav1.ObjectMeta{
85+
Namespace: "backend-ref-ns",
86+
Name: svcNameToUse,
87+
},
88+
Spec: corev1.ServiceSpec{
89+
Ports: []corev1.ServicePort{
90+
{
91+
Name: "port-80",
92+
Port: 80,
93+
},
94+
},
95+
},
96+
},
97+
weight: 100,
98+
servicePort: 80,
99+
},
100+
{
101+
name: "backend ref with namespace",
102+
routeIdentifier: types.NamespacedName{
103+
Name: routeNameToUse,
104+
},
105+
backendRef: gwv1.BackendRef{
106+
BackendObjectReference: gwv1.BackendObjectReference{
107+
Name: gwv1.ObjectName(svcNameToUse),
108+
Namespace: (*gwv1.Namespace)(&namespaceToUse),
109+
Port: portConverter(80),
110+
},
111+
},
112+
storedService: &corev1.Service{
113+
ObjectMeta: metav1.ObjectMeta{
114+
Namespace: namespaceToUse,
115+
Name: svcNameToUse,
116+
},
117+
Spec: corev1.ServiceSpec{
118+
Ports: []corev1.ServicePort{
119+
{
120+
Name: "port-80",
121+
Port: 80,
122+
},
123+
},
124+
},
125+
},
126+
weight: 1,
127+
servicePort: 80,
128+
},
129+
{
130+
name: "0 weight backend should return nil",
131+
routeIdentifier: types.NamespacedName{
132+
Name: routeNameToUse,
133+
},
134+
backendRef: gwv1.BackendRef{
135+
BackendObjectReference: gwv1.BackendObjectReference{
136+
Name: gwv1.ObjectName(svcNameToUse),
137+
Namespace: (*gwv1.Namespace)(&namespaceToUse),
138+
Port: portConverter(80),
139+
},
140+
Weight: awssdk.Int32(0),
141+
},
142+
expectNoResult: true,
143+
},
144+
{
145+
name: "non-service based backend should return nil",
146+
routeIdentifier: types.NamespacedName{
147+
Name: routeNameToUse,
148+
},
149+
backendRef: gwv1.BackendRef{
150+
BackendObjectReference: gwv1.BackendObjectReference{
151+
Name: gwv1.ObjectName(svcNameToUse),
152+
Namespace: (*gwv1.Namespace)(&namespaceToUse),
153+
Kind: (*gwv1.Kind)(awssdk.String("cat")),
154+
Port: portConverter(80),
155+
},
156+
},
157+
expectNoResult: true,
158+
},
159+
{
160+
name: "missing port in backend ref should result in an error",
161+
routeIdentifier: types.NamespacedName{
162+
Name: routeNameToUse,
163+
},
164+
backendRef: gwv1.BackendRef{
165+
BackendObjectReference: gwv1.BackendObjectReference{
166+
Name: gwv1.ObjectName(svcNameToUse),
167+
Namespace: (*gwv1.Namespace)(&namespaceToUse),
168+
},
169+
},
170+
expectErr: true,
171+
},
172+
}
173+
174+
for _, tc := range testCases {
175+
t.Run(tc.name, func(t *testing.T) {
176+
k8sSchema := runtime.NewScheme()
177+
clientgoscheme.AddToScheme(k8sSchema)
178+
elbv2api.AddToScheme(k8sSchema)
179+
k8sClient := testclient.NewClientBuilder().WithScheme(k8sSchema).Build()
180+
181+
if tc.storedService != nil {
182+
k8sClient.Create(context.Background(), tc.storedService)
183+
}
184+
185+
result, err := commonBackendLoader(context.Background(), k8sClient, tc.backendRef, tc.backendRef, tc.routeIdentifier, kind)
186+
187+
if tc.expectErr {
188+
assert.Error(t, err)
189+
return
190+
}
191+
192+
assert.NoError(t, err)
193+
194+
if tc.expectNoResult {
195+
assert.Nil(t, result)
196+
return
197+
}
198+
199+
assert.Equal(t, tc.storedService, result.Service)
200+
assert.Equal(t, tc.weight, result.Weight)
201+
assert.Equal(t, tc.servicePort, result.ServicePort.Port)
202+
assert.Equal(t, tc.backendRef, result.TypeSpecificBackend)
203+
})
204+
}
205+
206+
}

pkg/gateway/routeutils/descriptor.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
type routeMetadataDescriptor interface {
1111
GetRouteNamespacedName() types.NamespacedName
1212
GetRouteKind() string
13+
GetHostnames() []gwv1.Hostname
1314
GetParentRefs() []gwv1.ParentReference
1415
GetRawRoute() interface{}
1516
}

pkg/gateway/routeutils/grpc.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@ import (
88
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
99
)
1010

11+
/* Route Rule */
12+
1113
var _ RouteRule = &convertedGRPCRouteRule{}
1214

1315
type convertedGRPCRouteRule struct {
1416
rule *gwv1.GRPCRouteRule
1517
backends []Backend
1618
}
1719

20+
func (t *convertedGRPCRouteRule) GetRawRouteRule() interface{} {
21+
return t.rule
22+
}
23+
1824
func convertGRPCRouteRule(rule *gwv1.GRPCRouteRule, backends []Backend) RouteRule {
1925
return &convertedGRPCRouteRule{
2026
rule: rule,
@@ -30,28 +36,26 @@ func (t *convertedGRPCRouteRule) GetBackends() []Backend {
3036
return t.backends
3137
}
3238

33-
func (t *convertedGRPCRouteRule) GetHostnames() []string {
34-
return t.GetHostnames()
35-
}
39+
/* Route Description */
3640

3741
type grpcRouteDescription struct {
38-
route *gwv1.GRPCRoute
39-
rules []RouteRule
42+
route *gwv1.GRPCRoute
43+
rules []RouteRule
44+
backendLoader func(ctx context.Context, k8sClient client.Client, typeSpecificBackend interface{}, backendRef gwv1.BackendRef, routeIdentifier types.NamespacedName, routeKind string) (*Backend, error)
4045
}
4146

4247
func (grpcRoute *grpcRouteDescription) loadAttachedRules(ctx context.Context, k8sClient client.Client) (RouteDescriptor, error) {
4348
convertedRules := make([]RouteRule, 0)
4449
for _, rule := range grpcRoute.route.Spec.Rules {
4550
convertedBackends := make([]Backend, 0)
46-
4751
for _, backend := range rule.BackendRefs {
48-
// TODO - Figure out what stuff we need to transpose from GRPCBackendRef.
49-
// GRPCRouteFilter
50-
convertedBackend, err := commonBackendLoader(ctx, k8sClient, backend.BackendRef, grpcRoute.GetRouteNamespacedName(), grpcRoute.GetRouteKind())
52+
convertedBackend, err := grpcRoute.backendLoader(ctx, k8sClient, backend, backend.BackendRef, grpcRoute.GetRouteNamespacedName(), grpcRoute.GetRouteKind())
5153
if err != nil {
5254
return nil, err
5355
}
54-
convertedBackends = append(convertedBackends, *convertedBackend)
56+
if convertedBackend != nil {
57+
convertedBackends = append(convertedBackends, *convertedBackend)
58+
}
5559
}
5660

5761
convertedRules = append(convertedRules, convertGRPCRouteRule(&rule, convertedBackends))
@@ -61,6 +65,10 @@ func (grpcRoute *grpcRouteDescription) loadAttachedRules(ctx context.Context, k8
6165
return grpcRoute, nil
6266
}
6367

68+
func (grpcRoute *grpcRouteDescription) GetHostnames() []gwv1.Hostname {
69+
return grpcRoute.route.Spec.Hostnames
70+
}
71+
6472
func (grpcRoute *grpcRouteDescription) GetAttachedRules() []RouteRule {
6573
return grpcRoute.rules
6674
}
@@ -78,7 +86,7 @@ func (grpcRoute *grpcRouteDescription) GetRouteNamespacedName() types.Namespaced
7886
}
7987

8088
func convertGRPCRoute(r gwv1.GRPCRoute) *grpcRouteDescription {
81-
return &grpcRouteDescription{route: &r}
89+
return &grpcRouteDescription{route: &r, backendLoader: commonBackendLoader}
8290
}
8391

8492
func (grpcRoute *grpcRouteDescription) GetRawRoute() interface{} {

0 commit comments

Comments
 (0)