Skip to content

[GEP-2162] Updated a new field on supported features inference from boolean to enum and remove from report. #3885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jul 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions conformance/apis/v1/conformancereport.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ type ConformanceReport struct {
// SucceededProvisionalTests is a list of the names of the provisional tests that
// have been successfully run.
SucceededProvisionalTests []string `json:"succeededProvisionalTests,omitempty"`

// InferredSupportedFeatures indicates whether the supported features were
// automatically detected by the conformance suite.
InferredSupportedFeatures bool `json:"inferredSupportedFeatures"`
}

// Implementation provides metadata information on the downstream
Expand Down
42 changes: 26 additions & 16 deletions conformance/utils/suite/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ type ConformanceTestSuite struct {
// If SupportedFeatures are automatically determined from GWC Status.
// This will be required to report in future iterations as the passing
// will be determined based on this.
isInferredSupportedFeatures bool
supportedFeaturesSource supportedFeaturesSource

// mode is the operating mode of the implementation.
// The default value for it is "default".
Expand Down Expand Up @@ -188,24 +188,37 @@ const (
undefinedKeyword = "UNDEFINED"
)

// SupportedFeaturesSource represents the source from which supported features are derived.
// It is used to distinguish between them being inferred from GWC Status or manually
// supplied for the conformance report.
type supportedFeaturesSource string

const (
supportedFeaturesSourceManual supportedFeaturesSource = "Manual"
supportedFeaturesSourceInferred supportedFeaturesSource = "Inferred"
)

// NewConformanceTestSuite is a helper to use for creating a new ConformanceTestSuite.
func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, error) {
supportedFeatures := options.SupportedFeatures.Difference(options.ExemptFeatures)
isInferred := false
switch {
case options.EnableAllSupportedFeatures:
source := supportedFeaturesSourceManual
if options.EnableAllSupportedFeatures {
supportedFeatures = features.SetsToNamesSet(features.AllFeatures)
case shouldInferSupportedFeatures(&options):
} else if shouldInferSupportedFeatures(&options) {
var err error
supportedFeatures, err = fetchSupportedFeatures(options.Client, options.GatewayClassName)
if err != nil {
return nil, fmt.Errorf("Cannot infer supported features: %w", err)
return nil, fmt.Errorf("cannot infer supported features: %w", err)
}

if hasMeshFeatures(supportedFeatures) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bexxmodd I think this better be a warning + ignoring the features, not actually block the execution.

We can maybe have conformance tests to check that there are no mesh features in GWC if we wanted to.

return nil, fmt.Errorf("mesh features should not be populated in GatewayClass")
}
isInferred = true
source = supportedFeaturesSourceInferred
}

// If features were not inferred from Status, it's a GWC issue.
if isInferred && supportedFeatures.Len() == 0 {
if source == supportedFeaturesSourceInferred && supportedFeatures.Len() == 0 {
return nil, fmt.Errorf("no supported features were determined for test suite")
}

Expand Down Expand Up @@ -273,7 +286,7 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite,
mode: mode,
apiVersion: apiVersion,
apiChannel: apiChannel,
isInferredSupportedFeatures: isInferred,
supportedFeaturesSource: source,
Hook: options.Hook,
}

Expand Down Expand Up @@ -394,10 +407,6 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T, tests []ConformanceTest)
}
}

func (suite *ConformanceTestSuite) IsInferredSupportedFeatures() bool {
return suite.isInferredSupportedFeatures
}

