Skip to content

Commit 3fba3f1

Browse files
committed
MGMT-24397: Add OCP test version builder & PoC
Add TestVersionBuilder for resolving test versions from data files instead of hardcoding them. These helpers let tests reference versions dynamically so they adapt when data files change via make generate.
1 parent babc11d commit 3fba3f1

12 files changed

Lines changed: 584 additions & 45 deletions

File tree

data/default_os_images.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,4 @@
281281
"url": "https://mirror.openshift.com/pub/openshift-v4/s390x/dependencies/rhcos/pre-release/4.22.0-ec.5/rhcos-4.22.0-ec.5-s390x-live-iso.s390x.iso",
282282
"version": "9.6.20251023-0"
283283
}
284-
]
284+
]

data/default_release_images.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,4 +363,4 @@
363363
"support_level": "beta",
364364
"version": "5.0.0-ec.1-multi"
365365
}
366-
]
366+
]

hack/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ generate-events:
3838
validate-swagger-file:
3939
./hack/generate.sh validate_swagger_file
4040

41+
generate-test-versions:
42+
./hack/generate.sh generate_test_versions
43+
4144
generate-configuration:
4245
./hack/generate.sh generate_configuration
4346

@@ -61,4 +64,4 @@ generate-go:
6164
# because the latter copies around files that need to be generated by the
6265
# former. Without doing it in this order, the `generate` target will not be
6366
# idempotent and would have to be executed twice to achieve the desired result.
64-
generate: generate-from-swagger generate-go generate-events generate-mocks generate-configuration generate-bundle
67+
generate: generate-from-swagger generate-go generate-events generate-mocks generate-configuration generate-test-versions generate-bundle

hack/generate.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,44 @@ function generate_bundle() {
125125
operator-sdk bundle validate ${BUNDLE_OUTPUT_DIR}
126126
}
127127

