Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/update-demos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ on:
- 'api/*'
- 'config/*'
- 'test/e2e/platform/features/demos.feature'
- 'test/internal/e2e/steps/demo_steps.go'
- 'test/internal/e2e/steps/asciicast_*.go'
- 'test/internal/e2e/platform/steps/demo_steps.go'
- 'test/internal/e2e/platform/steps/asciicast_*.go'
- '.github/workflows/update-demos.yaml'
pull_request:
paths:
- 'api/*'
- 'config/*'
- 'test/e2e/platform/features/demos.feature'
- 'test/internal/e2e/steps/demo_steps.go'
- 'test/internal/e2e/steps/asciicast_*.go'
- 'test/internal/e2e/platform/steps/demo_steps.go'
- 'test/internal/e2e/platform/steps/asciicast_*.go'
- '.github/workflows/update-demos.yaml'

jobs:
Expand Down
1 change: 0 additions & 1 deletion test/e2e/catalogd/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func TestMain(m *testing.M) {
}, func(sc *godog.ScenarioContext) {
steps.RegisterSteps(sc)
catalogsteps.RegisterSteps(sc)
steps.RegisterDemoSteps(sc)
catalogsteps.RegisterHooks(sc)
steps.RegisterHooks(sc)
}))
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/features_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/operator-framework/operator-controller/test/internal/e2e"
catalogsteps "github.com/operator-framework/operator-controller/test/internal/e2e/catalogd/steps"
platformsteps "github.com/operator-framework/operator-controller/test/internal/e2e/platform/steps"
"github.com/operator-framework/operator-controller/test/internal/e2e/steps"
)

Expand Down Expand Up @@ -43,8 +44,8 @@ func TestMain(m *testing.M) {
}, func(sc *godog.ScenarioContext) {
steps.RegisterSteps(sc)
catalogsteps.RegisterSteps(sc)
steps.RegisterDemoSteps(sc)
platformsteps.RegisterDemoSteps(sc)
catalogsteps.RegisterHooks(sc)
steps.RegisterHooks(sc, steps.RegisterAsciiCastHooks)
steps.RegisterHooks(sc, platformsteps.RegisterAsciiCastHooks)
}))
}
1 change: 0 additions & 1 deletion test/e2e/object-controller/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ func TestMain(m *testing.M) {
tc.BeforeSuite(steps.BeforeSuite)
}, func(sc *godog.ScenarioContext) {
steps.RegisterSteps(sc)
steps.RegisterDemoSteps(sc)
steps.RegisterHooks(sc)
}))
}
1 change: 0 additions & 1 deletion test/e2e/operator-controller/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ func TestMain(m *testing.M) {
tc.BeforeSuite(steps.BeforeSuite)
}, func(sc *godog.ScenarioContext) {
steps.RegisterSteps(sc)
steps.RegisterDemoSteps(sc)
steps.RegisterHooks(sc)
}))
}
5 changes: 3 additions & 2 deletions test/e2e/platform/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/cucumber/godog"

"github.com/operator-framework/operator-controller/test/internal/e2e"
platformsteps "github.com/operator-framework/operator-controller/test/internal/e2e/platform/steps"
"github.com/operator-framework/operator-controller/test/internal/e2e/steps"
)

Expand All @@ -15,7 +16,7 @@ func TestMain(m *testing.M) {
tc.BeforeSuite(steps.BeforeSuite)
}, func(sc *godog.ScenarioContext) {
steps.RegisterSteps(sc)
steps.RegisterDemoSteps(sc)
steps.RegisterHooks(sc, steps.RegisterAsciiCastHooks)
platformsteps.RegisterDemoSteps(sc)
steps.RegisterHooks(sc, platformsteps.RegisterAsciiCastHooks)
}))
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"strings"

"github.com/cucumber/godog"

shared "github.com/operator-framework/operator-controller/test/internal/e2e/steps"
)

const demoTag = "@demo"
Expand Down Expand Up @@ -39,7 +41,7 @@ func startRecordingIfDemo(ctx context.Context, sc *godog.Scenario) (context.Cont
return ctx, nil
}
rec := NewAsciiCastRecorder(sc.Name, demoOutputDir)
logger.Info("Starting asciicast recording", "scenario", sc.Name, "output", rec.castPath)
shared.Log().Info("Starting asciicast recording", "scenario", sc.Name, "output", rec.castPath)
return WithRecorder(ctx, rec), nil
}

