@@ -31,11 +31,13 @@ import (
31
31
"github.com/stretchr/testify/require"
32
32
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
33
33
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34
+ "k8s.io/apimachinery/pkg/types"
34
35
"k8s.io/apimachinery/pkg/util/sets"
35
36
clientset "k8s.io/client-go/kubernetes"
36
37
"k8s.io/client-go/rest"
37
38
"sigs.k8s.io/controller-runtime/pkg/client"
38
39
40
+ gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
39
41
"sigs.k8s.io/gateway-api/apis/v1beta1"
40
42
confv1 "sigs.k8s.io/gateway-api/conformance/apis/v1"
41
43
"sigs.k8s.io/gateway-api/conformance/utils/config"
@@ -69,7 +71,7 @@ type ConformanceTestSuite struct {
69
71
BaseManifests string
70
72
MeshManifests string
71
73
Applier kubernetes.Applier
72
- SupportedFeatures sets. Set [features. FeatureName ]
74
+ SupportedFeatures FeaturesSet
73
75
TimeoutConfig config.TimeoutConfig
74
76
SkipTests sets.Set [string ]
75
77
SkipProvisionalTests bool
@@ -79,6 +81,11 @@ type ConformanceTestSuite struct {
79
81
UsableNetworkAddresses []v1beta1.GatewaySpecAddress
80
82
UnusableNetworkAddresses []v1beta1.GatewaySpecAddress
81
83
84
+ // If SupportedFeatures are automatically determined from GWC Status.
85
+ // This will be required to report in future iterations as the passing
86
+ // will be determined based on this.
87
+ isInferredSupportedFeatures bool
88
+
82
89
// mode is the operating mode of the implementation.
83
90
// The default value for it is "default".
84
91
mode string
@@ -142,8 +149,8 @@ type ConformanceOptions struct {
142
149
// CleanupBaseResources indicates whether or not the base test
143
150
// resources such as Gateways should be cleaned up after the run.
144
151
CleanupBaseResources bool
145
- SupportedFeatures sets. Set [features. FeatureName ]
146
- ExemptFeatures sets. Set [features. FeatureName ]
152
+ SupportedFeatures FeaturesSet
153
+ ExemptFeatures FeaturesSet
147
154
EnableAllSupportedFeatures bool
148
155
TimeoutConfig config.TimeoutConfig
149
156
// SkipTests contains all the tests not to be run and can be used to opt out
@@ -172,6 +179,8 @@ type ConformanceOptions struct {
172
179
ConformanceProfiles sets.Set [ConformanceProfileName ]
173
180
}
174
181
182
+ type FeaturesSet = sets.Set [features.FeatureName ]
183
+
175
184
const (
176
185
// undefinedKeyword is set in the ConformanceReport "GatewayAPIVersion" and
177
186
// "GatewayAPIChannel" fields in case it's not possible to figure out the actual
@@ -181,16 +190,23 @@ const (
181
190
182
191
// NewConformanceTestSuite is a helper to use for creating a new ConformanceTestSuite.
183
192
func NewConformanceTestSuite (options ConformanceOptions ) (* ConformanceTestSuite , error ) {
184
- // test suite callers are required to provide either:
185
- // - one conformance profile via the flag '-conformance-profiles'
186
- // - a list of supported features via the flag '-supported-features'
187
- // - an explicit test to run via the flag '-run-test'
188
- // - all features are being tested via the flag '-all-features'
189
- if options .SupportedFeatures .Len () == 0 &&
190
- options .ConformanceProfiles .Len () == 0 &&
191
- ! options .EnableAllSupportedFeatures &&
192
- options .RunTest == "" {
193
- return nil , fmt .Errorf ("no conformance profile, supported features, explicit tests were provided so no tests could be selected" )
193
+ supportedFeatures := options .SupportedFeatures .Difference (options .ExemptFeatures )
194
+ isInferred := false
195
+ switch {
196
+ case options .EnableAllSupportedFeatures :
197
+ supportedFeatures = features .SetsToNamesSet (features .AllFeatures )
198
+ case shouldInferSupportedFeatures (& options ):
199
+ var err error
200
+ supportedFeatures , err = fetchSupportedFeatures (options .Client , options .GatewayClassName )
201
+ if err != nil {
202
+ return nil , fmt .Errorf ("Cannot infer supported features: %w" , err )
203
+ }
204
+ isInferred = true
205
+ }
206
+
207
+ // If features were not inferred from Status, it's a GWC issue.
208
+ if isInferred && supportedFeatures .Len () == 0 {
209
+ return nil , fmt .Errorf ("no supported features were determined for test suite" )
194
210
}
195
211
196
212
config .SetupTimeoutConfig (& options .TimeoutConfig )
@@ -224,19 +240,6 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite,
224
240
mode = options .Mode
225
241
}
226
242
227
- // test suite callers can potentially just run all tests by saying they
228
- // cover all features, if they don't they'll need to have provided a
229
- // conformance profile or at least some specific features they support.
230
- if options .EnableAllSupportedFeatures {
231
- options .SupportedFeatures = features .SetsToNamesSet (features .AllFeatures )
232
- } else if options .SupportedFeatures == nil {
233
- options .SupportedFeatures = sets .New [features.FeatureName ]()
234
- }
235
-
236
- for feature := range options .ExemptFeatures {
237
- options .SupportedFeatures .Delete (feature )
238
- }
239
-
240
243
suite := & ConformanceTestSuite {
241
244
Client : options .Client ,
242
245
ClientOptions : options .ClientOptions ,
@@ -254,7 +257,7 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite,
254
257
NamespaceAnnotations : options .NamespaceAnnotations ,
255
258
AddressType : options .AddressType ,
256
259
},
257
- SupportedFeatures : options . SupportedFeatures ,
260
+ SupportedFeatures : supportedFeatures ,
258
261
TimeoutConfig : options .TimeoutConfig ,
259
262
SkipTests : sets .New (options .SkipTests ... ),
260
263
RunTest : options .RunTest ,
@@ -270,6 +273,7 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite,
270
273
mode : mode ,
271
274
apiVersion : apiVersion ,
272
275
apiChannel : apiChannel ,
276
+ isInferredSupportedFeatures : isInferred ,
273
277
Hook : options .Hook ,
274
278
}
275
279
@@ -288,12 +292,12 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite,
288
292
for _ , f := range conformanceProfile .ExtendedFeatures .UnsortedList () {
289
293
if options .SupportedFeatures .Has (f ) {
290
294
if suite .extendedSupportedFeatures [conformanceProfileName ] == nil {
291
- suite .extendedSupportedFeatures [conformanceProfileName ] = sets . New [features. FeatureName ]()
295
+ suite .extendedSupportedFeatures [conformanceProfileName ] = FeaturesSet {}
292
296
}
293
297
suite .extendedSupportedFeatures [conformanceProfileName ].Insert (f )
294
298
} else {
295
299
if suite .extendedUnsupportedFeatures [conformanceProfileName ] == nil {
296
- suite .extendedUnsupportedFeatures [conformanceProfileName ] = sets . New [features. FeatureName ]()
300
+ suite .extendedUnsupportedFeatures [conformanceProfileName ] = FeaturesSet {}
297
301
}
298
302
suite .extendedUnsupportedFeatures [conformanceProfileName ].Insert (f )
299
303
}
@@ -390,6 +394,10 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T, tests []ConformanceTest)
390
394
}
391
395
}
392
396
397
+ func (suite * ConformanceTestSuite ) IsInferredSupportedFeatures () bool {
398
+ return suite .isInferredSupportedFeatures
399
+ }
400
+
393
401
func (suite * ConformanceTestSuite ) setClientsetForTest (test ConformanceTest ) error {
394
402
featureNames := []string {}
395
403
for _ , v := range test .Features {
@@ -544,6 +552,7 @@ func (suite *ConformanceTestSuite) Report() (*confv1.ConformanceReport, error) {
544
552
GatewayAPIChannel : suite .apiChannel ,
545
553
ProfileReports : profileReports .list (),
546
554
SucceededProvisionalTests : succeededProvisionalTests ,
555
+ InferredSupportedFeatures : suite .IsInferredSupportedFeatures (),
547
556
}, nil
548
557
}
549
558
@@ -573,6 +582,39 @@ func ParseConformanceProfiles(p string) sets.Set[ConformanceProfileName] {
573
582
return res
574
583
}
575
584
585
+ func fetchSupportedFeatures (client client.Client , gatewayClassName string ) (FeaturesSet , error ) {
586
+ if gatewayClassName == "" {
587
+ return nil , fmt .Errorf ("GatewayClass name must be provided to fetch supported features" )
588
+ }
589
+ gwc := & gatewayv1.GatewayClass {}
590
+ err := client .Get (context .TODO (), types.NamespacedName {Name : gatewayClassName }, gwc )
591
+ if err != nil {
592
+ return nil , fmt .Errorf ("fetchSupportedFeatures(): %w" , err )
593
+ }
594
+
595
+ fs := FeaturesSet {}
596
+ for _ , feature := range gwc .Status .SupportedFeatures {
597
+ fs .Insert (features .FeatureName (feature .Name ))
598
+ }
599
+ fmt .Printf ("Supported features for GatewayClass %s: %v\n " , gatewayClassName , fs .UnsortedList ())
600
+ return fs , nil
601
+ }
602
+
603
+ // shouldInferSupportedFeatures checks if any flags were supplied for manually
604
+ // picking what to test. Inferred supported features are only used when no flags
605
+ // are set.
606
+ func shouldInferSupportedFeatures (opts * ConformanceOptions ) bool {
607
+ if opts == nil {
608
+ return false
609
+ }
610
+ return ! opts .EnableAllSupportedFeatures &&
611
+ opts .SupportedFeatures .Len () == 0 &&
612
+ opts .ExemptFeatures .Len () == 0 &&
613
+ opts .ConformanceProfiles .Len () == 0 &&
614
+ len (opts .SkipTests ) == 0 &&
615
+ opts .RunTest == ""
616
+ }
617
+
576
618
// getAPIVersionAndChannel iterates over all the crds installed in the cluster and check the version and channel annotations.
577
619
// In case the annotations are not found or there are crds with different versions or channels, an error is returned.
578
620
func getAPIVersionAndChannel (crds []apiextensionsv1.CustomResourceDefinition ) (version string , channel string , err error ) {
0 commit comments