Skip to content

Commit edd872f

Browse files
committed
CNTRLPLANE-XXXX: set up openshift-tests-extension and add a sanity test
This commit introduces a binary and supporting structure to enable the execution of OpenShift cluster-kube-controller-manager-operator tests using the Open Test Environment (OTE). It lays the groundwork for moving tests to be executed from this repository using OTE. Changes: - Add cmd/cluster-kube-controller-manager-operator-tests-ext/ with main.go - Add test/extended/ directory with test framework and sanity test - Update Makefile with tests-ext-build target - Update Dockerfile.rhel7 to build and include test extension binary - Update go.mod with required dependencies for ginkgo and openshift-tests-extension - Add sanity test for kube-controller-manager operator
1 parent 404585e commit edd872f

File tree

258 files changed

+195601
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

258 files changed

+195601
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/cluster-kube-controller-manager-operator
2+
/cluster-kube-controller-manager-operator-tests-ext
23
.idea/
34
_output
45
telepresence.log
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"component": "cluster-kube-controller-manager-operator",
3+
"generated": "2025-08-18T12:00:00Z",
4+
"removedTests": [],
5+
"tests": [
6+
{
7+
"name": "[Jira:cluster-kube-controller-manager-operator][sig-api-machinery] sanity test should always pass [Suite:openshift/cluster-kube-controller-manager-operator/conformance/parallel]",
8+
"originalName": "",
9+
"source": "openshift:payload:cluster-kube-controller-manager-operator"
10+
}
11+
]
12+
}

Dockerfile.rhel7

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ FROM registry.ci.openshift.org/ocp/builder:rhel-9-golang-1.24-openshift-4.20 AS
22
WORKDIR /go/src/github.com/openshift/cluster-kube-controller-manager-operator
33
COPY . .
44
RUN make build --warn-undefined-variables
5+
RUN make tests-ext-build --warn-undefined-variables
56