Expand Down Expand Up @@ -69,14 +71,14 @@ func stopRecordingIfDemo(ctx context.Context, sc *godog.Scenario, err error) (co
return ctx, nil
}
if stopErr := rec.Stop(); stopErr != nil {
logger.Info("Failed to write asciicast file", "error", stopErr)
shared.Log().Info("Failed to write asciicast file", "error", stopErr)
if err == nil {
return ctx, stopErr
}
} else {
// Slugify scenario name the same way as the recorder
slug := strings.ToLower(strings.ReplaceAll(sc.Name, " ", "-"))
logger.Info("Asciicast recording saved", "file", demoOutputDir+"/"+slug+".cast")
shared.Log().Info("Asciicast recording saved", "file", demoOutputDir+"/"+slug+".cast")
}
return ctx, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"path/filepath"
"strings"
"time"

shared "github.com/operator-framework/operator-controller/test/internal/e2e/steps"
)

type recorderContextKey struct{}
Expand All @@ -17,7 +19,7 @@ type recorderContextKey struct{}
// intentionally use the same instance; callers must not override the command
// recorder separately on the returned context.
func WithRecorder(ctx context.Context, rec *AsciiCastRecorder) context.Context {
return context.WithValue(WithCommandRecorder(ctx, rec), recorderContextKey{}, rec)
return context.WithValue(shared.WithCommandRecorder(ctx, rec), recorderContextKey{}, rec)
}

func RecorderFromContext(ctx context.Context) *AsciiCastRecorder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (

"github.com/cucumber/godog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

shared "github.com/operator-framework/operator-controller/test/internal/e2e/steps"
)

