Skip to content

Commit 26e8c07

Browse files
committed
Consolidate and fix v1beta1 fuzzer funcs
Firstly this change consolidates common fuzzer funcs for fuzzing v1beta1 between v1alpha6 and v1alpha7. Secondly, we fix a couple of bugs where we were generating invalid output: In OpenStackClusterSpec we were creating a second subnet with FuzzNoCustom, which doesn't use our custom functions for generating valid output. When generating filters we were appending a second tag after validating tags, which meant we occasionally got invalid tags. We now add tags before validation, and also add tags to all tag fields instead of just 'Tags'. We also consolidate tag validation in a FilterByNeutronTags func instead of individually for each Filter.
1 parent ec77c18 commit 26e8c07

File tree

3 files changed

+112
-194
lines changed

3 files changed

+112
-194
lines changed

api/v1alpha6/conversion_test.go

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ limitations under the License.
1717
package v1alpha6
1818

1919
import (
20-
"strings"
20+
"slices"
2121
"testing"
2222

2323
"github.com/google/go-cmp/cmp"
@@ -57,19 +57,8 @@ func TestFuzzyConversion(t *testing.T) {
5757
delete(obj.GetAnnotations(), utilconversion.DataAnnotation)
5858
}
5959

60-
filterInvalidTags := func(tags []infrav1.NeutronTag) []infrav1.NeutronTag {
61-
var ret []infrav1.NeutronTag
62-
for i := range tags {
63-
s := string(tags[i])
64-
if len(s) > 0 && !strings.Contains(s, ",") {
65-
ret = append(ret, tags[i])
66-
}
67-
}
68-
return ret
69-
}
70-
7160
fuzzerFuncs := func(_ runtimeserializer.CodecFactory) []interface{} {
72-
return []interface{}{
61+
v1alpha6FuzzerFuncs := []interface{}{
7362
func(instance *Instance, c fuzz.Continue) {
7463
c.FuzzNoCustom(instance)
7564

@@ -102,19 +91,6 @@ func TestFuzzyConversion(t *testing.T) {
10291
}
10392
},
10493

105-
func(spec *infrav1.OpenStackClusterSpec, c fuzz.Continue) {
106-
c.FuzzNoCustom(spec)
107-
108-
// The fuzzer only seems to generate Subnets of
109-
// length 1, but we need to also test length 2.
110-
// Ensure it is occasionally generated.
111-
if len(spec.Subnets) == 1 && c.RandBool() {
112-
subnet := infrav1.SubnetFilter{}
113-
c.FuzzNoCustom(&subnet)
114-
spec.Subnets = append(spec.Subnets, subnet)
115-
}
116-
},
117-
11894
func(spec *OpenStackMachineSpec, c fuzz.Continue) {
11995
c.FuzzNoCustom(spec)
12096

@@ -145,68 +121,9 @@ func TestFuzzyConversion(t *testing.T) {
145121
}
146122
}
147123
},
148-
149-
func(spec *infrav1.SubnetSpec, c fuzz.Continue) {
150-
c.FuzzNoCustom(spec)
151-
152-
// CIDR is required and API validates that it's present, so
153-
// we force it to always be set.
154-
for spec.CIDR == "" {
155-
spec.CIDR = c.RandString()
156-
}
157-
},
158-
159-
func(pool *infrav1.AllocationPool, c fuzz.Continue) {
160-
c.FuzzNoCustom(pool)
161-
162-
// Start and End are required properties, let's make sure both are set
163-
for pool.Start == "" {
164-
pool.Start = c.RandString()
165-
}
166-
167-
for pool.End == "" {
168-
pool.End = c.RandString()
169-
}
170-
},
171-
172-
// v1beta1 filter tags cannot contain commas and can't be empty.
173-
174-
func(filter *infrav1.SubnetFilter, c fuzz.Continue) {
175-
c.FuzzNoCustom(filter)
176-
177-
filter.Tags = filterInvalidTags(filter.Tags)
178-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
179-
filter.NotTags = filterInvalidTags(filter.NotTags)
180-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
181-
},
182-
183-
func(filter *infrav1.NetworkFilter, c fuzz.Continue) {
184-
c.FuzzNoCustom(filter)
185-
186-
filter.Tags = filterInvalidTags(filter.Tags)
187-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
188-
filter.NotTags = filterInvalidTags(filter.NotTags)
189-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
190-
},
191-
192-
func(filter *infrav1.RouterFilter, c fuzz.Continue) {
193-
c.FuzzNoCustom(filter)
194-
195-
filter.Tags = filterInvalidTags(filter.Tags)
196-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
197-
filter.NotTags = filterInvalidTags(filter.NotTags)
198-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
199-
},
200-
201-
func(filter *infrav1.SecurityGroupFilter, c fuzz.Continue) {
202-
c.FuzzNoCustom(filter)
203-
204-
filter.Tags = filterInvalidTags(filter.Tags)
205-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
206-
filter.NotTags = filterInvalidTags(filter.NotTags)
207-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
208-
},
209124
}
125+
126+
return slices.Concat(v1alpha6FuzzerFuncs, testhelpers.InfraV1FuzzerFuncs())
210127
}
211128

212129
t.Run("for OpenStackCluster", runParallel(utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{

api/v1alpha7/conversion_test.go

Lines changed: 4 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ limitations under the License.
1717
package v1alpha7
1818

1919
import (
20-
"strings"
20+
"slices"
2121
"testing"
2222

2323
"github.com/google/go-cmp/cmp"
@@ -57,32 +57,8 @@ func TestFuzzyConversion(t *testing.T) {
5757
delete(obj.GetAnnotations(), utilconversion.DataAnnotation)
5858
}
5959

60-
filterInvalidTags := func(tags []infrav1.NeutronTag) []infrav1.NeutronTag {
61-
var ret []infrav1.NeutronTag
62-
for i := range tags {
63-
s := string(tags[i])
64-
if len(s) > 0 && !strings.Contains(s, ",") {
65-
ret = append(ret, tags[i])
66-
}
67-
}
68-
return ret
69-
}
70-
7160
fuzzerFuncs := func(_ runtimeserializer.CodecFactory) []interface{} {
72-
return []interface{}{
73-
func(spec *infrav1.OpenStackClusterSpec, c fuzz.Continue) {
74-
c.FuzzNoCustom(spec)
75-
76-
// The fuzzer only seems to generate Subnets of
77-
// length 1, but we need to also test length 2.
78-
// Ensure it is occasionally generated.
79-
if len(spec.Subnets) == 1 && c.RandBool() {
80-
subnet := infrav1.SubnetFilter{}
81-
c.FuzzNoCustom(&subnet)
82-
spec.Subnets = append(spec.Subnets, subnet)
83-
}
84-
},
85-
61+
v1alpha7FuzzerFuncs := []interface{}{
8662
func(spec *OpenStackMachineSpec, c fuzz.Continue) {
8763
c.FuzzNoCustom(spec)
8864

@@ -113,88 +89,9 @@ func TestFuzzyConversion(t *testing.T) {
11389
}
11490
}
11591
},
116-
117-
func(spec *infrav1.SubnetSpec, c fuzz.Continue) {
118-
c.FuzzNoCustom(spec)
119-
120-
// CIDR is required and API validates that it's present, so
121-
// we force it to always be set.
122-
for spec.CIDR == "" {
123-
spec.CIDR = c.RandString()
124-
}
125-
},
126-
127-
func(pool *infrav1.AllocationPool, c fuzz.Continue) {
128-
c.FuzzNoCustom(pool)
129-
130-
// Start and End are required properties, let's make sure both are set
131-
for pool.Start == "" {
132-
pool.Start = c.RandString()
133-
}
134-
135-
for pool.End == "" {
136-
pool.End = c.RandString()
137-
}
138-
},
139-
140-
// v1beta1 filter tags cannot contain commas and can't be empty.
141-
142-
func(filter *infrav1.SubnetFilter, c fuzz.Continue) {
143-
c.FuzzNoCustom(filter)
144-
145-
// Sometimes add an additional tag to ensure we get test coverage of multiple tags
146-
if c.RandBool() {
147-
filter.Tags = append(filter.Tags, infrav1.NeutronTag(c.RandString()))
148-
}
149-
150-
filter.Tags = filterInvalidTags(filter.Tags)
151-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
152-
filter.NotTags = filterInvalidTags(filter.NotTags)
153-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
154-
},
155-
156-
func(filter *infrav1.NetworkFilter, c fuzz.Continue) {
157-
c.FuzzNoCustom(filter)
158-
159-
// Sometimes add an additional tag to ensure we get test coverage of multiple tags
160-
if c.RandBool() {
161-
filter.Tags = append(filter.Tags, infrav1.NeutronTag(c.RandString()))
162-
}
163-
164-
filter.Tags = filterInvalidTags(filter.Tags)
165-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
166-
filter.NotTags = filterInvalidTags(filter.NotTags)
167-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
168-
},
169-
170-
func(filter *infrav1.RouterFilter, c fuzz.Continue) {
171-
c.FuzzNoCustom(filter)
172-
173-
// Sometimes add an additional tag to ensure we get test coverage of multiple tags
174-
if c.RandBool() {
175-
filter.Tags = append(filter.Tags, infrav1.NeutronTag(c.RandString()))
176-
}
177-
178-
filter.Tags = filterInvalidTags(filter.Tags)
179-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
180-
filter.NotTags = filterInvalidTags(filter.NotTags)
181-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
182-
},
183-
184-
func(filter *infrav1.SecurityGroupFilter, c fuzz.Continue) {
185-
c.FuzzNoCustom(filter)
186-
187-
// Sometimes add an additional tag to ensure we get test coverage of multiple tags
188-
if c.RandBool() {
189-
filter.Tags = append(filter.Tags, infrav1.NeutronTag(c.RandString()))
190-
}
191-
192-
filter.Tags = filterInvalidTags(filter.Tags)
193-
filter.TagsAny = filterInvalidTags(filter.TagsAny)
194-
filter.NotTags = filterInvalidTags(filter.NotTags)
195-
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
196-
},
19792
}
93+
94+
return slices.Concat(v1alpha7FuzzerFuncs, testhelpers.InfraV1FuzzerFuncs())
19895
}
19996

20097
t.Run("for OpenStackCluster", runParallel(utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{

test/helpers/fuzzerfuncs.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package helpers
18+
19+
import (
20+
"strings"
21+
22+
fuzz "github.com/google/gofuzz"
23+
24+
infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
25+
)
26+
27+
func filterInvalidTags(tags []infrav1.NeutronTag) []infrav1.NeutronTag {
28+
var ret []infrav1.NeutronTag
29+
for i := range tags {
30+
s := string(tags[i])
31+
if len(s) > 0 && !strings.Contains(s, ",") {
32+
ret = append(ret, tags[i])
33+
}
34+
}
35+
return ret
36+
}
37+
38+
// InfraV1FuzzerFuncs returns fuzzer funcs for v1beta1 OpenStack types which:
39+
// * Constrain the output in ways which are validated by the API server
40+
// * Add additional test coverage where it is not generated by the default fuzzer.
41+
func InfraV1FuzzerFuncs() []interface{} {
42+
return []interface{}{
43+
func(spec *infrav1.OpenStackClusterSpec, c fuzz.Continue) {
44+
c.FuzzNoCustom(spec)
45+
46+
// The fuzzer only seems to generate Subnets of
47+
// length 1, but we need to also test length 2.
48+
// Ensure it is occasionally generated.
49+
if len(spec.Subnets) == 1 && c.RandBool() {
50+
subnet := infrav1.SubnetFilter{}
51+
c.Fuzz(&subnet)
52+
spec.Subnets = append(spec.Subnets, subnet)
53+
}
54+
},
55+
56+
func(spec *infrav1.SubnetSpec, c fuzz.Continue) {
57+
c.FuzzNoCustom(spec)
58+
59+
// CIDR is required and API validates that it's present, so
60+
// we force it to always be set.
61+
for spec.CIDR == "" {
62+
spec.CIDR = c.RandString()
63+
}
64+
},
65+
66+
func(pool *infrav1.AllocationPool, c fuzz.Continue) {
67+
c.FuzzNoCustom(pool)
68+
69+
// Start and End are required properties, let's make sure both are set
70+
for pool.Start == "" {
71+
pool.Start = c.RandString()
72+
}
73+
74+
for pool.End == "" {
75+
pool.End = c.RandString()
76+
}
77+
},
78+
79+
// v1beta1 filter tags cannot contain commas and can't be empty.
80+
func(filter *infrav1.FilterByNeutronTags, c fuzz.Continue) {
81+
c.FuzzNoCustom(filter)
82+
83+
// Sometimes add an additional tag to ensure we get test coverage of multiple tags
84+
if c.RandBool() {
85+
filter.Tags = append(filter.Tags, infrav1.NeutronTag(c.RandString()))
86+
}
87+
if c.RandBool() {
88+
filter.TagsAny = append(filter.TagsAny, infrav1.NeutronTag(c.RandString()))
89+
}
90+
if c.RandBool() {
91+
filter.NotTags = append(filter.NotTags, infrav1.NeutronTag(c.RandString()))
92+
}
93+
if c.RandBool() {
94+
filter.NotTagsAny = append(filter.NotTagsAny, infrav1.NeutronTag(c.RandString()))
95+
}
96+
97+
// Remove empty tags and tags with commas
98+
filter.Tags = filterInvalidTags(filter.Tags)
99+
filter.TagsAny = filterInvalidTags(filter.TagsAny)
100+
filter.NotTags = filterInvalidTags(filter.NotTags)
101+
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
102+
},
103+
}
104+
}

0 commit comments

Comments
 (0)