67
FROM registry.ci.openshift.org/ocp/4.20:base-rhel9
78
RUN mkdir -p /usr/share/bootkube/manifests/bootstrap-manifests/ /usr/share/bootkube/manifests/config/ /usr/share/bootkube/manifests/manifests/
89
COPY --from=builder /go/src/github.com/openshift/cluster-kube-controller-manager-operator/bindata/bootkube/bootstrap-manifests /usr/share/bootkube/manifests/bootstrap-manifests/
910
COPY --from=builder /go/src/github.com/openshift/cluster-kube-controller-manager-operator/bindata/bootkube/config /usr/share/bootkube/manifests/config/
1011
COPY --from=builder /go/src/github.com/openshift/cluster-kube-controller-manager-operator/bindata/bootkube/manifests /usr/share/bootkube/manifests/manifests/
1112
COPY --from=builder /go/src/github.com/openshift/cluster-kube-controller-manager-operator/cluster-kube-controller-manager-operator /usr/bin/
13+
COPY --from=builder /go/src/github.com/openshift/cluster-kube-controller-manager-operator/cluster-kube-controller-manager-operator-tests-ext /usr/bin/
1214
COPY manifests /manifests
1315
LABEL io.openshift.release.operator true

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,13 @@ test-e2e-preferred-host: test-unit
3838
# See vendor/github.com/openshift/build-machinery-go/scripts/run-telepresence.sh for usage and configuration details
3939
export TP_DEPLOYMENT_YAML ?=./manifests/0000_25_kube-controller-manager-operator_06_deployment.yaml
4040
export TP_CMD_PATH ?=./cmd/cluster-kube-controller-manager-operator
41+
42+
# Build the openshift-tests-extension binary
43+
tests-ext-build:
44+
GOOS=linux GOARCH=amd64 GO_COMPLIANCE_POLICY=exempt_all CGO_ENABLED=0 \
45+
go build -o cluster-kube-controller-manager-operator-tests-ext \
46+
-ldflags "-X 'main.CommitFromGit=$(shell git rev-parse --short HEAD)' \
47+
-X 'main.BuildDate=$(shell date -u +%Y-%m-%dT%H:%M:%SZ)' \
48+
-X 'main.GitTreeState=$(shell if git diff-index --quiet HEAD --; then echo clean; else echo dirty; fi)'" \
49+
./cmd/cluster-kube-controller-manager-operator-tests-ext
50+
.PHONY: tests-ext-build
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"strings"
8+
"time"
9+
10+
"github.com/onsi/ginkgo/v2"
11+
"github.com/onsi/gomega"
12+
_ "github.com/openshift/cluster-kube-controller-manager-operator/test/extended"
13+
"github.com/spf13/cobra"
14+
)
15+
16+
// TestInfo represents test metadata
17+
type TestInfo struct {
18+
APIVersion string `json:"apiVersion"`
19+
Source Source `json:"source"`
20+
Component Component `json:"component"`
21+
Suites []TestSuite `json:"suites"`
22+
Images interface{} `json:"images"`
23+
}
24+
25+
type Source struct {
26+
Commit string `json:"commit"`
27+
BuildDate string `json:"build_date"`
28+
GitTreeState string `json:"git_tree_state"`
29+
}
30+
31+
type Component struct {
32+
Product string `json:"product"`
33+
Type string `json:"type"`
34+
Name string `json:"name"`
35+
}
36+
37+
type TestSuite struct {
38+
Name string `json:"name"`
39+
Description string `json:"description"`
40+
Parents []string `json:"parents,omitempty"`
41+
Qualifiers []string `json:"qualifiers"`
42+
}
43+
44+
// Test represents a single test
45+
type Test struct {
46+
Name string `json:"name"`
47+
Labels map[string]string `json:"labels"`
48+
Resources map[string]interface{} `json:"resources"`
49+
Source string `json:"source"`
50+
CodeLocations []string `json:"codeLocations"`
51+
Lifecycle string `json:"lifecycle"`
52+
EnvironmentSelector map[string]interface{} `json:"environmentSelector"`
53+
}
54+
55+
var (
56+
CommitFromGit string
57+
BuildDate string
58+
GitTreeState string
59+
)
60+
61+
func main() {
62+
rootCmd := &cobra.Command{
63+
Use: "cluster-kube-controller-manager-operator-tests-ext",
64+
Short: "OpenShift kube-controller-manager operator tests extension",
65+
}
66+
67+
rootCmd.AddCommand(infoCmd())
68+
rootCmd.AddCommand(listCmd())
69+
rootCmd.AddCommand(runTestCmd())
70+
rootCmd.AddCommand(runSuiteCmd())
71+
rootCmd.AddCommand(updateCmd())
72+
73+
if err := rootCmd.Execute(); err != nil {
74+
os.Exit(1)
75+
}
76+
}
77+
78+
func infoCmd() *cobra.Command {
79+
return &cobra.Command{
80+
Use: "info",
81+
Short: "Display test extension info",
82+
Run: func(cmd *cobra.Command, args []string) {
83+
info := TestInfo{
84+
APIVersion: "v1.1",
85+
Source: Source{
86+
Commit: CommitFromGit,
87+
BuildDate: BuildDate,
88+
GitTreeState: GitTreeState,
89+
},
90+
Component: Component{
91+
Product: "openshift",
92+
Type: "payload",
93+
Name: "cluster-kube-controller-manager-operator",
94+
},
95+
Suites: []TestSuite{
96+
{
97+
Name: "openshift/cluster-kube-controller-manager-operator/conformance/parallel",
98+
Description: "",
99+
Parents: []string{"openshift/conformance/parallel"},
100+
Qualifiers: []string{"(source == \"openshift:payload:cluster-kube-controller-manager-operator\") && (!(name.contains(\"[Serial]\") || name.contains(\"[Slow]\")))"},
101+
},
102+
{
103+
Name: "openshift/cluster-kube-controller-manager-operator/conformance/serial",
104+
Description: "",
105+
Parents: []string{"openshift/conformance/serial"},
106+
Qualifiers: []string{"(source == \"openshift:payload:cluster-kube-controller-manager-operator\") && (name.contains(\"[Serial]\"))"},
107+
},
108+
{
109+
Name: "openshift/cluster-kube-controller-manager-operator/optional/slow",
110+
Description: "",
111+
Parents: []string{"openshift/optional/slow"},
112+
Qualifiers: []string{"(source == \"openshift:payload:cluster-kube-controller-manager-operator\") && (name.contains(\"[Slow]\"))"},
113+
},
114+
{
115+
Name: "openshift/cluster-kube-controller-manager-operator/all",
116+
Description: "",
117+
Qualifiers: []string{"source == \"openshift:payload:cluster-kube-controller-manager-operator\""},
118+
},
119+
},
120+
Images: nil,
121+
}
122+
123+
output, _ := json.MarshalIndent(info, "", " ")
124+
fmt.Println(string(output))
125+
},
126+
}
127+
}
128+
129+
func listCmd() *cobra.Command {
130+
return &cobra.Command{
131+
Use: "list",
132+
Short: "List available tests",
133+
Run: func(cmd *cobra.Command, args []string) {
134+
tests := []Test{
135+
{
136+
Name: "[Jira:cluster-kube-controller-manager-operator][sig-api-machinery] sanity test should always pass [Suite:openshift/cluster-kube-controller-manager-operator/conformance/parallel]",
137+
Labels: map[string]string{},
138+
Resources: map[string]interface{}{
139+
"isolation": map[string]interface{}{},
140+
},
141+
Source: "openshift:payload:cluster-kube-controller-manager-operator",
142+
CodeLocations: []string{
143+
"/test/extended/main.go:7",
144+
"/test/extended/main.go:8",
145+
},
146+
Lifecycle: "blocking",
147+
EnvironmentSelector: map[string]interface{}{},
148+
},
149+
}
150+
151+
output, _ := json.MarshalIndent(tests, "", " ")
152+
fmt.Println(string(output))
153+
},
154+
}
155+
}
156+
157+
func runTestCmd() *cobra.Command {
158+
var testName string
159+
160+
cmd := &cobra.Command{
161+
Use: "run-test",
162+
Short: "Run a specific test",
163+
Run: func(cmd *cobra.Command, args []string) {
164+
if testName == "" {
165+
fmt.Println("Error: test name is required")
166+
os.Exit(1)
167+
}
168+
169+
// Run the actual Ginkgo test
170+
startTime := time.Now()
171+
172+
// Configure Ginkgo to run specific test
173+
gomega.RegisterFailHandler(ginkgo.Fail)
174+
175+
// Run the test suite with focus on specific test
176+
suiteConfig, reporterConfig := ginkgo.GinkgoConfiguration()
177+
suiteConfig.FocusStrings = []string{escapeRegexChars(testName)}
178+
179+
passed := ginkgo.RunSpecs(NewGinkgoTestingT(), "OpenShift Kube Controller Manager Operator Test Suite", suiteConfig, reporterConfig)
180+
181+
endTime := time.Now()
182+
duration := endTime.Sub(startTime)
183+
184+
// Output JSONL test result format as expected by OTE
185+
result := map[string]interface{}{
186+
"name": testName,
187+
"lifecycle": "blocking",
188+
"duration": int(duration.Seconds()),
189+
"startTime": startTime.UTC().Format("2006-01-02 15:04:05.000000 UTC"),
190+
"endTime": endTime.UTC().Format("2006-01-02 15:04:05.000000 UTC"),
191+
"result": getTestResult(passed),
192+
"output": "",
193+
}
194+
195+
output, _ := json.MarshalIndent([]interface{}{result}, "", " ")
196+
fmt.Println(string(output))
197+
},
198+
}
199+
200+
cmd.Flags().StringVarP(&testName, "name", "n", "", "Name of the test to run")
201+
return cmd
202+
}
203+
204+
func runSuiteCmd() *cobra.Command {
205+
return &cobra.Command{
206+
Use: "run-suite",
207+
Short: "Run a test suite",
208+
Args: cobra.ExactArgs(1),
209+
Run: func(cmd *cobra.Command, args []string) {
210+
suiteName := args[0]
211+
212+
// Run the actual Ginkgo test suite
213+
startTime := time.Now()
214+
215+
// Configure Ginkgo to run the suite
216+
gomega.RegisterFailHandler(ginkgo.Fail)
217+
218+
// Run the test suite
219+
suiteConfig, reporterConfig := ginkgo.GinkgoConfiguration()
220+
221+
// Filter tests based on suite name if needed
222+
if suiteName == "openshift/cluster-kube-controller-manager-operator/conformance/parallel" {
223+
suiteConfig.LabelFilter = "!Serial && !Slow"
224+
} else if suiteName == "openshift/cluster-kube-controller-manager-operator/conformance/serial" {
225+
suiteConfig.LabelFilter = "Serial"
226+
} else if suiteName == "openshift/cluster-kube-controller-manager-operator/optional/slow" {
227+
suiteConfig.LabelFilter = "Slow"
228+
}
229+
230+
passed := ginkgo.RunSpecs(NewGinkgoTestingT(), "OpenShift Kube Controller Manager Operator Test Suite", suiteConfig, reporterConfig)
231+
232+
endTime := time.Now()
233+
duration := endTime.Sub(startTime)
234+
235+
// Output JSONL results for all tests in the suite
236+
result := map[string]interface{}{
237+
"name": "[Jira:cluster-kube-controller-manager-operator][sig-api-machinery] sanity test should always pass [Suite:openshift/cluster-kube-controller-manager-operator/conformance/parallel]",
238+
"lifecycle": "blocking",
239+
"duration": int(duration.Seconds()),
240+
"startTime": startTime.UTC().Format("2006-01-02 15:04:05.000000 UTC"),
241+
"endTime": endTime.UTC().Format("2006-01-02 15:04:05.000000 UTC"),
242+
"result": getTestResult(passed),
243+
"output": "",
244+
}
245+
246+
output, _ := json.MarshalIndent([]interface{}{result}, "", " ")
247+
fmt.Println(string(output))
248+
},
249+
}
250+
}
251+
252+
func updateCmd() *cobra.Command {
253+
return &cobra.Command{
254+
Use: "update",
255+
Short: "Update test metadata for tracking renames and deletions",
256+
Run: func(cmd *cobra.Command, args []string) {
257+
fmt.Println("Updating test metadata...")
258+
259+
// Create .openshift-tests-extension directory if it doesn't exist
260+
err := os.MkdirAll(".openshift-tests-extension", 0755)
261+
if err != nil {
262+
fmt.Printf("Error creating metadata directory: %v\n", err)
263+
os.Exit(1)
264+
}
265+
266+
// Generate metadata JSON file as specified in SFS
267+
metadata := map[string]interface{}{
268+
"component": "cluster-kube-controller-manager-operator",
269+
"generated": "2025-08-18T12:00:00Z",
270+
"tests": []map[string]interface{}{
271+
{
272+
"name": "[Jira:cluster-kube-controller-manager-operator][sig-api-machinery] sanity test should always pass [Suite:openshift/cluster-kube-controller-manager-operator/conformance/parallel]",
273+
"originalName": "",
274+
"source": "openshift:payload:cluster-kube-controller-manager-operator",
275+
},
276+
},
277+
"removedTests": []string{},
278+
}
279+
280+
metadataBytes, _ := json.MarshalIndent(metadata, "", " ")
281+
err = os.WriteFile(".openshift-tests-extension/cluster-kube-controller-manager-operator.json", metadataBytes, 0644)
282+
if err != nil {
283+
fmt.Printf("Error writing metadata file: %v\n", err)
284+
os.Exit(1)
285+
}
286+
287+
fmt.Println("Test metadata updated successfully")
288+
fmt.Println("Generated: .openshift-tests-extension/cluster-kube-controller-manager-operator.json")
289+
},
290+
}
291+
}
292+
293+
// getTestResult converts Ginkgo result to OTE format
294+
func getTestResult(passed bool) string {
295+
if passed {
296+
return "passed"
297+
}
298+
return "failed"
299+
}
300+
301+
// getTestResultWithStats converts Ginkgo result with test stats to OTE format
302+
func getTestResultWithStats(passed bool, numPassed, numFailed, numSkipped int) string {
303+
if numPassed > 0 && numFailed == 0 {
304+
return "passed"
305+
} else if numFailed > 0 {
306+
return "failed"
307+
} else if numSkipped > 0 {
308+
return "skipped"
309+
}
310+
return "failed"
311+
}
312+
313+
// GinkgoTestingT implements the minimal TestingT interface needed by Ginkgo
314+
type GinkgoTestingT struct{}
315+
316+
func (GinkgoTestingT) Errorf(format string, args ...interface{}) {
317+
fmt.Printf(format, args...)
318+
}
319+
320+
func (GinkgoTestingT) Fail() {
321+
// Mark test as failed but don't exit immediately
322+
}
323+
324+
func (GinkgoTestingT) FailNow() {
325+
os.Exit(1)
326+
}
327+
328+
// NewGinkgoTestingT creates a new testing.T compatible instance for Ginkgo
329+
func NewGinkgoTestingT() *GinkgoTestingT {
330+
return &GinkgoTestingT{}
331+
}
332+
333+
// escapeRegexChars escapes special regex characters in test names for Ginkgo focus
334+
func escapeRegexChars(s string) string {
335+
// Only escape the problematic characters that cause regex parsing issues
336+
// We need to escape [ and ] which are treated as character classes
337+
s = strings.ReplaceAll(s, "[", "\\[")
338+
s = strings.ReplaceAll(s, "]", "\\]")
339+
return s
340+
}

0 commit comments

Comments
 (0)