Skip to content
Open
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
6 changes: 6 additions & 0 deletions cmd/cluster-config-operator-tests-ext/dependencymagnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package main

import (
_ "github.com/openshift/build-machinery-go"
_ "github.com/openshift/cluster-config-operator/test/e2e"
)
70 changes: 44 additions & 26 deletions cmd/cluster-config-operator-tests-ext/main.go
Original file line number Diff line number Diff line change
@@ -1,73 +1,91 @@
/*
This command is used to run the Cluster Config Operator tests extension for OpenShift.
It registers the Cluster Config Operator tests with the OpenShift Tests Extension framework
and provides a command-line interface to execute them.
For further information, please refer to the documentation at:
https://github.com/openshift-eng/openshift-tests-extension/blob/main/cmd/example-tests/main.go
*/
// Package main provides the OpenShift Test Extension (OTE) CLI binary for cluster-config-operator.
//
// DEPLOYMENT MODEL:
// Once this binary is statically compiled (CGO_ENABLED=0), compressed, and included in the
// component Dockerfile, it will be registered in openshift/origin's test extension registry.
// The tests will then automatically execute through origin's orchestration infrastructure in
// matching existing CI jobs WITHOUT requiring standalone job configurations in openshift/release.
// For further information, please refer to the documentation at:
// https://github.com/openshift-eng/openshift-tests-extension/blob/main/cmd/example-tests/main.go

package main

import (
"fmt"
"os"

"github.com/spf13/cobra"
"k8s.io/component-base/cli"

otecmd "github.com/openshift-eng/openshift-tests-extension/pkg/cmd"
oteextension "github.com/openshift-eng/openshift-tests-extension/pkg/extension"
"github.com/openshift/cluster-config-operator/pkg/version"
oteginkgo "github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo"

"k8s.io/klog/v2"

// Import the test package to register Ginkgo test suites
_ "github.com/openshift/cluster-config-operator/test/e2e"
)

func main() {
cmd, err := newOperatorTestCommand()
if err != nil {
klog.Fatal(err)
}

code := cli.Run(cmd)
os.Exit(code)
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}

func newOperatorTestCommand() (*cobra.Command, error) {
registry, err := prepareOperatorTestsRegistry()
if err != nil {
return nil, fmt.Errorf("failed to prepare test registry: %w", err)
return nil, err
}

cmd := &cobra.Command{
Use: "cluster-config-operator-tests-ext",
Short: "A binary used to run cluster-config-operator tests as part of OTE.",
Long: "Cluster Config Operator Tests Extension",
Run: func(cmd *cobra.Command, args []string) {
// no-op, logic is provided by the OTE framework
if err := cmd.Help(); err != nil {
klog.Fatal(err)
}
},
}

if v := version.Get().String(); len(v) == 0 {
cmd.Version = "<unknown>"
} else {
cmd.Version = v
}

cmd.AddCommand(otecmd.DefaultExtensionCommands(registry)...)

return cmd, nil
}

