Skip to content

Commit d59aa35

Browse files
bandradeci-robot
authored andcommitted
UPSTREAM: <carry>: add 85889 automation
1 parent 805372d commit d59aa35

File tree

4 files changed

+339
-10
lines changed

4 files changed

+339
-10
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@
177177
"exclude": "topology==\"External\""
178178
}
179179
},
180+
{
181+
"name": "[sig-olmv1][Jira:OLM] clustercatalog PolarionID:85889-[OTP][Skipped:Disconnected]Validate catalogd content via port-forward [Serial]",
182+
"labels": {
183+
"ClusterCatalog": {},
184+
"Extended": {},
185+
"NonHyperShiftHOST": {}
186+
},
187+
"resources": {
188+
"isolation": {}
189+
},
190+
"source": "openshift:payload:olmv1",
191+
"lifecycle": "blocking",
192+
"environmentSelector": {
193+
"exclude": "topology==\"External\""
194+
}
195+
},
180196
{
181197
"name": "[sig-olmv1][Jira:OLM] clustercatalog PolarionID:73219-[OTP][Skipped:Disconnected]Fetch deprecation data from the catalogd http server",
182198
"labels": {

openshift/tests-extension/pkg/bindata/qe/bindata.go

Lines changed: 52 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

openshift/tests-extension/test/qe/specs/olmv1_cc.go

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@ package specs
22

33
import (
44
"context"
5+
"crypto/tls"
6+
"encoding/json"
57
"fmt"
8+
"io"
9+
"net/http"
10+
"os"
611
"os/exec"
712
"path/filepath"
813
"regexp"
14+
"strconv"
915
"strings"
1016
"time"
1117

@@ -322,6 +328,249 @@ var _ = g.Describe("[sig-olmv1][Jira:OLM] clustercatalog", g.Label("NonHyperShif
322328
exutil.AssertWaitPollNoErr(errWait, "Cannot get the result")
323329
})
324330

331+
g.It("PolarionID:85889-[OTP][Skipped:Disconnected]Validate catalogd content via port-forward [Serial]", func() {
332+
caseID := "85889"
333+
catalogName := "catalog-" + caseID
334+
catalogImage := "quay.io/openshifttest/nginxolm-operator-index:nginxolm74924"
335+
baseDir := exutil.FixturePath("testdata", "olm")
336+
catalogTemplate := filepath.Join(baseDir, "clustercatalog-with-pollinterval.yaml")
337+
outputDir := "/tmp/" + caseID + "-" + exutil.GetRandomString()
338+
err := os.MkdirAll(outputDir, 0755)
339+
o.Expect(err).NotTo(o.HaveOccurred())
340+
defer os.RemoveAll(outputDir)
341+
342+
redhatOperatorsFile := filepath.Join(outputDir, "redhat-operators-all.json")
343+
customCatalogFile := filepath.Join(outputDir, "all.json")
344+
345+
type catalogEntry struct {
346+
Schema string `json:"schema"`
347+
Name string `json:"name,omitempty"`
348+
Package string `json:"package,omitempty"`
349+
}
350+
351+
parseCatalogEntries := func(data []byte) ([]catalogEntry, error) {
352+
var entries []catalogEntry
353+
for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
354+
line = strings.TrimSpace(line)
355+
if line == "" || !strings.HasPrefix(line, "{") {
356+
continue
357+
}
358+
var entry catalogEntry
359+
if err := json.Unmarshal([]byte(line), &entry); err != nil {
360+
return nil, err
361+
}
362+
if entry.Schema != "" {
363+
entries = append(entries, entry)
364+
}
365+
}
366+
if len(entries) == 0 {
367+
return nil, fmt.Errorf("no catalog entries parsed")
368+
}
369+
return entries, nil
370+
}
371+
372+
fetchToFile := func(url, path string) ([]byte, error) {
373+
client := &http.Client{
374+
Transport: &http.Transport{
375+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec // uses catalogd route with test TLS
376+
},
377+
Timeout: 2 * time.Minute,
378+
}
379+
req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, url, nil)
380+
if err != nil {
381+
return nil, err
382+
}
383+
resp, err := client.Do(req)
384+
if err != nil {
385+
return nil, err
386+
}
387+
defer resp.Body.Close()
388+
if resp.StatusCode != http.StatusOK {
389+
return nil, fmt.Errorf("unexpected status %s for %s", resp.Status, url)
390+
}
391+
body, err := io.ReadAll(resp.Body)
392+
if err != nil {
393+
return nil, err
394+
}
395+
if err = os.WriteFile(path, body, 0600); err != nil {
396+
return nil, err
397+
}
398+
return body, nil
399+
}
400+
401+
getCatalogdLogs := func() (string, error) {
402+
return oc.AsAdmin().WithoutNamespace().Run("logs").Args("-n", "openshift-catalogd", "deploy/catalogd-controller-manager", "--since=10m").Output()
403+
}
404+
405+
getReconcileTotal := func() (float64, error) {
406+
metrics, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("--raw", "/api/v1/namespaces/openshift-catalogd/services/catalogd-service:metrics/proxy/metrics").Output()
407+
if err != nil {
408+
return 0, err
409+
}
410+
re := regexp.MustCompile(`(?im)^.*reconcile_total.*clustercatalog.*\\s+([0-9]+(?:\\.[0-9]+)?)$`)
411+
matches := re.FindAllStringSubmatch(metrics, -1)
412+
if len(matches) == 0 {
413+
return 0, fmt.Errorf("clustercatalog reconcile_total not found in metrics output")
414+
}
415+
var max float64
416+
for _, match := range matches {
417+
value, err := strconv.ParseFloat(match[1], 64)
418+
if err != nil {
419+
continue
420+
}
421+
if value > max {
422+
max = value
423+
}
424+
}
425+
return max, nil
426+
}
427+
428+
clustercatalog := olmv1util.ClusterCatalogDescription{Name: catalogName}
429+
deleted := false
430+
defer func() {
431+
if !deleted {
432+
clustercatalog.Delete(oc)
433+
}
434+
}()
435+
436+
g.By("Check OLM namespaces in ClusterOperator")
437+
nsOutput, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("co", "olm", `-o=jsonpath={.status.relatedObjects[?(@.resource=="namespaces")].name}`).Output()
438+
o.Expect(err).NotTo(o.HaveOccurred())
439+
o.Expect(nsOutput).To(o.ContainSubstring("openshift-catalogd"))
440+
o.Expect(nsOutput).To(o.ContainSubstring("openshift-operator-controller"))
441+
442+
g.By("Verify OLM CRDs referenced")
443+
crdOutput, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("co", "olm", `-o=jsonpath={.status.relatedObjects[?(@.resource=="customresourcedefinitions")].name}`).Output()
444+
o.Expect(err).NotTo(o.HaveOccurred())
445+
catalogCRDOK := strings.Contains(crdOutput, "clustercatalogs.catalogd.operatorframework.io") ||
446+
strings.Contains(crdOutput, "clustercatalogs.olm.operatorframework.io")
447+
o.Expect(catalogCRDOK).To(o.BeTrue())
448+
o.Expect(crdOutput).To(o.ContainSubstring("clusterextensions.olm.operatorframework.io"))
449+
450+
g.By("Create test ClusterCatalog")
451+
clustercatalog.Template = catalogTemplate
452+
clustercatalog.Imageref = catalogImage
453+
clustercatalog.PollIntervalMinutes = "300s"
454+
clustercatalog.Create(oc)
455+
456+
g.By("Verify ClusterCatalog list and phases")
457+
listOutput, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("clustercatalog", `-o=jsonpath={range .items[*]}{.metadata.name}{"="}{.status.phase}{"\n"}{end}`).Output()
458+
o.Expect(err).NotTo(o.HaveOccurred())
459+
o.Expect(listOutput).To(o.ContainSubstring("openshift-certified-operators="))
460+
o.Expect(listOutput).To(o.ContainSubstring("openshift-community-operators="))
461+
o.Expect(listOutput).To(o.ContainSubstring("openshift-redhat-operators="))
462+
o.Expect(listOutput).To(o.ContainSubstring(catalogName + "="))
463+
464+
g.By("Get catalog content URLs")
465+
redhatCatalog := olmv1util.ClusterCatalogDescription{Name: "openshift-redhat-operators"}
466+
redhatCatalog.GetContentURL(oc)
467+
468+
g.By("Create redhat-operators-all.json")
469+
redhatData, err := fetchToFile(redhatCatalog.ContentURL, redhatOperatorsFile)
470+
o.Expect(err).NotTo(o.HaveOccurred())
471+
_, err = os.Stat(redhatOperatorsFile)
472+
o.Expect(err).NotTo(o.HaveOccurred())
473+
474+
g.By("Create all.json for catalog-85889")
475+
customData, err := fetchToFile(clustercatalog.ContentURL, customCatalogFile)
476+
o.Expect(err).NotTo(o.HaveOccurred())
477+
_, err = os.Stat(customCatalogFile)
478+
o.Expect(err).NotTo(o.HaveOccurred())
479+
480+
g.By("List OLM packages from redhat-operators")
481+
redhatEntries, err := parseCatalogEntries(redhatData)
482+
o.Expect(err).NotTo(o.HaveOccurred())
483+
var packageNames []string
484+
for _, entry := range redhatEntries {
485+
if entry.Schema == "olm.package" && entry.Name != "" {
486+
packageNames = append(packageNames, entry.Name)
487+
}
488+
}
489+
o.Expect(packageNames).NotTo(o.BeEmpty())
490+
491+
g.By("Get channel info for custom catalog")
492+
customEntries, err := parseCatalogEntries(customData)
493+
o.Expect(err).NotTo(o.HaveOccurred())
494+
customPackages := map[string]struct{}{}
495+
for _, entry := range customEntries {
496+
if entry.Schema == "olm.package" && entry.Name != "" {
497+
customPackages[entry.Name] = struct{}{}
498+
}
499+
}
500+
o.Expect(customPackages).NotTo(o.BeEmpty())
501+
502+
channelFound := false
503+
for _, entry := range customEntries {
504+
if entry.Schema == "olm.channel" && entry.Package != "" {
505+
if _, ok := customPackages[entry.Package]; ok {
506+
channelFound = true
507+
break
508+
}
509+
}
510+
}
511+
o.Expect(channelFound).To(o.BeTrue())
512+
513+
g.By("Get bundle info for custom catalog")
514+
bundleFound := false
515+
for _, entry := range customEntries {
516+
if entry.Schema == "olm.bundle" && entry.Package != "" && entry.Name != "" {
517+
if _, ok := customPackages[entry.Package]; ok {
518+
bundleFound = true
519+
break
520+
}
521+
}
522+
}
523+
o.Expect(bundleFound).To(o.BeTrue())
524+
525+
g.By("Check ClusterCatalog reconciliation logs")
526+
consoleLogs, err := getCatalogdLogs()
527+
o.Expect(err).NotTo(o.HaveOccurred())
528+
consoleLogsLower := strings.ToLower(consoleLogs)
529+
o.Expect(strings.TrimSpace(consoleLogs)).NotTo(o.BeEmpty())
530+
o.Expect(strings.Contains(consoleLogsLower, "panic")).To(o.BeFalse())
531+
o.Expect(strings.Contains(consoleLogsLower, "stack trace")).To(o.BeFalse())
532+
533+
var errWait error
534+
535+
g.By("Check reconcile_total metrics before patch")
536+
reconcileBefore, err := getReconcileTotal()
537+
metricsAvailable := true
538+
if err != nil {
539+
metricsAvailable = false
540+
e2e.Logf("Skipping reconcile_total checks: %v", err)
541+
}
542+
543+
if metricsAvailable {
544+
g.By("Patch catalog-85889 image")
545+
patch := `{"spec":{"source":{"type":"Image","image":{"ref":"quay.io/operatorhubio/catalog:latest"}}}}`
546+
clustercatalog.Patch(oc, patch)
547+
548+
g.By("Confirm reconcile_total increases after patch")
549+
errWait := wait.PollUntilContextTimeout(context.TODO(), 10*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) {
550+
reconcileAfter, err := getReconcileTotal()
551+
if err != nil {
552+
return false, nil
553+
}
554+
return reconcileAfter > reconcileBefore, nil
555+
})
556+
exutil.AssertWaitPollNoErr(errWait, "reconcile_total did not increase after patch")
557+
}
558+
559+
g.By("Delete test ClusterCatalog")
560+
clustercatalog.Delete(oc)
561+
deleted = true
562+
563+
g.By("Verify ClusterCatalog deletion")
564+
errWait = wait.PollUntilContextTimeout(context.TODO(), 10*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) {
565+
output, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("clustercatalog", catalogName, "--ignore-not-found").Output()
566+
if err != nil {
567+
return false, nil
568+
}
569+
return strings.TrimSpace(output) == "", nil
570+
})
571+
exutil.AssertWaitPollNoErr(errWait, "catalog-85889 was not deleted")
572+
})
573+
325574
g.It("PolarionID:73219-[OTP][Skipped:Disconnected]Fetch deprecation data from the catalogd http server", func() {
326575
var (
327576
baseDir = exutil.FixturePath("testdata", "olm")

0 commit comments

Comments
 (0)