Skip to content

Commit cc313a4

Browse files
Merge pull request #31579 from redhat-chai-bot/ocpbugs-115153-extension-architectures
OCPBUGS-115153: Make extension test-binary extraction architecture-aware
2 parents 589a3d5 + 52b1048 commit cc313a4

2 files changed

Lines changed: 156 additions & 17 deletions

File tree

pkg/test/extensions/binary.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"path"
1212
"path/filepath"
1313
"regexp"
14+
"runtime"
1415
"strings"
1516
"sync"
1617
"syscall"
@@ -166,6 +167,8 @@ type TestBinary struct {
166167
imageTag string
167168
// The binary path to extract from the image
168169
binaryPath string
170+
// The architectures where the binary is available. An empty list means all architectures.
171+
architectures []string
169172

170173
// Cache the info after gathering it
171174
info *Extension
@@ -342,8 +345,9 @@ var extensionBinaries = []TestBinary{
342345
binaryPath: "/usr/bin/service-ca-operator-tests-ext.gz",
343346
},
344347
{
345-
imageTag: "vsphere-csi-driver-operator",
346-
binaryPath: "/usr/bin/vmware-vsphere-csi-driver-operator-tests-ext.gz",
348+
imageTag: "vsphere-csi-driver-operator",
349+
binaryPath: "/usr/bin/vmware-vsphere-csi-driver-operator-tests-ext.gz",
350+
architectures: []string{"amd64"},
347351
},
348352
}
349353