// prepareOperatorTestsRegistry creates the OTE registry for this operator.
//
// Note:
//
// This method must be called before adding the registry to the OTE framework.
func prepareOperatorTestsRegistry() (*oteextension.Registry, error) {
registry := oteextension.NewRegistry()
extension := oteextension.NewExtension("openshift", "payload", "cluster-config-operator")

// parallel suite runs non-serial, non-disruptive tests concurrently with parallelism of 4.
extension.AddSuite(oteextension.Suite{
Name: "openshift/cluster-config-operator/operator/parallel",
Parallelism: 4,
Qualifiers: []string{
`!name.contains("[Serial]") && !name.contains("[Disruptive]")`,
},
})

// <Place-holder> disruptive suite runs serial or disruptive tests one at a time, may impact cluster stability.
extension.AddSuite(oteextension.Suite{
Name: "openshift/cluster-config-operator/operator/disruptive",
Parallelism: 1,
ClusterStability: oteextension.ClusterStabilityDisruptive,
Qualifiers: []string{
`name.contains("[Serial]") || name.contains("[Disruptive]")`,
},
})

specs, err := oteginkgo.BuildExtensionTestSpecsFromOpenShiftGinkgoSuite()
if err != nil {
return nil, fmt.Errorf("couldn't build extension test specs from ginkgo: %w", err)
}

extension.AddSpecs(specs)
registry.Register(extension)
return registry, nil
}
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ require (
github.com/blang/semver/v4 v4.0.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/go-bindata/go-bindata v3.1.2+incompatible
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250804142706-7b3ab438a292
github.com/onsi/ginkgo/v2 v2.27.2
github.com/openshift-eng/openshift-tests-extension v0.0.0-20260528165303-ac98bf018579
github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee
github.com/openshift/client-go v0.0.0-20260429123927-c81f86abfa6a
Expand All @@ -16,6 +17,7 @@ require (
github.com/stretchr/testify v1.11.1
gopkg.in/gcfg.v1 v1.2.3
k8s.io/api v0.35.1
k8s.io/apiextensions-apiserver v0.35.1
k8s.io/apimachinery v0.35.1
k8s.io/client-go v0.35.1
k8s.io/component-base v0.35.1
Expand Down Expand Up @@ -43,6 +45,7 @@ require (
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.3 // indirect
Expand All @@ -62,7 +65,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/onsi/gomega v1.38.2 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
Expand Down Expand Up @@ -99,6 +102,7 @@ require (
golang.org/x/term v0.38.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.39.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.79.3 // indirect
Expand All @@ -108,7 +112,6 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.35.1 // indirect
k8s.io/apiserver v0.35.1 // indirect
k8s.io/kms v0.35.1 // indirect
k8s.io/kube-aggregator v0.35.1 // indirect
Expand Down
7 changes: 2 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
Expand Down Expand Up @@ -137,8 +136,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250804142706-7b3ab438a292 h1:3athg6KQ+TaNfW4BWZDlGFt1ImSZEJWgzXtPC1VPITI=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250804142706-7b3ab438a292/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20260528165303-ac98bf018579 h1:9O8t7c4tYOBjePUF57UImkpVknpvlMW7svjuP4898Cc=
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to move go dependencies in separate commit from test cases

github.com/openshift-eng/openshift-tests-extension v0.0.0-20260528165303-ac98bf018579/go.mod h1:pHOS9c6BjZv91OkkHyIHAOWnYhxwcxWQkyYGEvPyUCE=
github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9 h1:lZw6pYY7El1giNk1lYvkp6hLungiqwIOqLlH+Hm7w9g=
github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee h1:+Sp5GGnjHDhT/a/nQ1xdp43UscBMr7G5wxsYotyhzJ4=
Expand All @@ -150,8 +149,6 @@ github.com/openshift/library-go v0.0.0-20260429171401-d45f1f2500c3/go.mod h1:k1t
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241205171354-8006f302fd12 h1:AKx/w1qpS8We43bsRgf8Nll3CGlDHpr/WAXvuedTNZI=
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241205171354-8006f302fd12/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
134 changes: 134 additions & 0 deletions test/e2e/e2e.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package e2e

import (
"context"
"testing"
"time"

g "github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/require"

configclient "github.com/openshift/client-go/config/clientset/versioned"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

const (
infrastructureResourceName = "cluster"
pollInterval = 5 * time.Second
pollTimeout = 2 * time.Minute
)

// Test suite for cluster-config-operator configuration validation
var _ = g.Describe("cluster-config-operator", func() {
g.It("should establish config.openshift.io CRDs as healthy and serving [apigroup:config.openshift.io][Operator]", func() {
testConfigCRDsEstablished(g.GinkgoTB())
})

g.It("should render cluster-wide Infrastructure configuration [apigroup:config.openshift.io][Operator]", func() {
testInfrastructureConfiguration(g.GinkgoTB())
})
})

// testConfigCRDsEstablished verifies that core config.openshift.io CRDs are established and serving.
// cluster-config-operator is responsible for applying these CRDs during cluster bootstrap.
// This test validates that the API server recognizes and serves these critical API definitions.
func testConfigCRDsEstablished(t testing.TB) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is new case no need go standard framework design. We can use ginkgo format

t.Helper()

config, err := getClientConfig()
require.NoError(t, err, "failed to get client config")

apiextClient, err := apiextensionsclient.NewForConfig(config)
require.NoError(t, err, "failed to create apiextensions client")

// Core config.openshift.io CRDs that cluster-config-operator establishes
coreCRDs := []string{
"infrastructures.config.openshift.io",
"featuregates.config.openshift.io",
"schedulers.config.openshift.io",
"networks.config.openshift.io",
"clusterversions.config.openshift.io",
}

ctx := context.TODO()
for _, crdName := range coreCRDs {
err = wait.PollUntilContextTimeout(ctx, pollInterval, pollTimeout, true, func(ctx context.Context) (bool, error) {
crd, getErr := apiextClient.ApiextensionsV1().CustomResourceDefinitions().Get(ctx, crdName, metav1.GetOptions{})
if getErr != nil {
t.Logf("Failed to get CRD %s: %v (will retry)", crdName, getErr)
return false, nil
}

// Check if CRD is Established
established := false
for _, condition := range crd.Status.Conditions {
if condition.Type == apiextensionsv1.Established && condition.Status == apiextensionsv1.ConditionTrue {
established = true
break
}
}

if !established {
t.Logf("CRD %s not yet Established (will retry)", crdName)
return false, nil
}

t.Logf("CRD %s is Established and serving", crdName)
return true, nil
})

require.NoError(t, err, "timed out waiting for CRD %s to be Established", crdName)
}
}

// testInfrastructureConfiguration verifies that the cluster-config-operator has successfully
// rendered the cluster-wide Infrastructure configuration object named "cluster".
// This resource is created and maintained by cluster-config-operator during bootstrap and
// contains critical platform metadata such as platform type, API server URLs, and topology.
func testInfrastructureConfiguration(t testing.TB) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this cases added some value?

t.Helper()

config, err := getClientConfig()
require.NoError(t, err, "failed to get client config")

configClient, err := configclient.NewForConfig(config)
require.NoError(t, err, "failed to create config client")

// Poll until the Infrastructure resource is available and valid
err = wait.PollUntilContextTimeout(context.TODO(), pollInterval, pollTimeout, true, func(ctx context.Context) (bool, error) {
infra, getErr := configClient.ConfigV1().Infrastructures().Get(ctx, infrastructureResourceName, metav1.GetOptions{})
if getErr != nil {
t.Logf("Failed to get Infrastructure resource %s: %v (will retry)", infrastructureResourceName, getErr)
return false, nil
}

// Verify that the Infrastructure resource has required fields populated
if infra.Status.PlatformStatus == nil {
t.Logf("Infrastructure %s has nil PlatformStatus (will retry)", infrastructureResourceName)
return false, nil
}

if infra.Status.PlatformStatus.Type == "" {
t.Logf("Infrastructure %s has empty platform type (will retry)", infrastructureResourceName)
return false, nil
}

t.Logf("Infrastructure %s is valid: platform=%s", infrastructureResourceName, infra.Status.PlatformStatus.Type)
return true, nil
})

require.NoError(t, err, "timed out waiting for Infrastructure resource to be valid")
}

// getClientConfig builds a rest.Config from the default kubeconfig loading rules
func getClientConfig() (*rest.Config, error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
configOverrides := &clientcmd.ConfigOverrides{}
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
return kubeConfig.ClientConfig()
}
14 changes: 14 additions & 0 deletions vendor/github.com/go-task/slim-sprig/v3/.editorconfig

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/github.com/go-task/slim-sprig/v3/.gitattributes

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions vendor/github.com/go-task/slim-sprig/v3/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading