Skip to content

Commit c2c3356

Browse files
committed
Conformance: Merging SupportedFeatures and ExemptFeatures, adding TLSRoute feature
1 parent 0b19b47 commit c2c3356

12 files changed

+55
-62
lines changed

conformance/conformance_test.go

+9-17
Original file line numberDiff line numberDiff line change
@@ -47,36 +47,28 @@ func TestConformance(t *testing.T) {
4747
t.Logf("Running conformance tests with %s GatewayClass", *flags.GatewayClassName)
4848

4949
supportedFeatures := parseSupportedFeatures(*flags.SupportedFeatures)
50-
exemptFeatures := parseExemptFeatures(*flags.ExemptFeatures)
50+
exemptFeatures := parseSupportedFeatures(*flags.ExemptFeatures)
51+
for feature := range exemptFeatures {
52+
supportedFeatures[feature] = false
53+
}
5154

5255
cSuite := suite.New(suite.Options{
5356
Client: client,
5457
GatewayClassName: *flags.GatewayClassName,
5558
Debug: *flags.ShowDebug,
5659
CleanupBaseResources: *flags.CleanupBaseResources,
5760
SupportedFeatures: supportedFeatures,
58-
ExemptFeatures: exemptFeatures,
5961
})
6062
cSuite.Setup(t)
6163
cSuite.Run(t, tests.ConformanceTests)
6264
}
6365

