Skip to content

Commit 9beaf49

Browse files
kaovilaiclaude
andauthored
Fix HCP test suite BeforeAll failures and nil pointer panics (#1908)
This commit addresses the HCP backup and restore test suite failing with: 1. "multicluster-engine PackageManifest not found" errors 2. Nil pointer dereference panics in cleanup functions Changes made: - Add WaitForCatalogSourceReady() function to wait for CatalogSource to be READY - Add WaitForPackageManifest() function to wait for PackageManifest availability - Update BeforeAll to wait for prerequisites before operator installation - Use libhcp constants (RHOperatorsNamespace, OCPMarketplaceNamespace) instead of hardcoded strings - Use ginkgo.Fail() instead of ginkgo.Skip() for prerequisite failures - Add nil checks in AfterAll and AfterEach to prevent cleanup panics - Remove unused error variable to fix linting issues The test suite now properly handles timing issues with operator catalog synchronization and reports prerequisite failures as test failures rather than skipped tests. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <[email protected]>
1 parent 6aaf567 commit 9beaf49

File tree

2 files changed

+135
-4
lines changed

2 files changed

+135
-4
lines changed

tests/e2e/hcp_backup_restore_suite_test.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ var _ = ginkgo.Describe("HCP Backup and Restore tests", ginkgo.Ordered, func() {
7070
lastInstallTime time.Time
7171
lastBRCase HCPBackupRestoreCase
7272
h *libhcp.HCHandler
73-
err error
7473
ctx = context.Background()
7574
)
7675

@@ -80,6 +79,32 @@ var _ = ginkgo.Describe("HCP Backup and Restore tests", ginkgo.Ordered, func() {
8079

8180
// Before All
8281
var _ = ginkgo.BeforeAll(func() {
82+
// Wait for CatalogSource to be ready
83+
err := libhcp.WaitForCatalogSourceReady(
84+
ctx,
85+
runTimeClientForSuiteRun,
86+
libhcp.RHOperatorsNamespace,
87+
libhcp.OCPMarketplaceNamespace,
88+
time.Minute*5,
89+
)
90+
if err != nil {
91+
ginkgo.Fail(fmt.Sprintf("HCP tests failed: CatalogSource not ready timeout: %v", err))
92+
return
93+
}
94+
95+
// Wait for multicluster-engine PackageManifest to be available
96+
err = libhcp.WaitForPackageManifest(
97+
ctx,
98+
runTimeClientForSuiteRun,
99+
libhcp.MCEName,
100+
libhcp.OCPMarketplaceNamespace,
101+
time.Minute*5,
102+
)
103+
if err != nil {
104+
ginkgo.Fail(fmt.Sprintf("HCP tests failed: multicluster-engine PackageManifest not available timeout: %v", err))
105+
return
106+
}
107+
83108
reqOperators := []libhcp.RequiredOperator{
84109
{
85110
Name: libhcp.MCEName,
@@ -109,13 +134,17 @@ var _ = ginkgo.Describe("HCP Backup and Restore tests", ginkgo.Ordered, func() {
109134

110135
// After All
111136
var _ = ginkgo.AfterAll(func() {
112-
err := h.RemoveHCP(libhcp.Wait10Min)
113-
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "failed to remove HCP: %v", err)
137+
if h != nil {
138+
err := h.RemoveHCP(libhcp.Wait10Min)
139+
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "failed to remove HCP: %v", err)
140+
}
114141
})
115142

116143
// After Each
117144
var _ = ginkgo.AfterEach(func(ctx ginkgo.SpecContext) {
118-
h.RemoveHCP(libhcp.Wait10Min)
145+
if h != nil {
146+
h.RemoveHCP(libhcp.Wait10Min)
147+
}
119148
tearDownBackupAndRestore(lastBRCase.BackupRestoreCase, lastInstallTime, ctx.SpecReport())
120149
})
121150

tests/e2e/lib/hcp/mce.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import (
44
"context"
55
"fmt"
66
"log"
7+
"time"
78

89
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
910
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
1011
corev1 "k8s.io/api/core/v1"
1112
apierrors "k8s.io/apimachinery/pkg/api/errors"
1213
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
15+
"k8s.io/apimachinery/pkg/runtime/schema"
1416
"k8s.io/apimachinery/pkg/types"
1517
"k8s.io/apimachinery/pkg/util/wait"
1618
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -150,3 +152,103 @@ func (h *HCHandler) IsMCEDeployed() bool {
150152

151153
return true
152154
}
155+
156+
// WaitForCatalogSourceReady waits for a CatalogSource to be ready
157+
func WaitForCatalogSourceReady(ctx context.Context, c client.Client, catalogSourceName, namespace string, timeout time.Duration) error {
158+
log.Printf("Waiting for CatalogSource %s/%s to be ready...", namespace, catalogSourceName)
159+
160+
catalogSource := &unstructured.Unstructured{}
161+
catalogSource.SetGroupVersionKind(schema.GroupVersionResource{
162+
Group: "operators.coreos.com",
163+
Version: "v1alpha1",
164+
Resource: "catalogsources",
165+
}.GroupVersion().WithKind("CatalogSource"))
166+
167+
err := wait.PollUntilContextTimeout(ctx, time.Second*10, timeout, true, func(ctx context.Context) (bool, error) {
168+
err := c.Get(ctx, types.NamespacedName{
169+
Name: catalogSourceName,
170+
Namespace: namespace,
171+
}, catalogSource)
172+
173+
if err != nil {
174+
if apierrors.IsNotFound(err) {
175+
log.Printf("CatalogSource %s/%s not found, waiting...", namespace, catalogSourceName)
176+
return false, nil
177+
}
178+
log.Printf("Error getting CatalogSource: %v", err)
179+
return false, nil
180+
}
181+
182+
// Check connection state
183+
state, found, err := unstructured.NestedString(catalogSource.Object, "status", "connectionState", "lastObservedState")
184+
if err != nil {
185+
log.Printf("Error getting connection state: %v", err)
186+
return false, nil
187+
}
188+
189+
if !found {
190+
log.Printf("Connection state not found yet, waiting...")
191+
return false, nil
192+
}
193+
194+
log.Printf("CatalogSource %s/%s state: %s", namespace, catalogSourceName, state)
195+
return state == "READY", nil
196+
})
197+
198+
if err != nil {
199+
return fmt.Errorf("timeout waiting for CatalogSource %s/%s to be ready: %v", namespace, catalogSourceName, err)
200+
}
201+
202+
log.Printf("CatalogSource %s/%s is ready", namespace, catalogSourceName)
203+
return nil
204+
}
205+
206+
// WaitForPackageManifest waits for a PackageManifest to be available
207+
func WaitForPackageManifest(ctx context.Context, c client.Client, packageName, namespace string, timeout time.Duration) error {
208+
log.Printf("Waiting for PackageManifest %s/%s to be available...", namespace, packageName)
209+
210+
pkg := &unstructured.Unstructured{}
211+
pkg.SetGroupVersionKind(schema.GroupVersionResource{
212+
Group: "packages.operators.coreos.com",
213+
Version: "v1",
214+
Resource: "packagemanifests",
215+
}.GroupVersion().WithKind("PackageManifest"))
216+
217+
err := wait.PollUntilContextTimeout(ctx, time.Second*10, timeout, true, func(ctx context.Context) (bool, error) {
218+
err := c.Get(ctx, types.NamespacedName{
219+
Name: packageName,
220+
Namespace: namespace,
221+
}, pkg)
222+
223+
if err != nil {
224+
if apierrors.IsNotFound(err) {
225+
log.Printf("PackageManifest %s/%s not found, waiting...", namespace, packageName)
226+
return false, nil
227+
}
228+
log.Printf("Error getting PackageManifest: %v", err)
229+
return false, nil
230+
}
231+
232+
// Check if it has channels
233+
channels, found, err := unstructured.NestedSlice(pkg.Object, "status", "channels")
234+
if err != nil {
235+
log.Printf("Error getting channels: %v", err)
236+
return false, nil
237+
}
238+
239+
if !found || len(channels) == 0 {
240+
log.Printf("PackageManifest %s/%s found but no channels available yet", namespace, packageName)
241+
return false, nil
242+
}
243+
244+
log.Printf("PackageManifest %s/%s is available with %d channels", namespace, packageName, len(channels))
245+
return true, nil
246+
})
247+
248+
if err != nil {
249+
return fmt.Errorf("timeout waiting for PackageManifest %s/%s: %v", namespace, packageName, err)
250+
}
251+
252+
log.Printf("PackageManifest %s/%s is ready", namespace, packageName)
253+
return nil
254+
}

0 commit comments

Comments
 (0)