@@ -640,6 +644,7 @@ func ExtractAllTestBinaries(ctx context.Context, parallelism int) (func(), TestB
640644

641645
// Filter extension binaries based on environment variables
642646
filteredBinaries := filterExtensionBinariesByTags(extensionBinaries)
647+
filteredBinaries = filterExtensionBinariesByArchitecture(filteredBinaries, extensionBinaryArchitecture(runtime.GOARCH))
643648

644649
releaseImage, err := DetermineReleasePayloadImage()
645650
if err != nil {
@@ -1064,6 +1069,36 @@ func filterExtensionBinariesByTags(binaries []TestBinary) []TestBinary {
10641069
return filtered
10651070
}
10661071

1072+
// filterExtensionBinariesByArchitecture returns binaries available on architecture. Binaries
1073+
// without an architecture allowlist are available on all architectures.
1074+
func filterExtensionBinariesByArchitecture(binaries []TestBinary, architecture string) []TestBinary {
1075+
filtered := make([]TestBinary, 0, len(binaries))
1076+
for _, binary := range binaries {
1077+
if len(binary.architectures) == 0 {
1078+
filtered = append(filtered, binary)
1079+
continue
1080+
}
1081+
for _, supportedArchitecture := range binary.architectures {
1082+
if architecture == supportedArchitecture {
1083+
filtered = append(filtered, binary)
1084+
break
1085+
}
1086+
}
1087+
}
1088+
return filtered
1089+
}
1090+
1091+
// extensionBinaryArchitecture returns the target architecture used to select payload extension
1092+
// binaries. Multi-architecture CI may run a cross-compiled openshift-tests binary, so OCP_ARCH
1093+
// takes precedence over the executable's architecture when it is available. Native and legacy
1094+
// invocations fall back to the supplied runtime architecture.
1095+
func extensionBinaryArchitecture(runtimeArchitecture string) string {
1096+
if architecture := os.Getenv("OCP_ARCH"); len(architecture) > 0 {
1097+
return architecture
1098+
}
1099+
return runtimeArchitecture
1100+
}
1101+
10671102
// filterToApplicableEnvironmentFlags filters the provided envFlags to only those that are applicable to the
10681103
// APIVersion of OTE within the external binary.
10691104
func (b *TestBinary) filterToApplicableEnvironmentFlags(envFlags EnvironmentFlags) EnvironmentFlags {

pkg/test/extensions/binary_filter_test.go

Lines changed: 119 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package extensions
22

33
import (
44
"os"
5+
"runtime"
56
"testing"
67

78
"github.com/stretchr/testify/assert"
@@ -97,18 +98,8 @@ func TestFilterExtensionBinariesByTags(t *testing.T) {
9798

9899
for _, tt := range tests {
99100
t.Run(tt.name, func(t *testing.T) {
100-
// Set environment variables
101-
if tt.excludeTags != "" {
102-
os.Setenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS", tt.excludeTags)
103-
} else {
104-
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS")
105-
}
106-
107-
if tt.includeTags != "" {
108-
os.Setenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS", tt.includeTags)
109-
} else {
110-
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS")
111-
}
101+
t.Setenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS", tt.excludeTags)
102+
t.Setenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS", tt.includeTags)
112103

113104
// Call the function
114105
result := filterExtensionBinariesByTags(testBinaries)
@@ -123,10 +114,123 @@ func TestFilterExtensionBinariesByTags(t *testing.T) {
123114
}
124115

125116
assert.ElementsMatch(t, tt.expectedImageTags, actualImageTags, "Expected image tags %v, got %v", tt.expectedImageTags, actualImageTags)
117+
})
118+
}
119+
}
120+
121+
func TestExtensionBinaryArchitecture(t *testing.T) {
122+
tests := []struct {
123+
name string
124+
setOCPArchitecture bool
125+
ocpArchitecture string
126+
runtimeArchitecture string
127+
wantArchitecture string
128+
}{
129+
{
130+
name: "arm64 target overrides amd64 runtime",
131+
setOCPArchitecture: true,
132+
ocpArchitecture: "arm64",
133+
runtimeArchitecture: "amd64",
134+
wantArchitecture: "arm64",
135+
},
136+
{
137+
name: "amd64 target is honored",
138+
setOCPArchitecture: true,
139+
ocpArchitecture: "amd64",
140+
runtimeArchitecture: "arm64",
141+
wantArchitecture: "amd64",
142+
},
143+
{
144+
name: "unset target uses runtime architecture",
145+
runtimeArchitecture: runtime.GOARCH,
146+
wantArchitecture: runtime.GOARCH,
147+
},
148+
}
149+
150+
for _, tt := range tests {
151+
t.Run(tt.name, func(t *testing.T) {
152+
t.Setenv("OCP_ARCH", tt.ocpArchitecture)
153+
if !tt.setOCPArchitecture {
154+
assert.NoError(t, os.Unsetenv("OCP_ARCH"))
155+
}
156+
157+
assert.Equal(t, tt.wantArchitecture, extensionBinaryArchitecture(tt.runtimeArchitecture))
158+
})
159+
}
160+
}
161+
162+
func TestFilterExtensionBinariesByArchitecture(t *testing.T) {
163+
tests := []struct {
164+
name string
165+
architectures []string
166+
architecture string
167+
wantIncluded bool
168+
}{
169+
{
170+
name: "empty allowlist is available on all architectures",
171+
architecture: "arm64",
172+
wantIncluded: true,
173+
},
174+
{
175+
name: "matching architecture is included",
176+
architectures: []string{"amd64", "arm64"},
177+
architecture: "arm64",
178+
wantIncluded: true,
179+
},
180+
{
181+
name: "non-matching architecture is omitted",
182+
architectures: []string{"amd64"},
183+
architecture: "arm64",
184+
wantIncluded: false,
185+
},
186+
}
187+
188+
for _, tt := range tests {
189+
t.Run(tt.name, func(t *testing.T) {
190+
binary := TestBinary{
191+
imageTag: "test-extension",
192+
binaryPath: "/usr/bin/test-extension",
193+
architectures: tt.architectures,
194+
}
195+
196+
filtered := filterExtensionBinariesByArchitecture([]TestBinary{binary}, tt.architecture)
197+
198+
assert.Equal(t, tt.wantIncluded, len(filtered) == 1)
199+
})
200+
}
201+
}
202+
203+
func TestVSphereExtensionBinaryArchitectures(t *testing.T) {
204+
tests := []struct {
205+
name string
206+
architecture string
207+
wantIncluded bool
208+
}{
209+
{
210+
name: "included on amd64",
211+
architecture: "amd64",
212+
wantIncluded: true,
213+
},
214+
{
215+
name: "omitted on arm64",
216+
architecture: "arm64",
217+
wantIncluded: false,
218+
},
219+
}
220+
221+
for _, tt := range tests {
222+
t.Run(tt.name, func(t *testing.T) {
223+
filtered := filterExtensionBinariesByArchitecture(extensionBinaries, tt.architecture)
224+
included := false
225+
for _, binary := range filtered {
226+
if binary.imageTag == "vsphere-csi-driver-operator" {
227+
included = true
228+
assert.Equal(t, []string{"amd64"}, binary.architectures)
229+
break
230+
}
231+
}
126232

127-
// Clean up environment variables
128-
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS")
129-
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS")
233+
assert.Equal(t, tt.wantIncluded, included)
130234
})
131235
}
132236
}

0 commit comments

Comments
 (0)