64-
// parseSupportedFeatures parses the arguments for supported-features flag,
65-
// then converts the string to []suite.SupportedFeature
66-
func parseSupportedFeatures(f string) []suite.SupportedFeature {
67-
var res []suite.SupportedFeature
68-
for _, value := range strings.Split(f, ",") {
69-
res = append(res, suite.SupportedFeature(value))
70-
}
71-
return res
72-
}
73-
74-
// parseExemptFeatures parses the arguments for exempt-features flag,
75-
// then converts the string to []suite.ExemptFeature
76-
func parseExemptFeatures(f string) []suite.ExemptFeature {
77-
var res []suite.ExemptFeature
66+
// parseSupportedFeatures parses flag arguments and converts the string to
67+
// map[suite.SupportedFeature]bool
68+
func parseSupportedFeatures(f string) map[suite.SupportedFeature]bool {
69+
res := map[suite.SupportedFeature]bool{}
7870
for _, value := range strings.Split(f, ",") {
79-
res = append(res, suite.ExemptFeature(value))
71+
res[suite.SupportedFeature(value)] = true
8072
}
8173
return res
8274
}

conformance/tests/gateway-unsupported-route-kind.go conformance/tests/gateway-invalid-route-kind.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ import (
2828
)
2929

3030
func init() {
31-
ConformanceTests = append(ConformanceTests, GatewayUnsupportedRouteKind)
31+
ConformanceTests = append(ConformanceTests, GatewayInvalidRouteKind)
3232
}
3333

34-
var GatewayUnsupportedRouteKind = suite.ConformanceTest{
35-
ShortName: "GatewayUnsupportedRouteKind",
36-
Description: "A Gateway in the gateway-conformance-infra namespace should fail to become ready if explicitly supports any route type incompatible with the protocol type, even if there are types which are valid as well.",
37-
Manifests: []string{"tests/gateway-unsupported-route-kind.yaml"},
34+
var GatewayInvalidRouteKind = suite.ConformanceTest{
35+
ShortName: "GatewayInvalidRouteKind",
36+
Description: "A Gateway in the gateway-conformance-infra namespace should fail to become ready an invalid Route kind is specified.",
37+
Manifests: []string{"tests/gateway-invalid-route-kind.yaml"},
3838
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
3939
t.Run("Gateway listener should have a false ResolvedRefs condition with reason InvalidRouteKinds and no supportedKinds", func(t *testing.T) {
40-
gwNN := types.NamespacedName{Name: "gateway-only-unsupported-route-kind", Namespace: "gateway-conformance-infra"}
40+
gwNN := types.NamespacedName{Name: "gateway-only-invalid-route-kind", Namespace: "gateway-conformance-infra"}
4141
listeners := []v1beta1.ListenerStatus{{
4242
Name: v1beta1.SectionName("http"),
4343
SupportedKinds: []v1beta1.RouteGroupKind{},
@@ -52,7 +52,7 @@ var GatewayUnsupportedRouteKind = suite.ConformanceTest{
5252
})
5353

5454
t.Run("Gateway listener should have a false ResolvedRefs condition with reason InvalidRouteKinds and HTTPRoute must be put in the supportedKinds", func(t *testing.T) {
55-
gwNN := types.NamespacedName{Name: "gateway-supported-and-unsupported-route-kind", Namespace: "gateway-conformance-infra"}
55+
gwNN := types.NamespacedName{Name: "gateway-supported-and-invalid-route-kind", Namespace: "gateway-conformance-infra"}
5656
listeners := []v1beta1.ListenerStatus{{
5757
Name: v1beta1.SectionName("http"),
5858
SupportedKinds: []v1beta1.RouteGroupKind{{

conformance/tests/gateway-unsupported-route-kind.yaml conformance/tests/gateway-invalid-route-kind.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: gateway.networking.k8s.io/v1beta1
22
kind: Gateway
33
metadata:
4-
name: gateway-only-unsupported-route-kind
4+
name: gateway-only-invalid-route-kind
55
namespace: gateway-conformance-infra
66
spec:
77
gatewayClassName: "{GATEWAY_CLASS_NAME}"
@@ -13,12 +13,12 @@ spec:
1313
namespaces:
1414
from: All
1515
kinds:
16-
- kind: UDPRoute
16+
- kind: InvalidRoute
1717
---
1818
apiVersion: gateway.networking.k8s.io/v1beta1
1919
kind: Gateway
2020
metadata:
21-
name: gateway-supported-and-unsupported-route-kind
21+
name: gateway-supported-and-invalid-route-kind
2222
namespace: gateway-conformance-infra
2323
spec:
2424
gatewayClassName: "{GATEWAY_CLASS_NAME}"
@@ -30,5 +30,5 @@ spec:
3030
namespaces:
3131
from: All
3232
kinds:
33-
- kind: UDPRoute
33+
- kind: InvalidRoute
3434
- kind: HTTPRoute

conformance/tests/gateway-secret-invalid-reference-grant.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func init() {
3434
var GatewaySecretInvalidReferenceGrant = suite.ConformanceTest{
3535
ShortName: "GatewaySecretInvalidReferenceGrant",
3636
Description: "A Gateway in the gateway-conformance-infra namespace should fail to become ready if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant exists but does not grant permission to that specific Secret",
37-
Exemptions: []suite.ExemptFeature{suite.ExemptReferenceGrant},
37+
Features: []suite.SupportedFeature{suite.SupportReferenceGrant},
3838
Manifests: []string{"tests/gateway-secret-invalid-reference-grant.yaml"},
3939
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
4040
gwNN := types.NamespacedName{Name: "gateway-secret-invalid-reference-grant", Namespace: "gateway-conformance-infra"}

conformance/tests/gateway-secret-missing-reference-grant.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func init() {
3434
var GatewaySecretMissingReferenceGrant = suite.ConformanceTest{
3535
ShortName: "GatewaySecretMissingReferenceGrant",
3636
Description: "A Gateway in the gateway-conformance-infra namespace should fail to become ready if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to the Secret does not exist",
37-
Exemptions: []suite.ExemptFeature{suite.ExemptReferenceGrant},
37+
Features: []suite.SupportedFeature{suite.SupportReferenceGrant},
3838
Manifests: []string{"tests/gateway-secret-missing-reference-grant.yaml"},
3939
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
4040
gwNN := types.NamespacedName{Name: "gateway-secret-missing-reference-grant", Namespace: "gateway-conformance-infra"}

conformance/tests/gateway-secret-reference-grant-all-in-namespace.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func init() {
3434
var GatewaySecretReferenceGrantAllInNamespace = suite.ConformanceTest{
3535
ShortName: "GatewaySecretReferenceGrantAllInNamespace",
3636
Description: "A Gateway in the gateway-conformance-infra namespace should become ready if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to all Secrets in the namespace exists",
37-
Exemptions: []suite.ExemptFeature{suite.ExemptReferenceGrant},
37+
Features: []suite.SupportedFeature{suite.SupportReferenceGrant},
3838
Manifests: []string{"tests/gateway-secret-reference-grant-all-in-namespace.yaml"},
3939
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
4040
gwNN := types.NamespacedName{Name: "gateway-secret-reference-grant", Namespace: "gateway-conformance-infra"}

conformance/tests/gateway-secret-reference-grant-specific.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func init() {
3434
var GatewaySecretReferenceGrantSpecific = suite.ConformanceTest{
3535
ShortName: "GatewaySecretReferenceGrantSpecific",
3636
Description: "A Gateway in the gateway-conformance-infra namespace should become ready if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to the specific Secret exists",
37-
Exemptions: []suite.ExemptFeature{suite.ExemptReferenceGrant},
37+
Features: []suite.SupportedFeature{suite.SupportReferenceGrant},
3838
Manifests: []string{"tests/gateway-secret-reference-grant-specific.yaml"},
3939
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
4040
gwNN := types.NamespacedName{Name: "gateway-secret-reference-grant", Namespace: "gateway-conformance-infra"}

conformance/tests/httproute-disallowed-kind.go

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func init() {
3232
var HTTPRouteDisallowedKind = suite.ConformanceTest{
3333
ShortName: "HTTPRouteDisallowedKind",
3434
Description: "A single HTTPRoute in the gateway-conformance-infra namespace should fail to attach to a Listener that does not allow the HTTPRoute kind",
35+
Features: []suite.SupportedFeature{suite.SupportTLSRoute},
3536
Manifests: []string{"tests/httproute-disallowed-kind.yaml"},
3637
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
3738
// This test creates an additional Gateway in the gateway-conformance-infra

conformance/tests/httproute-invalid-cross-namespace-backend-ref.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func init() {
3535
var HTTPRouteInvalidCrossNamespaceBackendRef = suite.ConformanceTest{
3636
ShortName: "HTTPRouteInvalidCrossNamespaceBackendRef",
3737
Description: "A single HTTPRoute in the gateway-conformance-infra namespace should set a ResolvedRefs status False with reason RefNotPermitted when attempting to bind to a Gateway in the same namespace if the route has a BackendRef Service in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to route to that Service does not exist",
38-
Exemptions: []suite.ExemptFeature{suite.ExemptReferenceGrant},
38+
Features: []suite.SupportedFeature{suite.SupportReferenceGrant},
3939
Manifests: []string{"tests/httproute-invalid-cross-namespace-backend-ref.yaml"},
4040
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
4141
routeNN := types.NamespacedName{Name: "invalid-cross-namespace-backend-ref", Namespace: "gateway-conformance-infra"}

conformance/tests/httproute-invalid-reference-grant.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func init() {
3535
var HTTPRouteInvalidReferenceGrant = suite.ConformanceTest{
3636
ShortName: "HTTPRouteInvalidReferenceGrant",
3737
Description: "A single HTTPRoute in the gateway-conformance-infra namespace should fail to attach to a Gateway in the same namespace if the route has a backendRef Service in the gateway-conformance-app-backend namespace and a ReferenceGrant exists but does not grant permission to route to that specific Service",
38-
Exemptions: []suite.ExemptFeature{suite.ExemptReferenceGrant},
38+
Features: []suite.SupportedFeature{suite.SupportReferenceGrant},
3939
Manifests: []string{"tests/httproute-invalid-reference-grant.yaml"},
4040
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
4141
routeNN := types.NamespacedName{Name: "invalid-reference-grant", Namespace: "gateway-conformance-infra"}

conformance/tests/httproute-reference-grant.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func init() {
3333
var HTTPRouteReferenceGrant = suite.ConformanceTest{
3434
ShortName: "HTTPRouteReferenceGrant",
3535
Description: "A single HTTPRoute in the gateway-conformance-infra namespace, with a backendRef in the gateway-conformance-web-backend namespace, should attach to Gateway in the gateway-conformance-infra namespace",
36-
Exemptions: []suite.ExemptFeature{suite.ExemptReferenceGrant},
36+
Features: []suite.SupportedFeature{suite.SupportReferenceGrant},
3737
Manifests: []string{"tests/httproute-reference-grant.yaml"},
3838
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
3939
routeNN := types.NamespacedName{Name: "reference-grant", Namespace: "gateway-conformance-infra"}

conformance/utils/suite/suite.go

+27-27
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package suite
1919
import (
2020
"testing"
2121

22-
"golang.org/x/exp/slices"
2322
"sigs.k8s.io/controller-runtime/pkg/client"
2423

2524
"sigs.k8s.io/gateway-api/apis/v1beta1"
@@ -28,22 +27,19 @@ import (
2827
"sigs.k8s.io/gateway-api/conformance/utils/roundtripper"
2928
)
3029

31-
// ExemptFeature allows opting out of core conformance tests at an
32-
// individual feature granularity.
33-
type ExemptFeature string
34-
35-
const (
36-
// This option indicates the implementation is exempting itself from the
37-
// requirement of a ReferenceGrant to allow cross-namespace references,
38-
// and has instead implemented alternative safeguards.
39-
ExemptReferenceGrant ExemptFeature = "ReferenceGrant"
40-
)
41-
4230
// SupportedFeature allows opting in to additional conformance tests at an
4331
// individual feature granularity.
4432
type SupportedFeature string
4533

4634
const (
35+
// This option indicates support for ReferenceGrant (core conformance).
36+
// Opting out of this requires an implementation to have clearly implemented
37+
// and documented equivalent safeguards.
38+
SupportReferenceGrant SupportedFeature = "ReferenceGrant"
39+
40+
// This option indicates support for TLSRoute (extended conformance).
41+
SupportTLSRoute SupportedFeature = "TLSRoute"
42+
4743
// This option indicates support for HTTPRoute query param matching (extended conformance).
4844
SupportHTTPRouteQueryParamMatching SupportedFeature = "HTTPRouteQueryParamMatching"
4945

@@ -54,6 +50,12 @@ const (
5450
SupportHTTPResponseHeaderModification SupportedFeature = "HTTPResponseHeaderModification"
5551
)
5652

53+
// StandardCoreFeatures are the features that are required to be conformant with
54+
// the Core API features that are part of the Standard release channel.
55+
var StandardCoreFeatures = map[SupportedFeature]bool{
56+
SupportReferenceGrant: true,
57+
}
58+
5759
// ConformanceTestSuite defines the test suite used to run Gateway API
5860
// conformance tests.
5961
type ConformanceTestSuite struct {
@@ -65,8 +67,7 @@ type ConformanceTestSuite struct {
6567
Cleanup bool
6668
BaseManifests string
6769
Applier kubernetes.Applier
68-
ExemptFeatures []ExemptFeature
69-
SupportedFeatures []SupportedFeature
70+
SupportedFeatures map[SupportedFeature]bool
7071
TimeoutConfig config.TimeoutConfig
7172
}
7273

@@ -89,8 +90,7 @@ type Options struct {
8990
// CleanupBaseResources indicates whether or not the base test
9091
// resources such as Gateways should be cleaned up after the run.
9192
CleanupBaseResources bool
92-
ExemptFeatures []ExemptFeature
93-
SupportedFeatures []SupportedFeature
93+
SupportedFeatures map[SupportedFeature]bool
9494
TimeoutConfig config.TimeoutConfig
9595
}
9696

@@ -103,6 +103,16 @@ func New(s Options) *ConformanceTestSuite {
103103
roundTripper = &roundtripper.DefaultRoundTripper{Debug: s.Debug, TimeoutConfig: s.TimeoutConfig}
104104
}
105105

106+
if s.SupportedFeatures == nil {
107+
s.SupportedFeatures = StandardCoreFeatures
108+
} else {
109+
for feature, val := range StandardCoreFeatures {
110+
if _, ok := s.SupportedFeatures[feature]; !ok {
111+
s.SupportedFeatures[feature] = val
112+
}
113+
}
114+
}
115+
106116
suite := &ConformanceTestSuite{
107117
Client: s.Client,
108118
RoundTripper: roundTripper,
@@ -114,7 +124,6 @@ func New(s Options) *ConformanceTestSuite {
114124
NamespaceLabels: s.NamespaceLabels,
115125
ValidUniqueListenerPorts: s.ValidUniqueListenerPorts,
116126
},
117-
ExemptFeatures: s.ExemptFeatures,
118127
SupportedFeatures: s.SupportedFeatures,
119128
TimeoutConfig: s.TimeoutConfig,
120129
}
@@ -164,7 +173,6 @@ func (suite *ConformanceTestSuite) Run(t *testing.T, tests []ConformanceTest) {
164173
type ConformanceTest struct {
165174
ShortName string
166175
Description string
167-
Exemptions []ExemptFeature
168176
Features []SupportedFeature
169177
Manifests []string
170178
Slow bool
@@ -182,19 +190,11 @@ func (test *ConformanceTest) Run(t *testing.T, suite *ConformanceTestSuite) {
182190
// Check that all features exercised by the test have been opted into by
183191
// the suite.
184192
for _, feature := range test.Features {
185-
if !slices.Contains(suite.SupportedFeatures, feature) {
193+
if supported, ok := suite.SupportedFeatures[feature]; !ok || !supported {
186194
t.Skipf("Skipping %s: suite does not support %s", test.ShortName, feature)
187195
}
188196
}
189197

190-
// Check that no features exercised by the test have been opted out of by
191-
// the suite.
192-
for _, feature := range test.Exemptions {
193-
if slices.Contains(suite.ExemptFeatures, feature) {
194-
t.Skipf("Skipping %s: suite exempts %s", test.ShortName, feature)
195-
}
196-
}
197-
198198
for _, manifestLocation := range test.Manifests {
199199
t.Logf("Applying %s", manifestLocation)
200200
suite.Applier.MustApplyWithCleanup(t, suite.Client, suite.TimeoutConfig, manifestLocation, suite.GatewayClassName, true)

0 commit comments

Comments
 (0)