func RegisterDemoSteps(sc *godog.ScenarioContext) {
Expand All @@ -28,7 +30,7 @@ func RegisterDemoSteps(sc *godog.ScenarioContext) {

func bash(ctx context.Context, script string) (string, error) {
cmd := exec.CommandContext(ctx, "bash", "-c", script)
logger.V(1).Info("Running", "command", script)
shared.Log().V(1).Info("Running", "command", script)

var stdoutBuf, stderrBuf bytes.Buffer
cmd.Stdout = &stdoutBuf
Expand All @@ -42,33 +44,33 @@ func bash(ctx context.Context, script string) (string, error) {
stderr := stderrBuf.String()

if err != nil {
logger.V(1).Info("Failed to run", "command", script, "stderr", stderr, "error", err)
shared.Log().V(1).Info("Failed to run", "command", script, "stderr", stderr, "error", err)
var exitErr *exec.ExitError
if errors.As(err, &exitErr) {
exitErr.Stderr = stderrBuf.Bytes()
}
}
logger.V(1).Info("Output", "command", script, "output", stdout)
shared.Log().V(1).Info("Output", "command", script, "output", stdout)

if rec := CommandRecorderFromContext(ctx); rec != nil {
if rec := shared.CommandRecorderFromContext(ctx); rec != nil {
rec.RecordCommand(script, stdout, stderr, elapsed)
}
return stdout, err
}

func CatalogReportsConditionWithoutReason(ctx context.Context, catalogUserName, conditionType, conditionStatus string) error {
sc := Scenario(ctx)
sc := shared.Scenario(ctx)
catalogName, ok := sc.Catalogs[catalogUserName]
if !ok {
if _, err := K8sClient(ctx, "get", "clustercatalog", catalogUserName); err != nil {
if _, err := shared.K8sClient(ctx, "get", "clustercatalog", catalogUserName); err != nil {
return fmt.Errorf("catalog %q was not created by this scenario and does not exist on the cluster", catalogUserName)
}
catalogName = catalogUserName
}
err := WaitForCondition(ctx, "clustercatalog", catalogName, conditionType, metav1.ConditionStatus(conditionStatus), nil, nil)
err := shared.WaitForCondition(ctx, "clustercatalog", catalogName, conditionType, metav1.ConditionStatus(conditionStatus), nil, nil)
if err == nil {
if rec := CommandRecorderFromContext(ctx); rec != nil {
out, _ := K8sClient(ctx, "get", "clustercatalog", catalogName,
if rec := shared.CommandRecorderFromContext(ctx); rec != nil {
out, _ := shared.K8sClient(ctx, "get", "clustercatalog", catalogName,
"-o", fmt.Sprintf("jsonpath={.status.conditions[?(@.type==\"%s\")]}", conditionType))
var pretty bytes.Buffer
if jsonErr := json.Indent(&pretty, []byte(out), "", " "); jsonErr == nil {
Expand All @@ -85,40 +87,40 @@ func CatalogReportsConditionWithoutReason(ctx context.Context, catalogUserName,
}

func ensureCatalogPortForward(ctx context.Context) (string, error) {
sc := Scenario(ctx)
sc := shared.Scenario(ctx)
if sc.CatalogAddr != "" {
if catalogPortForwardAlive(sc.CatalogAddr) {
return sc.CatalogAddr, nil
}
logger.V(1).Info("Catalog port-forward is dead, re-establishing", "addr", sc.CatalogAddr)
shared.Log().V(1).Info("Catalog port-forward is dead, re-establishing", "addr", sc.CatalogAddr)
resetCatalogPortForward(ctx)
}

ns := ComponentNamespaces["catalogd"]
ns := shared.ComponentNamespaces["catalogd"]
target, err := catalogdLeaderPod(ctx, ns)
port := int32(443)
if err != nil {
logger.V(1).Info("Could not resolve catalogd leader pod, falling back to service", "error", err)
shared.Log().V(1).Info("Could not resolve catalogd leader pod, falling back to service", "error", err)
target = "service/catalogd-service"
} else {
port = 8443
}

addr, cleanup, err := PortForward(ctx, ns, target, port)
addr, cleanup, err := shared.PortForward(ctx, ns, target, port)
if err != nil {
return "", fmt.Errorf("failed to start catalog port-forward to %s: %w", target, err)
}
sc.CatalogAddr = addr
sc.CatalogCleanup = cleanup

WaitFor(ctx, func() bool {
shared.WaitFor(ctx, func() bool {
return catalogPortForwardAlive(addr)
})
return addr, nil
}

func catalogdLeaderPod(ctx context.Context, ns string) (string, error) {
holder, err := K8sClient(ctx, "get", "lease", "catalogd-operator-lock", "-n", ns,
holder, err := shared.K8sClient(ctx, "get", "lease", "catalogd-operator-lock", "-n", ns,
"-o", "jsonpath={.spec.holderIdentity}")
if err != nil {
return "", fmt.Errorf("failed to get catalogd leader lease: %w", err)
Expand All @@ -131,7 +133,7 @@ func catalogdLeaderPod(ctx context.Context, ns string) (string, error) {
if podName == "" {
return "", fmt.Errorf("catalogd leader lease has empty holderIdentity")
}
logger.Info("Resolved catalogd leader pod", "holder", holder, "pod", podName)
shared.Log().Info("Resolved catalogd leader pod", "holder", holder, "pod", podName)
return fmt.Sprintf("pod/%s", podName), nil
}

Expand All @@ -156,7 +158,7 @@ func catalogPortForwardAlive(addr string) bool {
// CatalogdHA, non-leader pods return 404 (empty local cache); resetting
// lets the next retry potentially reach the leader pod.
func resetCatalogPortForward(ctx context.Context) {
sc := Scenario(ctx)
sc := shared.Scenario(ctx)
if sc.CatalogCleanup != nil {
sc.CatalogCleanup()
}
Expand Down Expand Up @@ -185,15 +187,15 @@ func catalogCurlJq(ctx context.Context, catalogName, jqFilter string) (string, e
}

func CatalogContainsSomePackages(ctx context.Context, catalogName string) error {
WaitFor(ctx, func() bool {
shared.WaitFor(ctx, func() bool {
out, err := catalogCurlJq(ctx, catalogName,
`objects | select(.schema == "olm.package") | .name`)
if err != nil {
logger.Info("Catalog query failed, retrying", "catalog", catalogName, "error", err, "stderr", stderrOutput(err))
shared.Log().Info("Catalog query failed, retrying", "catalog", catalogName, "error", err, "stderr", shared.StderrOutput(err))
return false
}
if strings.TrimSpace(out) == "" {
logger.Info("Catalog returned no packages, retrying", "catalog", catalogName)
shared.Log().Info("Catalog returned no packages, retrying", "catalog", catalogName)
return false
}
return true
Expand All @@ -202,15 +204,15 @@ func CatalogContainsSomePackages(ctx context.Context, catalogName string) error
}

func PackageHasSomeChannels(ctx context.Context, packageName, catalogName string) error {
WaitFor(ctx, func() bool {
shared.WaitFor(ctx, func() bool {
out, err := catalogCurlJq(ctx, catalogName,
fmt.Sprintf(`objects | select(.schema == "olm.channel") | select(.package == "%s") | .name`, packageName))
if err != nil {
logger.Info("Catalog query failed, retrying", "catalog", catalogName, "package", packageName, "error", err, "stderr", stderrOutput(err))
shared.Log().Info("Catalog query failed, retrying", "catalog", catalogName, "package", packageName, "error", err, "stderr", shared.StderrOutput(err))
return false
}
if strings.TrimSpace(out) == "" {
logger.Info("Package has no channels, retrying", "catalog", catalogName, "package", packageName)
shared.Log().Info("Package has no channels, retrying", "catalog", catalogName, "package", packageName)
return false
}
return true
Expand All @@ -219,15 +221,15 @@ func PackageHasSomeChannels(ctx context.Context, packageName, catalogName string
}

func PackageHasSomeBundles(ctx context.Context, packageName, catalogName string) error {
WaitFor(ctx, func() bool {
shared.WaitFor(ctx, func() bool {
out, err := catalogCurlJq(ctx, catalogName,
fmt.Sprintf(`objects | select(.schema == "olm.bundle") | select(.package == "%s") | .name`, packageName))
if err != nil {
logger.Info("Catalog query failed, retrying", "catalog", catalogName, "package", packageName, "error", err, "stderr", stderrOutput(err))
shared.Log().Info("Catalog query failed, retrying", "catalog", catalogName, "package", packageName, "error", err, "stderr", shared.StderrOutput(err))
return false
}
if strings.TrimSpace(out) == "" {
logger.Info("Package has no bundles, retrying", "catalog", catalogName, "package", packageName)
shared.Log().Info("Package has no bundles, retrying", "catalog", catalogName, "package", packageName)
return false
}
return true
Expand All @@ -236,8 +238,8 @@ func PackageHasSomeBundles(ctx context.Context, packageName, catalogName string)
}

func RolebindingsReferenceServiceAccount(ctx context.Context, rbNamespace, saName, saNamespace string) error {
saNamespace = SubstituteScenarioVars(saNamespace, Scenario(ctx))
out, err := K8sClient(ctx, "get", "rolebindings", "-n", rbNamespace, "-o", "json")
saNamespace = shared.SubstituteScenarioVars(saNamespace, shared.Scenario(ctx))
out, err := shared.K8sClient(ctx, "get", "rolebindings", "-n", rbNamespace, "-o", "json")
if err != nil {
return fmt.Errorf("failed to list rolebindings in namespace %q: %w", rbNamespace, err)
}
Expand All @@ -261,8 +263,8 @@ func RolebindingsReferenceServiceAccount(ctx context.Context, rbNamespace, saNam
for _, rb := range rbList.Items {
for _, s := range rb.Subjects {
if s.Kind == "ServiceAccount" && s.Name == saName && s.Namespace == saNamespace {
if rec := CommandRecorderFromContext(ctx); rec != nil {
subjectsOut, _ := K8sClient(ctx, "get", "rolebinding", rb.Metadata.Name, "-n", rbNamespace,
if rec := shared.CommandRecorderFromContext(ctx); rec != nil {
subjectsOut, _ := shared.K8sClient(ctx, "get", "rolebinding", rb.Metadata.Name, "-n", rbNamespace,
"-o", "jsonpath={.subjects}")
rec.RecordCustom(
fmt.Sprintf("kubectl get rolebinding %s -n %s -o jsonpath='{.subjects}' | jq .", rb.Metadata.Name, rbNamespace),
Expand All @@ -277,19 +279,19 @@ func RolebindingsReferenceServiceAccount(ctx context.Context, rbNamespace, saNam
}

func PodHasContainerCount(ctx context.Context, podName string, expected int) error {
sc := Scenario(ctx)
sc := shared.Scenario(ctx)
var actual int
WaitFor(ctx, func() bool {
out, err := K8sClient(ctx, "get", "pod", podName, "-n", sc.Namespace, "-o", "jsonpath={.spec.containers[*].name}")
shared.WaitFor(ctx, func() bool {
out, err := shared.K8sClient(ctx, "get", "pod", podName, "-n", sc.Namespace, "-o", "jsonpath={.spec.containers[*].name}")
if err != nil {
return false
}
names := strings.Fields(strings.TrimSpace(out))
actual = len(names)
return actual == expected
})
if rec := CommandRecorderFromContext(ctx); rec != nil {
out, _ := K8sClient(ctx, "get", "pod", podName, "-n", sc.Namespace, "-o", "jsonpath={.spec.containers[*].name}")
if rec := shared.CommandRecorderFromContext(ctx); rec != nil {
out, _ := shared.K8sClient(ctx, "get", "pod", podName, "-n", sc.Namespace, "-o", "jsonpath={.spec.containers[*].name}")
rec.RecordCustom(
fmt.Sprintf("kubectl get pod %s -n %s -o jsonpath='{.spec.containers[*].name}'", podName, sc.Namespace),
out+"\n", "",
Expand Down
Loading
Loading