Skip to content

Commit a29df94

Browse files
UPSTREAM: <carry>: [OTE] add webhook tests
Migrates OLMv1 webhook operator tests from using external YAML files to defining resources in Go structs. This change removes file dependencies, improving test reliability and simplifying test setup. The migration is a refactoring of code from openshift/origin#30059. The new code uses better naming conventions and adapts the tests to work with a controller-runtime client, enhancing test consistency and maintainability. The migration covers all core test scenarios: - Validating, mutating, and conversion webhooks. - Certificate and secret rotation tolerance. Assisted-by: Gemini
1 parent 778bd57 commit a29df94

File tree

5 files changed

+488
-53
lines changed

5 files changed

+488
-53
lines changed

openshift/tests-extension/.openshift-tests-extension/openshift_payload_olmv1.json

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,55 @@
4848
"source": "openshift:payload:olmv1",
4949
"lifecycle": "blocking",
5050
"environmentSelector": {}
51+
},
52+
{
53+
"name": "[sig-olmv1][OCPFeatureGate:NewOLMWebhookProviderOpenshiftServiceCA][Skipped:Disconnected][Serial] OLMv1 operator with webhooks should have a working validating webhook",
54+
"labels": {},
55+
"resources": {
56+
"isolation": {}
57+
},
58+
"source": "openshift:payload:olmv1",
59+
"lifecycle": "blocking",
60+
"environmentSelector": {}
61+
},
62+
{
63+
"name": "[sig-olmv1][OCPFeatureGate:NewOLMWebhookProviderOpenshiftServiceCA][Skipped:Disconnected][Serial] OLMv1 operator with webhooks should have a working mutating webhook",
64+
"labels": {},
65+
"resources": {
66+
"isolation": {}
67+
},
68+
"source": "openshift:payload:olmv1",
69+
"lifecycle": "blocking",
70+
"environmentSelector": {}
71+
},
72+
{
73+
"name": "[sig-olmv1][OCPFeatureGate:NewOLMWebhookProviderOpenshiftServiceCA][Skipped:Disconnected][Serial] OLMv1 operator with webhooks should have a working conversion webhook",
74+
"labels": {},
75+
"resources": {
76+
"isolation": {}
77+
},
78+
"source": "openshift:payload:olmv1",
79+
"lifecycle": "blocking",
80+
"environmentSelector": {}
81+
},
82+
{
83+
"name": "[sig-olmv1][OCPFeatureGate:NewOLMWebhookProviderOpenshiftServiceCA][Skipped:Disconnected][Serial] OLMv1 operator with webhooks should be tolerant to openshift-service-ca certificate rotation",
84+
"labels": {},
85+
"resources": {
86+
"isolation": {}
87+
},
88+
"source": "openshift:payload:olmv1",
89+
"lifecycle": "blocking",
90+
"environmentSelector": {}
91+
},
92+
{
93+
"name": "[sig-olmv1][OCPFeatureGate:NewOLMWebhookProviderOpenshiftServiceCA][Skipped:Disconnected][Serial] OLMv1 operator with webhooks should be tolerant to tls secret deletion",
94+
"labels": {},
95+
"resources": {
96+
"isolation": {}
97+
},
98+
"source": "openshift:payload:olmv1",
99+
"lifecycle": "blocking",
100+
"environmentSelector": {}
51101
}
52102
]
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package helpers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
//nolint:staticcheck // ST1001: dot-imports for readability
9+
. "github.com/onsi/gomega"
10+
11+
"k8s.io/apimachinery/pkg/api/meta"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"sigs.k8s.io/controller-runtime/pkg/client"
14+
15+
olmv1 "github.com/operator-framework/operator-controller/api/v1"
16+
17+
"github/operator-framework-operator-controller/openshift/tests-extension/pkg/env"
18+
)
19+
20+
// NewClusterCatalog returns a new ClusterCatalog object.
21+
// It sets the image reference as source.
22+
func NewClusterCatalog(name, imageRef string) *olmv1.ClusterCatalog {
23+
return &olmv1.ClusterCatalog{
24+
ObjectMeta: metav1.ObjectMeta{
25+
Name: name,
26+
},
27+
Spec: olmv1.ClusterCatalogSpec{
28+
Source: olmv1.CatalogSource{
29+
Type: olmv1.SourceTypeImage,
30+
Image: &olmv1.ImageSource{
31+
Ref: imageRef,
32+
},
33+
},
34+
},
35+
}
36+
}
37+
38+
// ExpectCatalogToBeServing checks that the catalog with the given name is installed
39+
func ExpectCatalogToBeServing(ctx context.Context, name string) {
40+
k8sClient := env.Get().K8sClient
41+
Eventually(func(g Gomega) {
42+
var catalog olmv1.ClusterCatalog
43+
err := k8sClient.Get(ctx, client.ObjectKey{Name: name}, &catalog)
44+
g.Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("failed to get catalog %q", name))
45+
46+
conditions := catalog.Status.Conditions
47+
g.Expect(conditions).NotTo(BeEmpty(), fmt.Sprintf("catalog %q has empty status.conditions", name))
48+
49+
g.Expect(meta.IsStatusConditionPresentAndEqual(conditions, olmv1.TypeServing, metav1.ConditionTrue)).
50+
To(BeTrue(), fmt.Sprintf("catalog %q is not serving", name))
51+
}).WithTimeout(5 * time.Minute).WithPolling(5 * time.Second).Should(Succeed())
52+
}