func (suite *ConformanceTestSuite) setClientsetForTest(test ConformanceTest) error {
featureNames := []string{}
for _, v := range test.Features {
Expand Down Expand Up @@ -552,7 +561,6 @@ func (suite *ConformanceTestSuite) Report() (*confv1.ConformanceReport, error) {
GatewayAPIChannel: suite.apiChannel,
ProfileReports: profileReports.list(),
SucceededProvisionalTests: succeededProvisionalTests,
InferredSupportedFeatures: suite.IsInferredSupportedFeatures(),
}, nil
}

Expand Down Expand Up @@ -610,8 +618,6 @@ func shouldInferSupportedFeatures(opts *ConformanceOptions) bool {
return !opts.EnableAllSupportedFeatures &&
opts.SupportedFeatures.Len() == 0 &&
opts.ExemptFeatures.Len() == 0 &&
opts.ConformanceProfiles.Len() == 0 &&
len(opts.SkipTests) == 0 &&
opts.RunTest == ""
}

Expand Down Expand Up @@ -645,3 +651,7 @@ func getAPIVersionAndChannel(crds []apiextensionsv1.CustomResourceDefinition) (v

return version, channel, nil
}

func hasMeshFeatures(f FeaturesSet) bool {
return f.HasAny(features.SetsToNamesSet(features.MeshCoreFeatures, features.MeshExtendedFeatures).UnsortedList()...)
}
69 changes: 60 additions & 9 deletions conformance/utils/suite/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,6 @@ func TestSuiteReport(t *testing.T) {
coreProvisionalTest.ShortName,
extendedProvisionalTest.ShortName,
},
InferredSupportedFeatures: true,
},
},
{
Expand Down Expand Up @@ -390,7 +389,6 @@ func TestSuiteReport(t *testing.T) {
},
},
},
InferredSupportedFeatures: true,
},
},
}
Expand Down Expand Up @@ -434,33 +432,37 @@ func TestInferSupportedFeatures(t *testing.T) {
exemptFeatures FeaturesSet
ConformanceProfile sets.Set[ConformanceProfileName]
expectedFeatures FeaturesSet
expectedIsInferred bool
expectedSource supportedFeaturesSource
}{
{
name: "properly infer supported features",
expectedFeatures: namesToFeatureSet(statusFeatureNames),
expectedIsInferred: true,
name: "properly infer supported features",
expectedFeatures: namesToFeatureSet(statusFeatureNames),
expectedSource: supportedFeaturesSourceInferred,
},
{
name: "no features",
supportedFeatures: sets.New[features.FeatureName]("Gateway"),
expectedFeatures: sets.New[features.FeatureName]("Gateway"),
expectedSource: supportedFeaturesSourceManual,
},
{
name: "remove exempt features",
supportedFeatures: sets.New[features.FeatureName]("Gateway", "HTTPRoute"),
exemptFeatures: sets.New[features.FeatureName]("HTTPRoute"),
expectedFeatures: sets.New[features.FeatureName]("Gateway"),
expectedSource: supportedFeaturesSourceManual,
},
{
name: "allow all features",
allowAllFeatures: true,
expectedFeatures: features.SetsToNamesSet(features.AllFeatures),
expectedSource: supportedFeaturesSourceManual,
},
{
name: "supports conformance profile - core",
ConformanceProfile: sets.New(GatewayHTTPConformanceProfileName),
expectedFeatures: namesToFeatureSet([]string{"Gateway", "HTTPRoute", "ReferenceGrant"}),
expectedFeatures: namesToFeatureSet(statusFeatureNames),
expectedSource: supportedFeaturesSourceInferred,
},
}

Expand Down Expand Up @@ -512,8 +514,8 @@ func TestInferSupportedFeatures(t *testing.T) {
t.Fatalf("error initializing conformance suite: %v", err)
}

if cSuite.IsInferredSupportedFeatures() != tc.expectedIsInferred {
t.Errorf("InferredSupportedFeatures mismatch: got %v, want %v", cSuite.IsInferredSupportedFeatures(), tc.expectedIsInferred)
if cSuite.supportedFeaturesSource != tc.expectedSource {
t.Errorf("InferredSupportedFeatures mismatch: got %v, want %v", cSuite.supportedFeaturesSource, tc.expectedSource)
}

if equal := cSuite.SupportedFeatures.Equal(tc.expectedFeatures); !equal {
Expand All @@ -523,6 +525,55 @@ func TestInferSupportedFeatures(t *testing.T) {
}
}

func TestGWCPublishedMeshFeatures(t *testing.T) {
gwcName := "ochopintre"
gwc := &gatewayv1.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Name: gwcName,
},
Spec: gatewayv1.GatewayClassSpec{
ControllerName: "example.com/gateway-controller",
},
Status: gatewayv1.GatewayClassStatus{
Conditions: []metav1.Condition{
{
Type: string(gatewayv1.GatewayConditionAccepted),
Status: metav1.ConditionTrue,
Reason: "Accepted",
Message: "GatewayClass is accepted and ready for use",
},
},
SupportedFeatures: featureNamesToSet([]string{
string(features.SupportGateway),
string(features.SupportGatewayStaticAddresses),
string(features.SupportMeshClusterIPMatching),
string(features.SupportMeshConsumerRoute),
}),
},
}
scheme := runtime.NewScheme()
scheme.AddKnownTypes(gatewayv1.SchemeGroupVersion, &gatewayv1.GatewayClass{})
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(gwc).
WithLists(&apiextensionsv1.CustomResourceDefinitionList{}).
Build()

gatewayv1.Install(fakeClient.Scheme())
apiextensionsv1.AddToScheme(fakeClient.Scheme())

options := ConformanceOptions{
AllowCRDsMismatch: true,
GatewayClassName: gwcName,
Client: fakeClient,
}

_, err := NewConformanceTestSuite(options)
if err == nil {
t.Fatalf("expected an error but got nil")
}
}

func featureNamesToSet(set []string) []gatewayv1.SupportedFeature {
var features []gatewayv1.SupportedFeature
for _, feature := range set {
Expand Down