@@ -18,44 +18,61 @@ package v4
18
18
19
19
import (
20
20
"os"
21
- "testing"
21
+ "path/filepath"
22
+ "strings"
22
23
23
- "github.com/stretchr/testify/assert"
24
+ . "github.com/onsi/ginkgo/v2"
25
+ . "github.com/onsi/gomega"
24
26
25
27
"sigs.k8s.io/kubebuilder/v4/pkg/machinery"
28
+ "sigs.k8s.io/kubebuilder/v4/pkg/plugin/util"
29
+ "sigs.k8s.io/kubebuilder/v4/test/e2e/utils"
26
30
)
27
31
28
- func TestFeatureGateDiscoveryInTestdata (t * testing.T ) {
29
- // Test feature gate discovery in our testdata project
30
- parser := machinery .NewFeatureGateMarkerParser ()
31
-
32
- // Parse the testdata project API types
33
- markers , err := parser .ParseFile ("../../../testdata/project-v4/api/v1/captain_types.go" )
34
- assert .NoError (t , err )
35
- assert .NotEmpty (t , markers , "Should discover feature gate markers" )
36
-
37
- // Extract feature gate names
38
- featureGates := machinery .ExtractFeatureGates (markers )
39
-
40
- // Verify we found the expected feature gates
41
- expectedGates := []string {
42
- "experimental-bar" ,
43
- }
44
-
45
- for _ , expectedGate := range expectedGates {
46
- assert .Contains (t , featureGates , expectedGate ,
47
- "Should discover feature gate: %s" , expectedGate )
48
- }
32
+ var _ = Describe ("Feature Gates Discovery" , func () {
33
+ var kbc * utils.TestContext
34
+
35
+ BeforeEach (func () {
36
+ var err error
37
+ kbc , err = utils .NewTestContext (util .KubebuilderBinName , "GO111MODULE=on" )
38
+ Expect (err ).NotTo (HaveOccurred ())
39
+ Expect (kbc .Prepare ()).To (Succeed ())
40
+ })
41
+
42
+ AfterEach (func () {
43
+ By ("cleaning up test context" )
44
+ kbc .Destroy ()
45
+ })
46
+
47
+ Context ("when parsing testdata project" , func () {
48
+ It ("should discover feature gate markers from captain_types.go" , func () {
49
+ By ("parsing the testdata project API types" )
50
+ parser := machinery .NewFeatureGateMarkerParser ()
51
+ markers , err := parser .ParseFile ("../../../testdata/project-v4/api/v1/captain_types.go" )
52
+ Expect (err ).NotTo (HaveOccurred ())
53
+ Expect (markers ).NotTo (BeEmpty (), "Should discover feature gate markers" )
54
+
55
+ By ("extracting feature gate names" )
56
+ featureGates := machinery .ExtractFeatureGates (markers )
57
+
58
+ By ("verifying expected feature gates are found" )
59
+ expectedGates := []string {
60
+ "experimental-bar" ,
61
+ }
49
62
50
- t .Logf ("Discovered feature gates: %v" , featureGates )
51
- }
63
+ for _ , expectedGate := range expectedGates {
64
+ Expect (featureGates ).To (ContainElement (expectedGate ),
65
+ "Should discover feature gate: %s" , expectedGate )
66
+ }
52
67
53
- func TestFeatureGateDiscoveryIgnoresCommentedFields ( t * testing. T ) {
54
- // Test that commented fields with feature gate markers are not discovered
55
- parser := machinery . NewFeatureGateMarkerParser ( )
68
+ GinkgoWriter . Printf ( "Discovered feature gates: %v \n " , featureGates )
69
+ })
70
+ } )
56
71
57
- // Create a temporary file with commented feature gate markers
58
- tempContent := `package test
72
+ Context ("when parsing files with commented fields" , func () {
73
+ It ("should ignore commented feature gate markers" , func () {
74
+ By ("creating a temporary file with commented feature gate markers" )
75
+ tempContent := `package test
59
76
60
77
type TestStruct struct {
61
78
// This field is commented out and should not be discovered
@@ -68,85 +85,142 @@ type TestStruct struct {
68
85
}
69
86
`
70
87
71
- // Write to temporary file
72
- tmpFile , err := os .CreateTemp ("" , "featuregate_test_*.go" )
73
- assert . NoError ( t , err )
74
- defer os .Remove (tmpFile .Name ())
88
+ By ( "writing temporary file" )
89
+ tmpFile , err := os .CreateTemp ("" , "featuregate_test_*.go" )
90
+ Expect ( err ). NotTo ( HaveOccurred () )
91
+ defer os .Remove (tmpFile .Name ())
75
92
76
- _ , err = tmpFile .WriteString (tempContent )
77
- assert . NoError ( t , err )
78
- tmpFile .Close ()
93
+ _ , err = tmpFile .WriteString (tempContent )
94
+ Expect ( err ). NotTo ( HaveOccurred () )
95
+ tmpFile .Close ()
79
96
80
- // Parse the temporary file
81
- markers , err := parser .ParseFile (tmpFile .Name ())
82
- assert .NoError (t , err )
97
+ By ("parsing the temporary file" )
98
+ parser := machinery .NewFeatureGateMarkerParser ()
99
+ markers , err := parser .ParseFile (tmpFile .Name ())
100
+ Expect (err ).NotTo (HaveOccurred ())
83
101
84
- // Extract feature gate names
85
- featureGates := machinery .ExtractFeatureGates (markers )
102
+ By ( "extracting feature gate names" )
103
+ featureGates := machinery .ExtractFeatureGates (markers )
86
104
87
- // Should only discover the active feature gate, not the commented one
88
- assert . Contains ( t , featureGates , "active-feature" , "Should discover active feature gate" )
89
- assert . NotContains ( t , featureGates , "commented-feature" , "Should NOT discover commented feature gate" )
105
+ By ( "verifying only active feature gates are discovered" )
106
+ Expect ( featureGates ). To ( ContainElement ( "active-feature" ) , "Should discover active feature gate" )
107
+ Expect ( featureGates ). NotTo ( ContainElement ( "commented-feature" ) , "Should NOT discover commented feature gate" )
90
108
91
- t .Logf ("Discovered feature gates: %v" , featureGates )
92
- }
109
+ GinkgoWriter .Printf ("Discovered feature gates: %v\n " , featureGates )
110
+ })
111
+ })
112
+
113
+ Context ("when parsing feature gate strings" , func () {
114
+ It ("should handle various feature gate parsing scenarios" , func () {
115
+ testCases := []struct {
116
+ name string
117
+ input string
118
+ expected map [string ]bool
119
+ hasError bool
120
+ }{
121
+ {
122
+ name : "empty string" ,
123
+ input : "" ,
124
+ expected : map [string ]bool {},
125
+ hasError : false ,
126
+ },
127
+ {
128
+ name : "single feature gate" ,
129
+ input : "experimental-bar" ,
130
+ expected : map [string ]bool {"experimental-bar" : true },
131
+ hasError : false ,
132
+ },
133
+ {
134
+ name : "multiple feature gates" ,
135
+ input : "experimental-bar,advanced-features" ,
136
+ expected : map [string ]bool {
137
+ "experimental-bar" : true ,
138
+ "advanced-features" : true ,
139
+ },
140
+ hasError : false ,
141
+ },
142
+ {
143
+ name : "mixed enabled and disabled" ,
144
+ input : "experimental-bar=true,advanced-features=false" ,
145
+ expected : map [string ]bool {
146
+ "experimental-bar" : true ,
147
+ "advanced-features" : false ,
148
+ },
149
+ hasError : false ,
150
+ },
151
+ {
152
+ name : "invalid format" ,
153
+ input : "experimental-bar=invalid" ,
154
+ expected : nil ,
155
+ hasError : true ,
156
+ },
157
+ }
93
158
94
- func TestFeatureGateParsing (t * testing.T ) {
95
- // Test various feature gate parsing scenarios
96
- testCases := []struct {
97
- name string
98
- input string
99
- expected map [string ]bool
100
- hasError bool
101
- }{
102
- {
103
- name : "empty string" ,
104
- input : "" ,
105
- expected : map [string ]bool {},
106
- hasError : false ,
107
- },
108
- {
109
- name : "single feature gate" ,
110
- input : "experimental-bar" ,
111
- expected : map [string ]bool {"experimental-bar" : true },
112
- hasError : false ,
113
- },
114
- {
115
- name : "multiple feature gates" ,
116
- input : "experimental-bar,advanced-features" ,
117
- expected : map [string ]bool {
118
- "experimental-bar" : true ,
119
- "advanced-features" : true ,
120
- },
121
- hasError : false ,
122
- },
123
- {
124
- name : "mixed enabled and disabled" ,
125
- input : "experimental-bar=true,advanced-features=false" ,
126
- expected : map [string ]bool {
127
- "experimental-bar" : true ,
128
- "advanced-features" : false ,
129
- },
130
- hasError : false ,
131
- },
132
- {
133
- name : "invalid format" ,
134
- input : "experimental-bar=invalid" ,
135
- expected : nil ,
136
- hasError : true ,
137
- },
138
- }
139
-
140
- for _ , tc := range testCases {
141
- t .Run (tc .name , func (t * testing.T ) {
142
- result , err := machinery .ParseFeatureGates (tc .input )
143
-
144
- if tc .hasError {
145
- assert .Error (t , err )
146
- } else {
147
- assert .NoError (t , err )
148
- assert .Equal (t , machinery .FeatureGates (tc .expected ), result )
159
+ for _ , tc := range testCases {
160
+ By ("testing scenario: " + tc .name )
161
+ result , err := machinery .ParseFeatureGates (tc .input )
162
+
163
+ if tc .hasError {
164
+ Expect (err ).To (HaveOccurred ())
165
+ } else {
166
+ Expect (err ).NotTo (HaveOccurred ())
167
+ Expect (result ).To (Equal (machinery .FeatureGates (tc .expected )))
168
+ }
149
169
}
150
170
})
151
- }
152
- }
171
+ })
172
+
173
+ Context ("when scaffolding a project with feature gates" , func () {
174
+ It ("should generate feature gates file correctly" , func () {
175
+ By ("initializing a project" )
176
+ err := kbc .Init (
177
+ "--plugins" , "go/v4" ,
178
+ "--project-version" , "3" ,
179
+ "--domain" , kbc .Domain ,
180
+ )
181
+ Expect (err ).NotTo (HaveOccurred (), "Failed to initialize project" )
182
+
183
+ By ("creating API with feature gate markers" )
184
+ err = kbc .CreateAPI (
185
+ "--group" , kbc .Group ,
186
+ "--version" , kbc .Version ,
187
+ "--kind" , kbc .Kind ,
188
+ "--make=false" ,
189
+ "--manifests=false" ,
190
+ )
191
+ Expect (err ).NotTo (HaveOccurred (), "Failed to create API definition" )
192
+
193
+ By ("adding feature gate markers to the API types" )
194
+ apiTypesFile := filepath .Join (kbc .Dir , "api" , kbc .Version , strings .ToLower (kbc .Kind )+ "_types.go" )
195
+
196
+ // Add a feature gate marker to the spec
197
+ err = util .InsertCode (
198
+ apiTypesFile ,
199
+ "//+kubebuilder:validation:Optional" ,
200
+ "\n \t // +feature-gate experimental-feature" ,
201
+ )
202
+ Expect (err ).NotTo (HaveOccurred (), "Failed to add feature gate marker" )
203
+
204
+ // Add a field after the marker
205
+ err = util .InsertCode (
206
+ apiTypesFile ,
207
+ "// +feature-gate experimental-feature" ,
208
+ "\n \t ExperimentalField *string `json:\" experimentalField,omitempty\" `" ,
209
+ )
210
+ Expect (err ).NotTo (HaveOccurred (), "Failed to add experimental field" )
211
+
212
+ By ("regenerating the project to discover feature gates" )
213
+ err = kbc .Regenerate ()
214
+ Expect (err ).NotTo (HaveOccurred (), "Failed to regenerate project" )
215
+
216
+ By ("verifying feature gates file was generated" )
217
+ featureGatesFile := filepath .Join (kbc .Dir , "internal" , "featuregates" , "featuregates.go" )
218
+ Expect (featureGatesFile ).To (BeAnExistingFile ())
219
+
220
+ By ("verifying feature gates file contains the discovered feature gate" )
221
+ hasContent , err := util .HasFileContentWith (featureGatesFile , "experimental-feature" )
222
+ Expect (err ).NotTo (HaveOccurred ())
223
+ Expect (hasContent ).To (BeTrue (), "Feature gates file should contain the discovered feature gate" )
224
+ })
225
+ })
226
+ })
0 commit comments