Skip to content

Commit e1389ac

Browse files
author
Per Goncalves da Silva
committed
Add revision e2e
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 0cd545f commit e1389ac

File tree

2 files changed

+246
-0
lines changed

2 files changed

+246
-0
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"slices"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
corev1 "k8s.io/api/core/v1"
13+
apimeta "k8s.io/apimachinery/pkg/api/meta"
14+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/types"
16+
"k8s.io/client-go/kubernetes/scheme"
17+
"k8s.io/client-go/tools/remotecommand"
18+
ctrl "sigs.k8s.io/controller-runtime"
19+
"sigs.k8s.io/controller-runtime/pkg/client"
20+
21+
ocv1 "github.com/operator-framework/operator-controller/api/v1"
22+
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
23+
. "github.com/operator-framework/operator-controller/internal/shared/util/testutils"
24+
. "github.com/operator-framework/operator-controller/test/helpers"
25+
)
26+
27+
func TestClusterExtensionRevision(t *testing.T) {
28+
SkipIfFeatureGateDisabled(t, string(features.BoxcutterRuntime))
29+
t.Log("When a cluster extension is installed from a catalog")
30+
t.Log("When the extension bundle format is registry+v1")
31+
32+
clusterExtension, extensionCatalog, sa, ns := TestInit(t)
33+
defer TestCleanup(t, extensionCatalog, clusterExtension, sa, ns)
34+
defer CollectTestArtifacts(t, artifactName, c, cfg)
35+
36+
clusterExtension.Spec = ocv1.ClusterExtensionSpec{
37+
Source: ocv1.SourceConfig{
38+
SourceType: "Catalog",
39+
Catalog: &ocv1.CatalogFilter{
40+
PackageName: "test",
41+
Version: "1.0.1",
42+
Selector: &metav1.LabelSelector{
43+
MatchLabels: map[string]string{"olm.operatorframework.io/metadata.name": extensionCatalog.Name},
44+
},
45+
},
46+
},
47+
Namespace: ns.Name,
48+
ServiceAccount: ocv1.ServiceAccountReference{
49+
Name: sa.Name,
50+
},
51+
}
52+
t.Log("It resolves the specified package with correct bundle path")
53+
t.Log("By creating the ClusterExtension resource")
54+
require.NoError(t, c.Create(context.Background(), clusterExtension))
55+
56+
t.Log("By eventually reporting a successful resolution and bundle path")
57+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
58+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
59+
}, pollDuration, pollInterval)
60+
61+
t.Log("By revision-1 eventually reporting Progressing:False:RolledOut and Available:True:ProbesSucceeded conditions")
62+
var clusterExtensionRevision ocv1.ClusterExtensionRevision
63+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
64+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("%s-1", clusterExtension.Name)}, &clusterExtensionRevision))
65+
cond := apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeProgressing)
66+
require.NotNil(ct, cond)
67+
require.Equal(ct, metav1.ConditionFalse, cond.Status)
68+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonRolledOut, cond.Reason)
69+
70+
cond = apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
71+
require.NotNil(ct, cond)
72+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
73+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbesSucceeded, cond.Reason)
74+
}, pollDuration, pollInterval)
75+
76+
t.Log("By eventually reporting progressing as True")
77+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
78+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
79+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeProgressing)
80+
require.NotNil(ct, cond)
81+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
82+
require.Equal(ct, ocv1.ReasonSucceeded, cond.Reason)
83+
}, pollDuration, pollInterval)
84+
85+
t.Log("By eventually reporting available as True")
86+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
87+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
88+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
89+
require.NotNil(ct, cond)
90+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
91+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbesSucceeded, cond.Reason)
92+
}, pollDuration, pollInterval)
93+
94+
t.Log("By eventually installing the package successfully")
95+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
96+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
97+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeInstalled)
98+
require.NotNil(ct, cond)
99+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
100+
require.Equal(ct, ocv1.ReasonSucceeded, cond.Reason)
101+
require.Contains(ct, cond.Message, "Installed bundle")
102+
require.NotEmpty(ct, clusterExtension.Status.Install.Bundle)
103+
}, pollDuration, pollInterval)
104+
105+
t.Log("Check Deployment Availability Probe")
106+
t.Log("By making the operator pod not ready")
107+
podName := getPodName(t, clusterExtension.Spec.Namespace, client.MatchingLabels{"app": "olme2etest"})
108+
podExec(t, clusterExtension.Spec.Namespace, podName, []string{"rm", "/var/www/ready"})
109+
110+
t.Log("By revision-1 eventually reporting Progressing:False:RolledOut and Available:False:ProbeFailure conditions")
111+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
112+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("%s-1", clusterExtension.Name)}, &clusterExtensionRevision))
113+
cond := apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeProgressing)
114+
require.NotNil(ct, cond)
115+
require.Equal(ct, metav1.ConditionFalse, cond.Status)
116+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonRolledOut, cond.Reason)
117+
118+
cond = apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
119+
require.NotNil(ct, cond)
120+
require.Equal(ct, metav1.ConditionFalse, cond.Status)
121+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbeFailure, cond.Reason)
122+
}, pollDuration, pollInterval)
123+
124+
t.Log("By extension eventually reporting available as False")
125+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
126+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
127+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
128+
require.NotNil(ct, cond)
129+
require.Equal(ct, metav1.ConditionFalse, cond.Status)
130+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbeFailure, cond.Reason)
131+
}, pollDuration, pollInterval)
132+
133+
t.Log("By making the operator pod ready")
134+
podName = getPodName(t, clusterExtension.Spec.Namespace, client.MatchingLabels{"app": "olme2etest"})
135+
podExec(t, clusterExtension.Spec.Namespace, podName, []string{"touch", "/var/www/ready"})
136+
137+
t.Log("By revision-1 eventually reporting Progressing:False:RolledOut and Available:True:ProbesSucceeded conditions")
138+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
139+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("%s-1", clusterExtension.Name)}, &clusterExtensionRevision))
140+
cond := apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeProgressing)
141+
require.NotNil(ct, cond)
142+
require.Equal(ct, metav1.ConditionFalse, cond.Status)
143+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonRolledOut, cond.Reason)
144+
145+
cond = apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
146+
require.NotNil(ct, cond)
147+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
148+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbesSucceeded, cond.Reason)
149+
}, pollDuration, pollInterval)
150+
151+
t.Log("By extension eventually reporting available as True")
152+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
153+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
154+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
155+
require.NotNil(ct, cond)
156+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
157+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbesSucceeded, cond.Reason)
158+
}, pollDuration, pollInterval)
159+
160+
t.Log("Check archiving")
161+
t.Log("By upgrading the cluster extension to v1.2.0")
162+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
163+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
164+
clusterExtension.Spec.Source.Catalog.Version = "1.2.0"
165+
require.NoError(t, c.Update(context.Background(), clusterExtension))
166+
}, pollDuration, pollInterval)
167+
168+
t.Log("By revision-2 eventually reporting Progressing:False:RolledOut and Available:True:ProbesSucceeded conditions")
169+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
170+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("%s-2", clusterExtension.Name)}, &clusterExtensionRevision))
171+
cond := apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeProgressing)
172+
require.NotNil(ct, cond)
173+
require.Equal(ct, metav1.ConditionFalse, cond.Status)
174+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonRolledOut, cond.Reason)
175+
176+
cond = apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
177+
require.NotNil(ct, cond)
178+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
179+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbesSucceeded, cond.Reason)
180+
}, pollDuration, pollInterval)
181+
182+
t.Log("By eventually reporting progressing, available, and installed as True")
183+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
184+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
185+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeProgressing)
186+
require.NotNil(ct, cond)
187+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
188+
require.Equal(ct, ocv1.ReasonSucceeded, cond.Reason)
189+
190+
cond = apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
191+
require.NotNil(ct, cond)
192+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
193+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonProbesSucceeded, cond.Reason)
194+
195+
cond = apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeInstalled)
196+
require.NotNil(ct, cond)
197+
require.Equal(ct, metav1.ConditionTrue, cond.Status)
198+
require.Equal(ct, ocv1.ReasonSucceeded, cond.Reason)
199+
require.Contains(ct, cond.Message, "Installed bundle")
200+
require.NotEmpty(ct, clusterExtension.Status.Install.Bundle)
201+
}, pollDuration, pollInterval)
202+
203+
t.Log("By revision-1 eventually reporting Progressing:False:Archived and Available:Unknown:Archived conditions")
204+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
205+
require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: fmt.Sprintf("%s-1", clusterExtension.Name)}, &clusterExtensionRevision))
206+
cond := apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeProgressing)
207+
require.NotNil(ct, cond)
208+
require.Equal(ct, metav1.ConditionFalse, cond.Status)
209+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonArchived, cond.Reason)
210+
211+
cond = apimeta.FindStatusCondition(clusterExtensionRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
212+
require.NotNil(ct, cond)
213+
require.Equal(ct, metav1.ConditionUnknown, cond.Status)
214+
require.Equal(ct, ocv1.ClusterExtensionRevisionReasonArchived, cond.Reason)
215+
}, pollDuration, pollInterval)
216+
}
217+
218+
func getPodName(t *testing.T, podNamespace string, matchingLabels client.MatchingLabels) string {
219+
var podList corev1.PodList
220+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
221+
require.NoError(ct, c.List(context.Background(), &podList, client.InNamespace(podNamespace), matchingLabels))
222+
podList.Items = slices.DeleteFunc(podList.Items, func(pod corev1.Pod) bool {
223+
// Ignore terminating pods
224+
return pod.DeletionTimestamp != nil
225+
})
226+
require.Len(ct, podList.Items, 1)
227+
}, pollDuration, pollInterval)
228+
return podList.Items[0].Name
229+
}
230+
231+
func podExec(t *testing.T, podNamespace string, podName string, cmd []string) {
232+
req := cs.CoreV1().RESTClient().Post().Resource("pods").Name(podName).Namespace(podNamespace).SubResource("exec")
233+
req.VersionedParams(&corev1.PodExecOptions{
234+
Command: cmd,
235+
Stdout: true,
236+
}, scheme.ParameterCodec)
237+
exec, err := remotecommand.NewSPDYExecutor(ctrl.GetConfigOrDie(), "POST", req.URL())
238+
require.NoError(t, err)
239+
err = exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{Stdout: os.Stdout})
240+
require.NoError(t, err)
241+
}

test/e2e/e2e_suite_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1010
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
11+
"k8s.io/client-go/kubernetes"
1112
"k8s.io/client-go/rest"
1213
ctrl "sigs.k8s.io/controller-runtime"
1314
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -20,6 +21,7 @@ import (
2021
var (
2122
cfg *rest.Config
2223
c client.Client
24+
cs *kubernetes.Clientset
2325
)
2426

2527
const (
@@ -35,6 +37,9 @@ func TestMain(m *testing.M) {
3537
c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
3638
utilruntime.Must(err)
3739

40+
cs, err = kubernetes.NewForConfig(cfg)
41+
utilruntime.Must(err)
42+
3843
res := m.Run()
3944
path := os.Getenv(testSummaryOutputEnvVar)
4045
if path == "" {

0 commit comments

Comments
 (0)