Skip to content

Commit a538831

Browse files
authored
e2e test utilities update (#2799)
* Update unpack job pod security (#2793) * Update unpack job security Signed-off-by: perdasilva <[email protected]> * Refactor catsrc pod creation to use security package Signed-off-by: perdasilva <[email protected]> * Refactor MagicCatalog removing superfluous interface and add factory method to create from file Signed-off-by: perdasilva <[email protected]> * Switch TestContext client to be the e2e client and add crd garbage collection Signed-off-by: perdasilva <[email protected]> * Add determined e2e client that retries on failure Signed-off-by: perdasilva <[email protected]> * Small fixes Signed-off-by: perdasilva <[email protected]> * Add olm gomega assertions and matchers Signed-off-by: perdasilva <[email protected]>
1 parent eedad28 commit a538831

12 files changed

+327
-71
lines changed

test/e2e/catalog_e2e_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() {
13491349

13501350
When("A CatalogSource is created with an operator that has a CSV with missing metadata.ApiVersion", func() {
13511351
var (
1352-
magicCatalog MagicCatalog
1352+
magicCatalog *MagicCatalog
13531353
catalogSourceName string
13541354
subscription *operatorsv1alpha1.Subscription
13551355
c client.Client

test/e2e/ctx/ctx.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@ import (
55
"os"
66
"os/exec"
77
"path/filepath"
8-
"strings"
98

109
"github.com/operator-framework/operator-lifecycle-manager/test/e2e/util"
1110
appsv1 "k8s.io/api/apps/v1"
1211
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
1312
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
1413

15-
g "github.com/onsi/ginkgo/v2"
1614
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1715
"k8s.io/apimachinery/pkg/runtime"
1816
"k8s.io/client-go/dynamic"
@@ -61,10 +59,7 @@ func Ctx() *TestContext {
6159
}
6260

6361
func (ctx TestContext) Logf(f string, v ...interface{}) {
64-
if !strings.HasSuffix(f, "\n") {
65-
f += "\n"
66-
}
67-
fmt.Fprintf(g.GinkgoWriter, f, v...)
62+
util.Logf(f, v...)
6863
}
6964

7065
func (ctx TestContext) Scheme() *runtime.Scheme {
@@ -210,8 +205,8 @@ func setDerivedFields(ctx *TestContext) error {
210205
if err != nil {
211206
return err
212207
}
213-
ctx.client = client
214208
ctx.e2eClient = util.NewK8sResourceManager(client)
209+
ctx.client = ctx.e2eClient
215210

216211
ctx.ssaClient, err = controllerclient.NewForConfig(ctx.restConfig, ctx.scheme, "test.olm.registry")
217212
if err != nil {

test/e2e/fail_forward_e2e_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ var _ = Describe("Fail Forward Upgrades", func() {
5555
When("an InstallPlan is reporting a failed state", func() {
5656

5757
var (
58-
magicCatalog MagicCatalog
58+
magicCatalog *MagicCatalog
5959
catalogSourceName string
6060
subscription *operatorsv1alpha1.Subscription
6161
)
@@ -194,7 +194,7 @@ var _ = Describe("Fail Forward Upgrades", func() {
194194
When("a CSV resource is in a failed state", func() {
195195

196196
var (
197-
magicCatalog MagicCatalog
197+
magicCatalog *MagicCatalog
198198
catalogSourceName string
199199
subscription *operatorsv1alpha1.Subscription
200200
)

test/e2e/magic_catalog.go

+67-54
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,20 @@ const (
2121
catalogReadyState string = "READY"
2222
)
2323

24-
type MagicCatalog interface {
25-
DeployCatalog(ctx context.Context) error
26-
UpdateCatalog(ctx context.Context, provider FileBasedCatalogProvider) error
27-
UndeployCatalog(ctx context.Context) []error
28-
}
29-
30-
type magicCatalog struct {
24+
type MagicCatalog struct {
3125
fileBasedCatalog FileBasedCatalogProvider
3226
kubeClient k8scontrollerclient.Client
33-
namespace string
3427
name string
28+
namespace string
3529
configMapName string
3630
serviceName string
3731
podName string
3832
}
3933

4034
// NewMagicCatalog creates an object that can deploy an arbitrary file-based catalog given by the FileBasedCatalogProvider
4135
// Keep in mind that there are limits to the configMaps. So, the catalogs need to be relatively simple
42-
func NewMagicCatalog(kubeClient k8scontrollerclient.Client, namespace string, catalogName string, provider FileBasedCatalogProvider) MagicCatalog {
43-
return &magicCatalog{
36+
func NewMagicCatalog(kubeClient k8scontrollerclient.Client, namespace string, catalogName string, provider FileBasedCatalogProvider) *MagicCatalog {
37+
return &MagicCatalog{
4438
fileBasedCatalog: provider,
4539
kubeClient: kubeClient,
4640
namespace: namespace,
@@ -51,53 +45,41 @@ func NewMagicCatalog(kubeClient k8scontrollerclient.Client, namespace string, ca
5145
}
5246
}
5347

54-
func (c *magicCatalog) DeployCatalog(ctx context.Context) error {
55-
catalogSource := c.makeCatalogSource()
48+
func NewMagicCatalogFromFile(kubeClient k8scontrollerclient.Client, namespace string, catalogName string, fbcFilePath string) (*MagicCatalog, error) {
49+
provider, err := NewFileBasedFiledBasedCatalogProvider(fbcFilePath)
50+
if err != nil {
51+
return nil, err
52+
}
53+
catalog := NewMagicCatalog(kubeClient, namespace, catalogName, provider)
54+
return catalog, nil
55+
}
56+
57+
func (c *MagicCatalog) GetName() string {
58+
return c.name
59+
}
60+
61+
func (c *MagicCatalog) GetNamespace() string {
62+
return c.namespace
63+
}
64+
65+
func (c *MagicCatalog) DeployCatalog(ctx context.Context) error {
5666
resourcesInOrderOfDeployment := []k8scontrollerclient.Object{
5767
c.makeConfigMap(),
5868
c.makeCatalogSourcePod(),
5969
c.makeCatalogService(),
60-
catalogSource,
70+
c.makeCatalogSource(),
6171
}
6272
if err := c.deployCatalog(ctx, resourcesInOrderOfDeployment); err != nil {
6373
return err
6474
}
65-
if err := catalogSourceIsReady(ctx, c.kubeClient, catalogSource); err != nil {
66-
return c.cleanUpAfter(ctx, err)
75+
if err := c.catalogSourceIsReady(ctx); err != nil {
76+
return c.cleanUpAfterError(ctx, err)
6777
}
6878

6979
return nil
7080
}
7181

72-
func catalogSourceIsReady(ctx context.Context, c k8scontrollerclient.Client, cs *operatorsv1alpha1.CatalogSource) error {
73-
// wait for catalog source to become ready
74-
return waitFor(func() (bool, error) {
75-
err := c.Get(ctx, k8scontrollerclient.ObjectKey{
76-
Name: cs.GetName(),
77-
Namespace: cs.GetNamespace(),
78-
}, cs)
79-
if err != nil || cs.Status.GRPCConnectionState == nil {
80-
return false, err
81-
}
82-
state := cs.Status.GRPCConnectionState.LastObservedState
83-
if state != catalogReadyState {
84-
return false, nil
85-
}
86-
return true, nil
87-
})
88-
}
89-
90-
func (c *magicCatalog) deployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) error {
91-
for _, res := range resources {
92-
err := c.kubeClient.Create(ctx, res)
93-
if err != nil {
94-
return c.cleanUpAfter(ctx, err)
95-
}
96-
}
97-
return nil
98-
}
99-
100-
func (c *magicCatalog) UpdateCatalog(ctx context.Context, provider FileBasedCatalogProvider) error {
82+
func (c *MagicCatalog) UpdateCatalog(ctx context.Context, provider FileBasedCatalogProvider) error {
10183
resourcesInOrderOfDeletion := []k8scontrollerclient.Object{
10284
c.makeCatalogSourcePod(),
10385
c.makeConfigMap(),
@@ -132,14 +114,14 @@ func (c *magicCatalog) UpdateCatalog(ctx context.Context, provider FileBasedCata
132114
if err := c.deployCatalog(ctx, resourcesInOrderOfCreation); err != nil {
133115
return err
134116
}
135-
if err := catalogSourceIsReady(ctx, c.kubeClient, c.makeCatalogSource()); err != nil {
136-
return c.cleanUpAfter(ctx, err)
117+
if err := c.catalogSourceIsReady(ctx); err != nil {
118+
return c.cleanUpAfterError(ctx, err)
137119
}
138120

139121
return nil
140122
}
141123

142-
func (c *magicCatalog) UndeployCatalog(ctx context.Context) []error {
124+
func (c *MagicCatalog) UndeployCatalog(ctx context.Context) []error {
143125
resourcesInOrderOfDeletion := []k8scontrollerclient.Object{
144126
c.makeCatalogSource(),
145127
c.makeCatalogService(),
@@ -149,7 +131,38 @@ func (c *magicCatalog) UndeployCatalog(ctx context.Context) []error {
149131
return c.undeployCatalog(ctx, resourcesInOrderOfDeletion)
150132
}
151133

152-
func (c *magicCatalog) undeployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) []error {
134+
func (c *MagicCatalog) catalogSourceIsReady(ctx context.Context) error {
135+
// wait for catalog source to become ready
136+
key := k8scontrollerclient.ObjectKey{
137+
Name: c.name,
138+
Namespace: c.namespace,
139+
}
140+
141+
return waitFor(func() (bool, error) {
142+
catalogSource := &operatorsv1alpha1.CatalogSource{}
143+
err := c.kubeClient.Get(ctx, key, catalogSource)
144+
if err != nil || catalogSource.Status.GRPCConnectionState == nil {
145+
return false, err
146+
}
147+
state := catalogSource.Status.GRPCConnectionState.LastObservedState
148+
if state != catalogReadyState {
149+
return false, nil
150+
}
151+
return true, nil
152+
})
153+
}
154+
155+
func (c *MagicCatalog) deployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) error {
156+
for _, res := range resources {
157+
err := c.kubeClient.Create(ctx, res)
158+
if err != nil {
159+
return c.cleanUpAfterError(ctx, err)
160+
}
161+
}
162+
return nil
163+
}
164+
165+
func (c *MagicCatalog) undeployCatalog(ctx context.Context, resources []k8scontrollerclient.Object) []error {
153166
var errors []error
154167
// try to delete all resourcesInOrderOfDeletion even if errors are
155168
// encountered through deletion.
@@ -167,15 +180,15 @@ func (c *magicCatalog) undeployCatalog(ctx context.Context, resources []k8scontr
167180
return errors
168181
}
169182

170-
func (c *magicCatalog) cleanUpAfter(ctx context.Context, err error) error {
183+
func (c *MagicCatalog) cleanUpAfterError(ctx context.Context, err error) error {
171184
cleanupErr := c.UndeployCatalog(ctx)
172185
if cleanupErr != nil {
173186
return fmt.Errorf("the following cleanup errors occurred: '%s' after an error deploying the configmap: '%s' ", cleanupErr, err)
174187
}
175188
return err
176189
}
177190

178-
func (c *magicCatalog) makeCatalogService() *corev1.Service {
191+
func (c *MagicCatalog) makeCatalogService() *corev1.Service {
179192
return &corev1.Service{
180193
ObjectMeta: metav1.ObjectMeta{
181194
Name: c.serviceName,
@@ -195,7 +208,7 @@ func (c *magicCatalog) makeCatalogService() *corev1.Service {
195208
}
196209
}
197210

198-
func (c *magicCatalog) makeConfigMap() *corev1.ConfigMap {
211+
func (c *MagicCatalog) makeConfigMap() *corev1.ConfigMap {
199212
isImmutable := true
200213
return &corev1.ConfigMap{
201214
ObjectMeta: metav1.ObjectMeta{
@@ -224,7 +237,7 @@ func (c *magicCatalog) makeConfigMap() *corev1.ConfigMap {
224237
}
225238
}
226239

227-
func (c *magicCatalog) makeCatalogSource() *operatorsv1alpha1.CatalogSource {
240+
func (c *MagicCatalog) makeCatalogSource() *operatorsv1alpha1.CatalogSource {
228241
return &operatorsv1alpha1.CatalogSource{
229242
ObjectMeta: metav1.ObjectMeta{
230243
Name: c.name,
@@ -237,7 +250,7 @@ func (c *magicCatalog) makeCatalogSource() *operatorsv1alpha1.CatalogSource {
237250
}
238251
}
239252

240-
func (c *magicCatalog) makeCatalogSourcePod() *corev1.Pod {
253+
func (c *MagicCatalog) makeCatalogSourcePod() *corev1.Pod {
241254

242255
const (
243256
image = "quay.io/operator-framework/upstream-opm-builder"
@@ -320,7 +333,7 @@ func (c *magicCatalog) makeCatalogSourcePod() *corev1.Pod {
320333
}
321334
}
322335

323-
func (c *magicCatalog) makeCatalogSourcePodLabels() map[string]string {
336+
func (c *MagicCatalog) makeCatalogSourcePodLabels() map[string]string {
324337
return map[string]string{
325338
olmCatalogLabel: c.name,
326339
}

test/e2e/magic_catalog_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var _ = Describe("MagicCatalog", func() {
4545

4646
When("an existing magic catalog exists", func() {
4747
var (
48-
mc MagicCatalog
48+
mc *MagicCatalog
4949
catalogName string
5050
)
5151

test/e2e/util.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -1010,11 +1010,11 @@ func SetupGeneratedTestNamespaceWithOperatorGroup(name string, og operatorsv1.Op
10101010
},
10111011
}
10121012
Eventually(func() error {
1013-
return ctx.Ctx().Client().Create(context.Background(), &ns)
1013+
return ctx.Ctx().E2EClient().Create(context.Background(), &ns)
10141014
}).Should(Succeed())
10151015

10161016
Eventually(func() error {
1017-
return ctx.Ctx().Client().Create(context.Background(), &og)
1017+
return ctx.Ctx().E2EClient().Create(context.Background(), &og)
10181018
}).Should(Succeed())
10191019

10201020
ctx.Ctx().Logf("created the %s testing namespace", ns.GetName())
@@ -1049,7 +1049,7 @@ func TeardownNamespace(ns string) {
10491049

10501050
log("tearing down the %s namespace", ns)
10511051
Eventually(func() error {
1052-
return ctx.Ctx().KubeClient().KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns, metav1.DeleteOptions{})
1052+
return ctx.Ctx().E2EClient().Reset()
10531053
}).Should(Succeed())
10541054
}
10551055

test/e2e/util/e2e_client.go

+37-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package util
22

33
import (
44
"context"
5+
"strings"
56

67
"github.com/onsi/ginkgo/v2"
7-
k8serror "k8s.io/apimachinery/pkg/api/errors"
8+
extensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
89
k8scontrollerclient "sigs.k8s.io/controller-runtime/pkg/client"
910
)
1011

@@ -38,7 +39,6 @@ func (m *E2EKubeClient) Update(context context.Context, obj k8scontrollerclient.
3839
if err := m.Client.Update(context, obj, options...); err != nil {
3940
return err
4041
}
41-
m.createdResources.EnqueueIgnoreExisting(obj)
4242
return nil
4343
}
4444

@@ -51,17 +51,51 @@ func (m *E2EKubeClient) Delete(context context.Context, obj k8scontrollerclient.
5151
}
5252

5353
func (m *E2EKubeClient) Reset() error {
54+
Logf("resetting e2e kube client")
5455
for {
5556
obj, ok := m.createdResources.DequeueTail()
5657

5758
if !ok {
5859
break
5960
}
6061

61-
if err := m.Delete(context.TODO(), obj); err != nil && !k8serror.IsNotFound(err) {
62+
namespace := obj.GetNamespace()
63+
if namespace == "" {
64+
namespace = "<global>"
65+
}
66+
67+
Logf("deleting %s/%s", namespace, obj.GetName())
68+
if err := k8scontrollerclient.IgnoreNotFound(m.Delete(context.Background(), obj)); err != nil {
69+
Logf("error deleting object %s/%s: %s", namespace, obj.GetName(), obj)
6270
return err
6371
}
6472
}
73+
return m.GarbageCollectCRDs()
74+
}
75+
76+
// GarbageCollectCRDs deletes any CRD with a label like operatorframework.io/installed-alongside-*
77+
// these are the result of operator installations by olm and tent to be left behind after an e2e test
78+
func (m *E2EKubeClient) GarbageCollectCRDs() error {
79+
Logf("garbage collecting CRDs")
80+
const operatorFrameworkAnnotation = "operatorframework.io/installed-alongside-"
81+
82+
crds := &extensionsv1.CustomResourceDefinitionList{}
83+
err := m.Client.List(context.Background(), crds)
84+
if err != nil {
85+
return err
86+
}
87+
88+
for _, crd := range crds.Items {
89+
for key, _ := range crd.Annotations {
90+
if strings.HasPrefix(key, operatorFrameworkAnnotation) {
91+
Logf("deleting crd %s", crd.GetName())
92+
if err := m.Client.Delete(context.Background(), &crd); err != nil {
93+
return err
94+
}
95+
break
96+
}
97+
}
98+
}
6599
return nil
66100
}
67101

0 commit comments

Comments
 (0)