Skip to content

Commit 57676d9

Browse files
authored
Fix unit tests to avoid data race in pipelines (#2602)
Fix unit tests to avoid data race in pipelines Problem: Users want to parallelize unit tests without having data race issues Solution: Modify unit tests to be independent of variables, maps/structs to avoid data race when tests run in parallel.
1 parent d490d7e commit 57676d9

File tree

3 files changed

+110
-149
lines changed

3 files changed

+110
-149
lines changed

docs/developer/testing.md

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ the [Counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) tool. Counter
3636
implementations of internal and public interfaces, allowing us to isolate and control dependencies during testing. It
3737
simplifies the process of mocking and stubbing, making our tests more robust and flexible.
3838

39+
**Parallelize unit tests**: In general, all tests should be designed to run in parallel for faster execution and help uncover bugs. For standard Go tests, this requires adding `t.Parallel()` to every test and subtest. Ginkgo tests, on the other hand, automatically run in parallel without the need for additional configuration. If a component under test requires sequential execution, you can run tests sequentially by using an [ordered container](https://onsi.github.io/ginkgo/#ordered-containers) for Ginkgo tests or by omitting `t.Parallel()` from the go test or subtest. In such cases, it’s essential to include a comment explaining why parallel execution is not possible.
40+
3941
By combining BDD style tests, unit tests, and mock generation, we aim to achieve a comprehensive and maintainable
4042
testing strategy. This approach enables us to ensure the correctness, reliability, and flexibility of our codebase while
4143
promoting efficient refactoring and continuous development.

internal/mode/static/state/graph/policies_test.go

+95-133
Original file line numberDiff line numberDiff line change
@@ -25,60 +25,20 @@ var testNs = "test"
2525
func TestAttachPolicies(t *testing.T) {
2626
t.Parallel()
2727
policyGVK := schema.GroupVersionKind{Group: "Group", Version: "Version", Kind: "Policy"}
28-
29-
gwPolicyKey := createTestPolicyKey(policyGVK, "gw-policy")
30-
gwPolicy := &Policy{
31-
Valid: true,
32-
Source: &policiesfakes.FakePolicy{},
33-
TargetRefs: []PolicyTargetRef{
34-
{
35-
Kind: kinds.Gateway,
36-
Group: v1.GroupName,
37-
Nsname: types.NamespacedName{Namespace: testNs, Name: "gateway"},
38-
},
39-
{
40-
Kind: kinds.Gateway,
41-
Group: v1.GroupName,
42-
Nsname: types.NamespacedName{Namespace: testNs, Name: "gateway2"}, // ignored
43-
},
44-
},
45-
}
46-
47-
routePolicyKey := createTestPolicyKey(policyGVK, "route-policy")
48-
routePolicy := &Policy{
49-
Valid: true,
50-
Source: &policiesfakes.FakePolicy{},
51-
TargetRefs: []PolicyTargetRef{
52-
{
53-
Kind: kinds.HTTPRoute,
54-
Group: v1.GroupName,
55-
Nsname: types.NamespacedName{Namespace: testNs, Name: "hr-route"},
56-
},
57-
{
58-
Kind: kinds.HTTPRoute,
59-
Group: v1.GroupName,
60-
Nsname: types.NamespacedName{Namespace: testNs, Name: "hr2-route"},
61-
},
62-
},
63-
}
64-
65-
grpcRoutePolicyKey := createTestPolicyKey(policyGVK, "grpc-route-policy")
66-
grpcRoutePolicy := &Policy{
67-
Valid: true,
68-
Source: &policiesfakes.FakePolicy{},
69-
TargetRefs: []PolicyTargetRef{
70-
{
71-
Kind: kinds.GRPCRoute,
28+
createPolicy := func(targetRefsNames []string, refKind v1.Kind) *Policy {
29+
targetRefs := make([]PolicyTargetRef, 0, len(targetRefsNames))
30+
for _, name := range targetRefsNames {
31+
targetRefs = append(targetRefs, PolicyTargetRef{
32+
Kind: refKind,
7233
Group: v1.GroupName,
73-
Nsname: types.NamespacedName{Namespace: testNs, Name: "grpc-route"},
74-
},
75-
},
76-
}
77-
78-
ngfPolicies := map[PolicyKey]*Policy{
79-
gwPolicyKey: gwPolicy,
80-
routePolicyKey: routePolicy,
81-
grpcRoutePolicyKey: grpcRoutePolicy,
34+
Nsname: types.NamespacedName{Namespace: testNs, Name: name},
35+
})
36+
}
37+
return &Policy{
38+
Valid: true,
39+
Source: &policiesfakes.FakePolicy{},
40+
TargetRefs: targetRefs,
41+
}
8242
}
8343

8444
createRouteKey := func(name string, routeType RouteType) RouteKey {
@@ -88,77 +48,40 @@ func TestAttachPolicies(t *testing.T) {
8848
}
8949
}
9050

91-
newGraph := func() *Graph {
92-
return &Graph{
93-
Gateway: &Gateway{
94-
Source: &v1.Gateway{
95-
ObjectMeta: metav1.ObjectMeta{
96-
Name: "gateway",
97-
Namespace: testNs,
98-
},
51+
createGateway := func(name string) *Gateway {
52+
return &Gateway{
53+
Source: &v1.Gateway{
54+
ObjectMeta: metav1.ObjectMeta{
55+
Name: name,
56+
Namespace: testNs,
9957
},
100-
Valid: true,
10158
},
102-
Routes: map[RouteKey]*L7Route{
103-
createRouteKey("hr-route", RouteTypeHTTP): {
104-
Source: &v1.HTTPRoute{
105-
ObjectMeta: metav1.ObjectMeta{
106-
Name: "hr-route",
107-
Namespace: testNs,
108-
},
109-
},
110-
ParentRefs: []ParentRef{
111-
{
112-
Attachment: &ParentRefAttachmentStatus{
113-
Attached: true,
114-
},
115-
},
116-
},
117-
Valid: true,
118-
Attachable: true,
119-
},
120-
createRouteKey("hr2-route", RouteTypeHTTP): {
121-
Source: &v1.HTTPRoute{
122-
ObjectMeta: metav1.ObjectMeta{
123-
Name: "hr2-route",
124-
Namespace: testNs,
125-
},
126-
},
127-
ParentRefs: []ParentRef{
128-
{
129-
Attachment: &ParentRefAttachmentStatus{
130-
Attached: true,
131-
},
132-
},
59+
Valid: true,
60+
}
61+
}
62+
63+
createRoutesForGraph := func(routes map[string]RouteType) map[RouteKey]*L7Route {
64+
routesMap := make(map[RouteKey]*L7Route, len(routes))
65+
for routeName, routeType := range routes {
66+
routesMap[createRouteKey(routeName, routeType)] = &L7Route{
67+
Source: &v1.HTTPRoute{
68+
ObjectMeta: metav1.ObjectMeta{
69+
Name: routeName,
70+
Namespace: testNs,
13371
},
134-
Valid: true,
135-
Attachable: true,
13672
},
137-
createRouteKey("grpc-route", RouteTypeGRPC): {
138-
Source: &v1alpha2.GRPCRoute{
139-
ObjectMeta: metav1.ObjectMeta{
140-
Name: "grpc-route",
141-
Namespace: testNs,
142-
},
143-
},
144-
ParentRefs: []ParentRef{
145-
{
146-
Attachment: &ParentRefAttachmentStatus{
147-
Attached: true,
148-
},
73+
ParentRefs: []ParentRef{
74+
{
75+
Attachment: &ParentRefAttachmentStatus{
76+
Attached: true,
14977
},
15078
},
151-
Valid: true,
152-
Attachable: true,
15379
},
154-
},
155-
156-
NGFPolicies: ngfPolicies,
80+
Valid: true,
81+
Attachable: true,
82+
}
15783
}
158-
}
159-
160-
newModifiedGraph := func(mod func(g *Graph) *Graph) *Graph {
161-
return mod(newGraph())
84+
return routesMap
16285
}
16386

16487
expectNoPolicyAttachment := func(g *WithT, graph *Graph) {
@@ -192,30 +115,63 @@ func TestAttachPolicies(t *testing.T) {
192115
}
193116

194117
tests := []struct {
195-
graph *Graph
196-
expect func(g *WithT, graph *Graph)
197-
name string
118+
gateway *Gateway
119+
routes map[RouteKey]*L7Route
120+
ngfPolicies map[PolicyKey]*Policy
121+
expect func(g *WithT, graph *Graph)
122+
name string
198123
}{
199124
{
200125
name: "nil Gateway",
201-
graph: newModifiedGraph(func(g *Graph) *Graph {
202-
g.Gateway = nil
203-
return g
204-
}),
126+
routes: createRoutesForGraph(
127+
map[string]RouteType{
128+
"hr1-route": RouteTypeHTTP,
129+
"hr2-route": RouteTypeHTTP,
130+
"grpc-route": RouteTypeGRPC,
131+
},
132+
),
133+
ngfPolicies: map[PolicyKey]*Policy{
134+
createTestPolicyKey(policyGVK, "gw-policy"): createPolicy([]string{"gateway", "gateway1"}, kinds.Gateway),
135+
createTestPolicyKey(policyGVK, "route-policy"): createPolicy(
136+
[]string{"hr1-route", "hr2-route"},
137+
kinds.HTTPRoute,
138+
),
139+
createTestPolicyKey(policyGVK, "grpc-route-policy"): createPolicy([]string{"grpc-route"}, kinds.GRPCRoute),
140+
},
205141
expect: expectNoPolicyAttachment,
206142
},
207143
{
208-
name: "nil routes",
209-
graph: newModifiedGraph(func(g *Graph) *Graph {
210-
g.Routes = nil
211-
return g
212-
}),
144+
name: "nil routes",
145+
gateway: createGateway("gateway"),
146+
ngfPolicies: map[PolicyKey]*Policy{
147+
createTestPolicyKey(policyGVK, "gw-policy1"): createPolicy([]string{"gateway", "gateway1"}, kinds.Gateway),
148+
createTestPolicyKey(policyGVK, "route-policy1"): createPolicy(
149+
[]string{"hr1-route", "hr2-route"},
150+
kinds.HTTPRoute,
151+
),
152+
createTestPolicyKey(policyGVK, "grpc-route-policy1"): createPolicy([]string{"grpc-route"}, kinds.GRPCRoute),
153+
},
213154
expect: expectGatewayPolicyAttachment,
214155
},
215156
{
216-
name: "normal",
217-
graph: newGraph(),
218-
expect: expectPolicyAttachment,
157+
name: "normal",
158+
routes: createRoutesForGraph(
159+
map[string]RouteType{
160+
"hr-1": RouteTypeHTTP,
161+
"hr-2": RouteTypeHTTP,
162+
"grpc-1": RouteTypeGRPC,
163+
},
164+
),
165+
ngfPolicies: map[PolicyKey]*Policy{
166+
createTestPolicyKey(policyGVK, "gw-policy2"): createPolicy([]string{"gateway2", "gateway3"}, kinds.Gateway),
167+
createTestPolicyKey(policyGVK, "route-policy2"): createPolicy(
168+
[]string{"hr-1", "hr-2"},
169+
kinds.HTTPRoute,
170+
),
171+
createTestPolicyKey(policyGVK, "grpc-route-policy2"): createPolicy([]string{"grpc-1"}, kinds.GRPCRoute),
172+
},
173+
gateway: createGateway("gateway2"),
174+
expect: expectPolicyAttachment,
219175
},
220176
}
221177

@@ -224,8 +180,14 @@ func TestAttachPolicies(t *testing.T) {
224180
t.Parallel()
225181
g := NewWithT(t)
226182

227-
test.graph.attachPolicies("nginx-gateway")
228-
test.expect(g, test.graph)
183+
graph := &Graph{
184+
Gateway: test.gateway,
185+
Routes: test.routes,
186+
NGFPolicies: test.ngfPolicies,
187+
}
188+
189+
graph.attachPolicies("nginx-gateway")
190+
test.expect(g, graph)
229191
})
230192
}
231193
}

internal/mode/static/state/graph/reference_grant_test.go

+13-16
Original file line numberDiff line numberDiff line change
@@ -345,63 +345,57 @@ func TestRefAllowedFrom(t *testing.T) {
345345
},
346346
}
347347

348-
resolver := newReferenceGrantResolver(refGrants)
349-
refAllowedFromGRPCRoute := resolver.refAllowedFrom(fromGRPCRoute(grNs))
350-
refAllowedFromHTTPRoute := resolver.refAllowedFrom(fromHTTPRoute(hrNs))
351-
refAllowedFromTLSRoute := resolver.refAllowedFrom(fromTLSRoute(trNs))
352-
refAllowedFromGateway := resolver.refAllowedFrom(fromGateway(gwNs))
353-
354348
tests := []struct {
355349
name string
356-
refAllowedFrom func(resource toResource) bool
350+
refAllowedFrom fromResource
357351
toResource toResource
358352
expAllowed bool
359353
}{
360354
{
361355
name: "ref allowed from gateway to secret",
362-
refAllowedFrom: refAllowedFromGateway,
356+
refAllowedFrom: fromGateway(gwNs),
363357
toResource: toSecret(allowedGatewayNsName),
364358
expAllowed: true,
365359
},
366360
{
367361
name: "ref not allowed from gateway to secret",
368-
refAllowedFrom: refAllowedFromGateway,
362+
refAllowedFrom: fromGateway(gwNs),
369363
toResource: toSecret(notAllowedNsName),
370364
expAllowed: false,
371365
},
372366
{
373367
name: "ref allowed from httproute to service",
374-
refAllowedFrom: refAllowedFromHTTPRoute,
368+
refAllowedFrom: fromHTTPRoute(hrNs),
375369
toResource: toService(allowedHTTPRouteNsName),
376370
expAllowed: true,
377371
},
378372
{
379373
name: "ref not allowed from httproute to service",
380-
refAllowedFrom: refAllowedFromHTTPRoute,
374+
refAllowedFrom: fromHTTPRoute(hrNs),
381375
toResource: toService(notAllowedNsName),
382376
expAllowed: false,
383377
},
384378
{
385379
name: "ref allowed from grpcroute to service",
386-
refAllowedFrom: refAllowedFromGRPCRoute,
380+
refAllowedFrom: fromGRPCRoute(grNs),
387381
toResource: toService(allowedGRPCRouteNsName),
388382
expAllowed: true,
389383
},
390384
{
391385
name: "ref not allowed from grpcroute to service",
392-
refAllowedFrom: refAllowedFromGRPCRoute,
386+
refAllowedFrom: fromGRPCRoute(grNs),
393387
toResource: toService(notAllowedNsName),
394388
expAllowed: false,
395389
},
396390
{
397391
name: "ref allowed from tlsroute to service",
398-
refAllowedFrom: refAllowedFromTLSRoute,
392+
refAllowedFrom: fromTLSRoute(trNs),
399393
toResource: toService(allowedTLSRouteNsName),
400394
expAllowed: true,
401395
},
402396
{
403397
name: "ref not allowed from tlsroute to service",
404-
refAllowedFrom: refAllowedFromTLSRoute,
398+
refAllowedFrom: fromTLSRoute(trNs),
405399
toResource: toService(notAllowedNsName),
406400
expAllowed: false,
407401
},
@@ -411,8 +405,11 @@ func TestRefAllowedFrom(t *testing.T) {
411405
t.Run(test.name, func(t *testing.T) {
412406
t.Parallel()
413407

408+
resolver := newReferenceGrantResolver(refGrants)
409+
refAllowed := resolver.refAllowedFrom(test.refAllowedFrom)
410+
414411
g := NewWithT(t)
415-
g.Expect(test.refAllowedFrom(test.toResource)).To(Equal(test.expAllowed))
412+
g.Expect(refAllowed(test.toResource)).To(Equal(test.expAllowed))
416413
})
417414
}
418415
}

0 commit comments

Comments
 (0)