@@ -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
1620func 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