openshift/tests-extension/pkg/helpers/cluster_extension.go

Lines changed: 71 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,27 @@ package helpers
22

33
import (
44
"context"
5+
"fmt"
6+
"time"
57

68
//nolint:staticcheck // ST1001: dot-imports for readability
79
. "github.com/onsi/gomega"
810

911
corev1 "k8s.io/api/core/v1"
1012
rbacv1 "k8s.io/api/rbac/v1"
13+
"k8s.io/apimachinery/pkg/api/meta"
1114
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1215
"k8s.io/apimachinery/pkg/util/rand"
16+
"sigs.k8s.io/controller-runtime/pkg/client"
1317

14-
ocv1 "github.com/operator-framework/operator-controller/api/v1"
18+
olmv1 "github.com/operator-framework/operator-controller/api/v1"
1519

1620
"github/operator-framework-operator-controller/openshift/tests-extension/pkg/env"
1721
)
1822

19-
const openshiftOperatorsNs = "openshift-operators"
20-
2123
// CreateClusterExtension creates a ServiceAccount, ClusterRoleBinding, and ClusterExtension using typed APIs.
2224
// It returns the unique suffix and a cleanup function.
23-
func CreateClusterExtension(packageName, version string) (string, func()) {
25+
func CreateClusterExtension(packageName, version, namespace string) (string, func()) {
2426
ctx := context.TODO()
2527
k8sClient := env.Get().K8sClient
2628
unique := rand.String(8)
@@ -30,59 +32,92 @@ func CreateClusterExtension(packageName, version string) (string, func()) {
3032
ceName := "install-test-ce-" + unique
3133

3234
// 1. Create ServiceAccount
33-
sa := &corev1.ServiceAccount{
34-
ObjectMeta: metav1.ObjectMeta{
35-
Name: saName,
36-
Namespace: openshiftOperatorsNs,
37-
},
38-
}
39-
Expect(k8sClient.Create(ctx, sa)).To(Succeed(), "failed to create ServiceAccount")
35+
sa := NewServiceAccount(saName, namespace)
36+
Expect(k8sClient.Create(ctx, sa)).To(Succeed(),
37+
"failed to create ServiceAccount")
4038

4139
// 2. Create ClusterRoleBinding
42-
crb := &rbacv1.ClusterRoleBinding{
40+
crb := NewClusterRoleBinding(crbName, "cluster-admin", saName, namespace)
41+
Expect(k8sClient.Create(ctx, crb)).To(Succeed(), "failed to create ClusterRoleBinding")
42+
43+
// 3. Create ClusterExtension
44+
ce := NewClusterExtensionObject(packageName, version, ceName, saName, namespace)
45+
Expect(k8sClient.Create(ctx, ce)).To(Succeed(), "failed to create ClusterExtension")
46+
47+
// Cleanup closure
48+
return ceName, func() {
49+
_ = k8sClient.Delete(ctx, ce)
50+
_ = k8sClient.Delete(ctx, crb)
51+
_ = k8sClient.Delete(ctx, sa)
52+
}
53+
}
54+
55+
// NewServiceAccount creates a new ServiceAccount object in the openshift-operators namespace.
56+
func NewServiceAccount(name, namespace string) *corev1.ServiceAccount {
57+
return &corev1.ServiceAccount{
4358
ObjectMeta: metav1.ObjectMeta{
44-
Name: crbName,
59+
Name: name,
60+
Namespace: namespace,
4561
},
62+
}
63+
}
64+
65+
// NewClusterRoleBinding creates a new ClusterRoleBinding object that binds a ClusterRole to a ServiceAccount.
66+
func NewClusterRoleBinding(name, roleName, saName, namespace string) *rbacv1.ClusterRoleBinding {
67+
return &rbacv1.ClusterRoleBinding{
68+
ObjectMeta: metav1.ObjectMeta{Name: name},
4669
RoleRef: rbacv1.RoleRef{
4770
APIGroup: "rbac.authorization.k8s.io",
4871
Kind: "ClusterRole",
49-
Name: "cluster-admin",
72+
Name: roleName,
5073
},
5174
Subjects: []rbacv1.Subject{{
5275
Kind: "ServiceAccount",
5376
Name: saName,
54-
Namespace: openshiftOperatorsNs,
77+
Namespace: namespace,
5578
}},
5679
}
57-
Expect(k8sClient.Create(ctx, crb)).To(Succeed(), "failed to create ClusterRoleBinding")
80+
}
5881

59-
// 3. Create ClusterExtension
60-
ce := &ocv1.ClusterExtension{
61-
ObjectMeta: metav1.ObjectMeta{
62-
Name: ceName,
63-
},
64-
Spec: ocv1.ClusterExtensionSpec{
65-
Namespace: openshiftOperatorsNs,
66-
ServiceAccount: ocv1.ServiceAccountReference{
82+
// NewClusterExtensionObject creates a new ClusterExtension object with the specified package, version, name, and ServiceAccount.
83+
func NewClusterExtensionObject(pkg, version, ceName, saName, namespace string) *olmv1.ClusterExtension {
84+
return &olmv1.ClusterExtension{
85+
ObjectMeta: metav1.ObjectMeta{Name: ceName},
86+
Spec: olmv1.ClusterExtensionSpec{
87+
Namespace: namespace,
88+
ServiceAccount: olmv1.ServiceAccountReference{
6789
Name: saName,
6890
},
69-
Source: ocv1.SourceConfig{
70-
SourceType: ocv1.SourceTypeCatalog,
71-
Catalog: &ocv1.CatalogFilter{
72-
PackageName: packageName,
91+
Source: olmv1.SourceConfig{
92+
SourceType: olmv1.SourceTypeCatalog,
93+
Catalog: &olmv1.CatalogFilter{
94+
PackageName: pkg,
7395
Version: version,
7496
Selector: &metav1.LabelSelector{},
75-
UpgradeConstraintPolicy: ocv1.UpgradeConstraintPolicyCatalogProvided,
97+
UpgradeConstraintPolicy: olmv1.UpgradeConstraintPolicyCatalogProvided,
7698
},
7799
},
78100
},
79101
}
80-
Expect(k8sClient.Create(ctx, ce)).To(Succeed(), "failed to create ClusterExtension")
102+
}
81103

82-
// Cleanup closure
83-
return ceName, func() {
84-
_ = k8sClient.Delete(ctx, ce)
85-
_ = k8sClient.Delete(ctx, crb)
86-
_ = k8sClient.Delete(ctx, sa)
87-
}
104+
// ExpectClusterExtensionToBeInstalled checks that the ClusterExtension has both Progressing=True and Installed=True.
105+
func ExpectClusterExtensionToBeInstalled(ctx context.Context, name string) {
106+
k8sClient := env.Get().K8sClient
107+
Eventually(func(g Gomega) {
108+
var ext olmv1.ClusterExtension
109+
err := k8sClient.Get(ctx, client.ObjectKey{Name: name}, &ext)
110+
g.Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("failed to get ClusterExtension %q", name))
111+
112+
conditions := ext.Status.Conditions
113+
g.Expect(conditions).NotTo(BeEmpty(), fmt.Sprintf("ClusterExtension %q has empty status.conditions", name))
114+
115+
progressing := meta.FindStatusCondition(conditions, string(olmv1.TypeProgressing))
116+
g.Expect(progressing).ToNot(BeNil(), "Progressing condition not found")
117+
g.Expect(progressing.Status).To(Equal(metav1.ConditionTrue), "Progressing should be True")
118+
119+
installed := meta.FindStatusCondition(conditions, string(olmv1.TypeInstalled))
120+
g.Expect(installed).ToNot(BeNil(), "Installed condition not found")
121+
g.Expect(installed.Status).To(Equal(metav1.ConditionTrue), "Installed should be True")
122+
}).WithTimeout(5 * time.Minute).WithPolling(1 * time.Second).Should(Succeed())
88123
}

openshift/tests-extension/test/olmv1.go

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import (
1111
. "github.com/onsi/gomega"
1212

1313
configv1 "github.com/openshift/api/config/v1"
14+
corev1 "k8s.io/api/core/v1"
1415
apiextclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
1516
"k8s.io/apimachinery/pkg/api/meta"
1617
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18+
"k8s.io/apimachinery/pkg/util/rand"
1719
"sigs.k8s.io/controller-runtime/pkg/client"
1820

1921
olmv1 "github.com/operator-framework/operator-controller/api/v1"
@@ -71,37 +73,42 @@ var _ = Describe("[sig-olmv1][OCPFeatureGate:NewOLM] OLMv1 CRDs", func() {
7173
})
7274

7375
var _ = Describe("[sig-olmv1][OCPFeatureGate:NewOLM][Skipped:Disconnected] OLMv1 operator installation", func() {
76+
var (
77+
namespace string
78+
k8sClient client.Client
79+
)
7480
BeforeEach(func() {
7581
helpers.RequireOLMv1CapabilityOnOpenshift()
82+
k8sClient = env.Get().K8sClient
83+
namespace = "install-test-ns-" + rand.String(4)
84+
85+
By(fmt.Sprintf("creating namespace %s for single-namespace tests", namespace))
86+
ns := &corev1.Namespace{
87+
ObjectMeta: metav1.ObjectMeta{
88+
Name: namespace,
89+
},
90+
}
91+
Expect(k8sClient.Create(context.Background(), ns)).To(Succeed(), "failed to create test namespace")
92+
DeferCleanup(func() {
93+
_ = k8sClient.Delete(context.Background(), ns)
94+
})
7695
})
96+
7797
It("should install a cluster extension", func(ctx SpecContext) {
7898
if !env.Get().IsOpenShift {
7999
Skip("Requires OCP Catalogs: not OpenShift")
80100
}
81101
By("applying the ClusterExtension resource")
82-
name, cleanup := helpers.CreateClusterExtension("quay-operator", "3.13.0")
102+
name, cleanup := helpers.CreateClusterExtension("quay-operator", "3.13.0", namespace)
83103
DeferCleanup(cleanup)
84104

85105
By("waiting for the quay-operator ClusterExtension to be installed")
86-
Eventually(func(g Gomega) {
87-
k8sClient := env.Get().K8sClient
88-
ce := &olmv1.ClusterExtension{}
89-
err := k8sClient.Get(ctx, client.ObjectKey{Name: name}, ce)
90-
g.Expect(err).ToNot(HaveOccurred())
91-
92-
progressing := meta.FindStatusCondition(ce.Status.Conditions, olmv1.TypeProgressing)
93-
g.Expect(progressing).ToNot(BeNil())
94-
g.Expect(progressing.Status).To(Equal(metav1.ConditionTrue))
95-
96-
installed := meta.FindStatusCondition(ce.Status.Conditions, olmv1.TypeInstalled)
97-
g.Expect(installed).ToNot(BeNil())
98-
g.Expect(installed.Status).To(Equal(metav1.ConditionTrue))
99-
}).WithTimeout(5 * time.Minute).WithPolling(1 * time.Second).Should(Succeed())
106+
helpers.ExpectClusterExtensionToBeInstalled(ctx, name)
100107
})
101108

102109
It("should fail to install a non-existing cluster extension", func(ctx SpecContext) {
103110
By("applying the ClusterExtension resource")
104-
name, cleanup := helpers.CreateClusterExtension("does-not-exist", "99.99.99")
111+
name, cleanup := helpers.CreateClusterExtension("does-not-exist", "99.99.99", namespace)
105112
DeferCleanup(cleanup)
106113

107114
By("waiting for the ClusterExtension to exist")
@@ -136,7 +143,7 @@ var _ = Describe("[sig-olmv1][OCPFeatureGate:NewOLM][Skipped:Disconnected] OLMv1
136143
}
137144

138145
By("applying the ClusterExtension resource")
139-
name, cleanup := helpers.CreateClusterExtension("cluster-logging", "6.2.2")
146+
name, cleanup := helpers.CreateClusterExtension("cluster-logging", "6.2.2", namespace)
140147
DeferCleanup(cleanup)
141148

142149
By("waiting for the function-mesh ClusterExtension to be installed")

0 commit comments

Comments
 (0)