Skip to content

Commit b59120e

Browse files
jparrillclaude
andcommitted
test(integration): add boot image stream resolution tests for AWS
Add TestBootImageStreamResolution with AWS subtests covering the end-to-end flow from HostedCluster + NodePool + ReleaseImage through ResolveAWSAMI. Tests multi-stream payload resolution, user AMI override precedence, legacy 4.x backward compatibility, unsupported architecture and missing region error paths. Structured with t.Run("AWS", ...) so future providers (GCP, KubeVirt, etc.) are added as new subtests in CNTRLPLANE-3027. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Juan Manuel Parrilla Madrid <jparrill@redhat.com>
1 parent 1c3b0c9 commit b59120e

1 file changed

Lines changed: 121 additions & 0 deletions

File tree

test/integration/osstreams/osstreams_test.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ import (
88
"github.com/blang/semver"
99
. "github.com/onsi/gomega"
1010

11+
hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
1112
"github.com/openshift/hypershift/hypershift-operator/controllers/nodepool"
1213
"github.com/openshift/hypershift/support/releaseinfo"
1314
"github.com/openshift/hypershift/support/releaseinfo/fixtures"
15+
16+
imagev1 "github.com/openshift/api/image/v1"
17+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1418
)
1519

1620
func TestOSStreamsEndToEnd(t *testing.T) {
@@ -197,3 +201,120 @@ func TestOSStreamsLegacyPayloadBackwardCompat(t *testing.T) {
197201
g.Expect(err.Error()).To(ContainSubstring("no multi-stream metadata"))
198202
})
199203
}
204+
205+
// TestBootImageStreamResolution tests platform-specific boot image resolvers
206+
// with multi-stream metadata. Each platform has its own subtest block.
207+
// Adding a provider = adding a new t.Run block with platform-specific cases.
208+
func TestBootImageStreamResolution(t *testing.T) {
209+
g := NewWithT(t)
210+
211+
// Multi-stream payload (OCP 5.0+)
212+
defaultStream5, osStreams5, err := releaseinfo.DeserializeImageMetadata(fixtures.CoreOSBootImagesYAML_5_0)
213+
g.Expect(err).ToNot(HaveOccurred())
214+
multiStreamRelease := &releaseinfo.ReleaseImage{
215+
ImageStream: &imagev1.ImageStream{ObjectMeta: metav1.ObjectMeta{Name: "5.0.0"}},
216+
StreamMetadata: defaultStream5,
217+
OSStreams: osStreams5,
218+
}
219+
220+
// Legacy single-stream payload (OCP 4.10)
221+
defaultStream4, _, err := releaseinfo.DeserializeImageMetadata(fixtures.CoreOSBootImagesYAML_4_10)
222+
g.Expect(err).ToNot(HaveOccurred())
223+
legacyRelease := &releaseinfo.ReleaseImage{
224+
ImageStream: &imagev1.ImageStream{ObjectMeta: metav1.ObjectMeta{Name: "4.10.0"}},
225+
StreamMetadata: defaultStream4,
226+
}
227+
228+
t.Run("AWS", func(t *testing.T) {
229+
testCases := []struct {
230+
name string
231+
region string
232+
arch string
233+
amiOverride string
234+
releaseImage *releaseinfo.ReleaseImage
235+
expectedAMI string
236+
expectedErr bool
237+
}{
238+
// --- Happy paths ---
239+
{
240+
name: "When resolving amd64 AMI with multi-stream payload it should return default stream AMI",
241+
region: "us-east-1",
242+
arch: "amd64",
243+
releaseImage: multiStreamRelease,
244+
expectedAMI: "ami-06a6b025350ff1e23",
245+
},
246+
{
247+
name: "When resolving arm64 AMI with multi-stream payload it should return default stream AMI",
248+
region: "us-east-1",
249+
arch: "arm64",
250+
releaseImage: multiStreamRelease,
251+
expectedAMI: "ami-0e73a95fb409d8abd",
252+
},
253+
{
254+
name: "When NodePool has explicit AMI override it should return the override",
255+
region: "us-east-1",
256+
arch: "amd64",
257+
amiOverride: "ami-user-custom-override",
258+
releaseImage: multiStreamRelease,
259+
expectedAMI: "ami-user-custom-override",
260+
},
261+
{
262+
name: "When using legacy 4.x payload it should resolve from single-stream metadata",
263+
region: "us-east-1",
264+
arch: "amd64",
265+
releaseImage: legacyRelease,
266+
expectedAMI: "ami-0713d9bcf78401cd1",
267+
},
268+
// --- Sad paths ---
269+
{
270+
name: "When region has no AMI it should return error",
271+
region: "xx-nonexistent-1",
272+
arch: "amd64",
273+
releaseImage: multiStreamRelease,
274+
expectedErr: true,
275+
},
276+
{
277+
name: "When architecture has no ArchAliases mapping it should return error",
278+
region: "us-east-1",
279+
arch: "ppc64le",
280+
releaseImage: multiStreamRelease,
281+
expectedErr: true,
282+
},
283+
{
284+
name: "When stream metadata is nil it should return error",
285+
region: "us-east-1",
286+
arch: "amd64",
287+
releaseImage: &releaseinfo.ReleaseImage{ImageStream: &imagev1.ImageStream{ObjectMeta: metav1.ObjectMeta{Name: "5.0.0"}}},
288+
expectedErr: true,
289+
},
290+
}
291+
292+
for _, tc := range testCases {
293+
t.Run(tc.name, func(t *testing.T) {
294+
g := NewWithT(t)
295+
296+
hc := &hyperv1.HostedCluster{
297+
Spec: hyperv1.HostedClusterSpec{
298+
Platform: hyperv1.PlatformSpec{
299+
AWS: &hyperv1.AWSPlatformSpec{Region: tc.region},
300+
},
301+
},
302+
}
303+
np := &hyperv1.NodePool{
304+
Spec: hyperv1.NodePoolSpec{
305+
Arch: tc.arch,
306+
Platform: hyperv1.NodePoolPlatform{AWS: &hyperv1.AWSNodePoolPlatform{AMI: tc.amiOverride}},
307+
},
308+
}
309+
310+
ami, err := nodepool.ResolveAWSAMI(hc, np, tc.releaseImage)
311+
if tc.expectedErr {
312+
g.Expect(err).To(HaveOccurred())
313+
} else {
314+
g.Expect(err).ToNot(HaveOccurred())
315+
g.Expect(ami).To(Equal(tc.expectedAMI))
316+
}
317+
})
318+
}
319+
})
320+
}

0 commit comments

Comments
 (0)