128+
function generate_test_versions() {
129+
local data_file="${__root}/data/default_release_images.json"
130+
local output_file="${__root}/internal/common/test_versions_generated.go"
131+
132+
python3 -c '
133+
import json, re
134+
from collections import defaultdict
135+
136+
with open("'"${data_file}"'") as f:
137+
data = json.load(f)
138+
139+
arch_versions = defaultdict(set)
140+
for entry in data:
141+
version = re.sub(r"-multi$", "", entry["openshift_version"])
142+
parts = version.split(".")
143+
version = "%s.%s" % (parts[0], parts[1])
144+
arch_versions[entry["cpu_architecture"]].add(version)
145+
146+
def sort_key(v):
147+
return tuple(int(p) for p in v.split(".") if p.isdigit())
148+
149+
lines = []
150+
for arch in sorted(arch_versions):
151+
versions = sorted(arch_versions[arch], key=sort_key)
152+
quoted = ", ".join("\"%s\"" % v for v in versions)
153+
lines.append("\t\"%s\": {%s}," % (arch, quoted))
154+
155+
print("""// Code generated by hack/generate.sh generate_test_versions; DO NOT EDIT.
156+
package common
157+
158+
var testVersionsByArch = map[string][]string{
159+
%s
160+
}""" % "\n".join(lines))
161+
' > "$output_file"
162+
163+
gofmt -w "$output_file"
164+
}
165+
128166
function print_help() {
129167
echo "The available functions are:"
130168
compgen -A function | grep "^generate" | awk '{print "\t" $1}'

internal/bminventory/inventory_test.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5209,6 +5209,17 @@ var _ = Describe("cluster", func() {
52095209
})
52105210

52115211
Context("Multiple VIPs forbidden in update for pre-4.12", func() {
5212+
var pre412Version string
5213+
5214+
BeforeEach(func() {
5215+
v, ok := common.TestVersion().LessThan("4.12").Latest().TryVersion()
5216+
if !ok {
5217+
Skip("no test version available below 4.12")
5218+
}
5219+
pre412Version = v
5220+
Expect(db.Model(&common.Cluster{}).Where("id = ?", clusterID).Update("openshift_version", pre412Version).Error).ShouldNot(HaveOccurred())
5221+
})
5222+
52125223
It("2 APIVips and 2 IngressVips", func() {
52135224
apiVip := "8.8.8.7"
52145225
ingressVip := "8.8.8.1"
@@ -5223,7 +5234,7 @@ var _ = Describe("cluster", func() {
52235234
},
52245235
})
52255236

5226-
verifyApiErrorString(reply, http.StatusBadRequest, "dual-stack VIPs are not supported in OpenShift 4.6")
5237+
verifyApiErrorString(reply, http.StatusBadRequest, "dual-stack VIPs are not supported in OpenShift "+pre412Version)
52275238
})
52285239

52295240
It("2 APIVips and 1 IngressVips", func() {
@@ -5240,7 +5251,7 @@ var _ = Describe("cluster", func() {
52405251
},
52415252
})
52425253

5243-
verifyApiErrorString(reply, http.StatusBadRequest, "dual-stack VIPs are not supported in OpenShift 4.6")
5254+
verifyApiErrorString(reply, http.StatusBadRequest, "dual-stack VIPs are not supported in OpenShift "+pre412Version)
52445255
})
52455256

52465257
It("1 APIVip and 2 IngressVips", func() {
@@ -5257,7 +5268,7 @@ var _ = Describe("cluster", func() {
52575268
},
52585269
})
52595270

5260-
verifyApiErrorString(reply, http.StatusBadRequest, "dual-stack VIPs are not supported in OpenShift 4.6")
5271+
verifyApiErrorString(reply, http.StatusBadRequest, "dual-stack VIPs are not supported in OpenShift "+pre412Version)
52615272
})
52625273
})
52635274
})
@@ -5355,6 +5366,7 @@ var _ = Describe("cluster", func() {
53555366
ID: &clusterID,
53565367
APIVips: []*models.APIVip{{IP: "10.11.12.13"}},
53575368
IngressVips: []*models.IngressVip{{IP: "10.11.20.50"}},
5369+
CPUArchitecture: common.DefaultCPUArchitecture,
53585370
OpenshiftVersion: common.TestDefaultConfig.OpenShiftVersion,
53595371
Status: swag.String(models.ClusterStatusReady),
53605372
}}
@@ -5363,6 +5375,7 @@ var _ = Describe("cluster", func() {
53635375
ID: &clusterID,
53645376
APIVips: []*models.APIVip{{IP: "10.11.12.13"}},
53655377
IngressVips: []*models.IngressVip{{IP: "10.11.20.50"}},
5378+
CPUArchitecture: common.DefaultCPUArchitecture,
53665379
OpenshiftVersion: common.TestDefaultConfig.OpenShiftVersion,
53675380
Status: swag.String(models.ClusterStatusInstalling),
53685381
},
@@ -15102,8 +15115,8 @@ var _ = Describe("RegisterCluster", func() {
1510215115
Expect(result.Platform.None).Should(BeNil())
1510315116
Expect(result.Platform.Baremetal).Should(BeNil())
1510415117

15105-
Expect(result.Platform.Vsphere.DeprecatedAPIVIP).Should(Equal(apiVip))
15106-
Expect(result.Platform.Vsphere.DeprecatedIngressVIP).Should(Equal(ingressVip))
15118+
Expect(result.Platform.Vsphere.APIVIPs).Should(ContainElement(apiVip))
15119+
Expect(result.Platform.Vsphere.IngressVIPs).Should(ContainElement(ingressVip))
1510715120
})
1510815121
})
1510915122

