@@ -14,6 +14,7 @@ import (
1414 "github.com/spf13/cobra"
1515 corev1 "k8s.io/api/core/v1"
1616 kclientset "k8s.io/client-go/kubernetes"
17+ restclient "k8s.io/client-go/rest"
1718 "k8s.io/client-go/tools/clientcmd"
1819 "k8s.io/kubernetes/test/e2e/framework"
1920
@@ -39,10 +40,9 @@ func main() {
3940 Qualifiers : []string {`!labels.exists(l, l == "Serial") && labels.exists(l, l == "Conformance")` },
4041 })
4142
42- // Initialize framework for the tests.
43- if err := initFrameworkForTests (); err != nil {
44- panic (fmt .Errorf ("failed to initialize test framework: %w" , err ))
45- }
43+ // Initialize framework for the tests. Works with or without KUBECONFIG
44+ // so that "info" and "list tests" commands can run without cluster access.
45+ initFrameworkForTests ()
4646
4747 // Build the extension test specs
4848 specs , err := g .BuildExtensionTestSpecsFromOpenShiftGinkgoSuite ()
@@ -125,16 +125,14 @@ func getRegionFromEnv() string {
125125}
126126
127127// initFrameworkForTests initializes the framework for the tests globally.
128- func initFrameworkForTests () error {
129- if len (os .Getenv ("KUBECONFIG" )) == 0 {
130- return fmt .Errorf ("KUBECONFIG is empty. Set the KUBECONFIG environment variable" )
131- }
132-
133- // Initialize framework - required for test discovery
134- // TODO:
135- // 1. Fix the provider getting from env (when ote supports aws)
136- // 2. Build the config from the env, and set the testContext.CloudConfig (if required by the test)
137- // 3. Move this init to a dedicated function
128+ // When KUBECONFIG is set, it loads the cluster config and sets the host.
129+ // When KUBECONFIG is not set, it uses a placeholder host so that
130+ // AfterReadingAllFlags can run without emitting a klog warning to stdout
131+ // (which would violate the OTE Binary Stdout Contract for info/list commands).
132+ // TODO:
133+ // 1. Fix the provider getting from env (when ote supports aws)
134+ // 2. Build the config from the env, and set the testContext.CloudConfig (if required by the test)
135+ func initFrameworkForTests () {
138136 testContext .Provider = "local" // TODO: OTE supports local or skeleton
139137
140138 // Set up AWS cloud configuration when environment variables are set.
@@ -157,27 +155,37 @@ func initFrameworkForTests() error {
157155 testContext .NodeOSDistro = "custom"
158156 testContext .MasterOSDistro = "custom"
159157
160- // Load kube client config and set the host variable for kubectl
161- testContext .KubeConfig = os .Getenv ("KUBECONFIG" )
162- clientConfig := clientcmd .NewNonInteractiveDeferredLoadingClientConfig (
163- & clientcmd.ClientConfigLoadingRules {
164- ExplicitPath : testContext .KubeConfig ,
165- },
166- & clientcmd.ConfigOverrides {},
167- )
168- cfg , err := clientConfig .ClientConfig ()
169- if err != nil {
170- return fmt .Errorf ("failed to get client config: %w" , err )
158+ // Load kube client config when available.
159+ if kubeconfig := os .Getenv ("KUBECONFIG" ); len (kubeconfig ) > 0 {
160+ testContext .KubeConfig = kubeconfig
161+ clientConfig := clientcmd .NewNonInteractiveDeferredLoadingClientConfig (
162+ & clientcmd.ClientConfigLoadingRules {
163+ ExplicitPath : testContext .KubeConfig ,
164+ },
165+ & clientcmd.ConfigOverrides {},
166+ )
167+ if cfg , err := clientConfig .ClientConfig (); err == nil {
168+ testContext .Host = cfg .Host
169+ }
170+ } else if _ , err := restclient .InClusterConfig (); err != nil {
171+ // No KUBECONFIG and not running in-cluster. Set a placeholder Host so
172+ // AfterReadingAllFlags skips in-cluster config detection, which would
173+ // emit a klog warning through GinkgoWriter to stdout.
174+ testContext .Host = "placeholder"
171175 }
172- testContext .Host = cfg .Host
173176
174- // After reading all flags, this will configure the test context, and need to be
175- // called once by framework to avoid re-configuring the test context, and leding
176- // to issues in Ginkgo phases (PhaseBuildTopLevel, PhaseBuildTree, PhaseRun),
177- // such as:'cannot clone suite after tree has been built'
177+ // Redirect framework.Output to stderr to preserve the OTE Binary Stdout
178+ // Contract (info/list tests commands must output clean JSON on stdout).
179+ framework .Output = os .Stderr
180+
181+ // Must be called during startup (before the Ginkgo tree is built) because it
182+ // internally calls ginkgo.PreviewSpecs which clones the suite.
178183 framework .AfterReadingAllFlags (testContext )
179184
180- return nil
185+ // Clear the placeholder so tests don't accidentally use it.
186+ if testContext .Host == "placeholder" {
187+ testContext .Host = ""
188+ }
181189}
182190
183191// initFrameworkForTest initializes the framework for the test instance.
0 commit comments