@@ -17815,6 +17828,7 @@ var _ = Describe("AMS subscriptions", func() {
1781517828
err := db.Create(&common.Cluster{Cluster: models.Cluster{
1781617829
ID: &clusterID,
1781717830
OpenshiftVersion: common.TestDefaultConfig.OpenShiftVersion,
17831+
CPUArchitecture: common.DefaultCPUArchitecture,
1781817832
Status: swag.String(models.ClusterStatusReady),
1781917833
}}).Error
1782017834
Expect(err).ShouldNot(HaveOccurred())

internal/common/test_configuration.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ const TestDiskPath = "/dev/test-disk"
5252
const MinimalVersionForNmstatectl = "4.18"
5353

5454
var (
55-
OpenShiftVersion string = "4.6"
56-
ReleaseVersion = "4.6.0"
57-
ReleaseImageURL = "quay.io/openshift-release-dev/ocp-release:4.6.16-x86_64"
58-
RhcosImage = "rhcos_4.6.0"
59-
RhcosVersion = "version-46.123-0"
60-
SupportLevel = "beta"
61-
CPUArchitecture = DefaultCPUArchitecture
55+
DefaultTestVersion = TestVersion().Latest()
56+
OpenShiftVersion = DefaultTestVersion.Version()
57+
ReleaseVersion = DefaultTestVersion.ReleaseVersion()
58+
ReleaseImageURL = DefaultTestVersion.ReleaseImageURL()
59+
RhcosImage = DefaultTestVersion.RhcosImage()
60+
RhcosVersion = DefaultTestVersion.RhcosVersion()
61+
SupportLevel = "beta"
62+
CPUArchitecture = DefaultCPUArchitecture
6263
)
6364

6465
// Defaults to be used by all testing modules

internal/common/test_versions.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/hashicorp/go-version"
8+
)
9+
10+
type TestVersionBuilder struct {
11+
arch string
12+
oldest bool
13+
constraint func(string) bool
14+
versionsByArch map[string][]string
15+
}
16+
17+
func TestVersion() *TestVersionBuilder {
18+
return &TestVersionBuilder{
19+
arch: DefaultCPUArchitecture,
20+
versionsByArch: testVersionsByArch,
21+
}
22+
}
23+
24+
func (b *TestVersionBuilder) ForArch(arch string) *TestVersionBuilder {
25+
b.arch = arch
26+
return b
27+
}
28+
29+
func (b *TestVersionBuilder) Latest() *TestVersionBuilder {
30+
b.oldest = false
31+
return b
32+
}
33+
34+
func (b *TestVersionBuilder) Oldest() *TestVersionBuilder {
35+
b.oldest = true
36+
return b
37+
}
38+
39+
func (b *TestVersionBuilder) LessThan(threshold string) *TestVersionBuilder {
40+
parsed := b.parseVersion(threshold)
41+
b.constraint = func(v string) bool {
42+
return b.parseVersion(v).LessThan(parsed)
43+
}
44+
return b
45+
}
46+
47+
func (b *TestVersionBuilder) GreaterThan(threshold string) *TestVersionBuilder {
48+
parsed := b.parseVersion(threshold)
49+
b.constraint = func(v string) bool {
50+
return b.parseVersion(v).GreaterThan(parsed)
51+
}
52+
return b
53+
}
54+
55+
func (b *TestVersionBuilder) Exact(target string) *TestVersionBuilder {
56+
parsed := b.parseVersion(target)
57+
b.constraint = func(v string) bool {
58+
return b.parseVersion(v).Equal(parsed)
59+
}
60+
return b
61+
}
62+
63+
func (b *TestVersionBuilder) TryVersion() (string, bool) {
64+
v := b.versions()
65+
if len(v) == 0 {
66+
return "", false
67+
}
68+
if b.oldest {
69+
return v[0], true
70+
}
71+
return v[len(v)-1], true
72+
}
73+
74+
func (b *TestVersionBuilder) Version() string {
75+
v, ok := b.TryVersion()
76+
if !ok {
77+
panic(fmt.Sprintf("no test version found for arch %q with active constraint", b.arch))
78+
}
79+
return v
80+
}
81+
82+
func (b *TestVersionBuilder) ReleaseVersion() string {
83+
return b.Version() + ".0"
84+
}
85+
86+
// Mirrors getReleaseImageReference in internal/releasesources/release_sources.go
87+
func (b *TestVersionBuilder) ReleaseImageURL() string {
88+
suffix := b.arch
89+
if suffix == ARM64CPUArchitecture {
90+
suffix = AARCH64CPUArchitecture
91+
}
92+
return fmt.Sprintf("quay.io/openshift-release-dev/ocp-release:%s-%s", b.ReleaseVersion(), suffix)
93+
}
94+
95+
func (b *TestVersionBuilder) RhcosImage() string {
96+
return fmt.Sprintf("rhcos_%s", b.ReleaseVersion())
97+
}
98+
99+
func (b *TestVersionBuilder) RhcosVersion() string {
100+
return fmt.Sprintf("version-%s.123-0", strings.ReplaceAll(b.Version(), ".", ""))
101+
}
102+
103+
func (b *TestVersionBuilder) versions() []string {
104+
all, ok := testVersionsByArch[b.arch]
105+
if !ok {
106+
return []string{}
107+
}
108+
if b.constraint == nil || len(all) == 0 {
109+
return all
110+
}
111+
var filtered []string
112+
for _, v := range all {
113+
if b.constraint(v) {
114+
filtered = append(filtered, v)
115+
}
116+
}
117+
return filtered
118+
}
119+
120+
func (b *TestVersionBuilder) parseVersion(v string) *version.Version {
121+
parsed, err := version.NewVersion(v)
122+
if err != nil {
123+
panic(fmt.Sprintf("invalid version %q: %v", v, err))
124+
}
125+
return parsed
126+
}

internal/common/test_versions_generated.go

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

0 commit comments

Comments
 (0)