@@ -207,6 +207,61 @@ func TestDesiredControlPlaneZVersion_ZStreamManagedUpgrade(t *testing.T) {
207207 expectedVersion : nil ,
208208 expectedError : false ,
209209 },
210+ {
211+ name : "Z-stream upgrade - candidate channel, customer desired full version (4.20.15) normalized to same minor" ,
212+ activeVersions : []api.HCPClusterActiveVersion {{Version : ptr .To (semver .MustParse ("4.20.10" ))}},
213+ customerDesiredMinor : "4.20.15" ,
214+ channelGroup : "candidate" ,
215+ mockSetup : func (mc * cincinatti.MockClient ) {
216+ mc .EXPECT ().GetUpdates (gomock .AssignableToTypeOf (context .Background ()), api .Must (cincinatti .GetCincinnatiURI ("candidate" )), "multi" , "multi" , "candidate-4.20" , semver .MustParse ("4.20.10" )).Return (
217+ configv1.Release {Version : "4.20.10" },
218+ []configv1.Release {{Version : "4.20.15" }, {Version : "4.20.12" }},
219+ []configv1.ConditionalUpdate {},
220+ nil ,
221+ )
222+ // Check if next minor (4.21) exists using latest candidate (4.20.15)
223+ mc .EXPECT ().GetUpdates (gomock .AssignableToTypeOf (context .Background ()), api .Must (cincinatti .GetCincinnatiURI ("candidate" )), "multi" , "multi" , "candidate-4.21" , semver .MustParse ("4.20.15" )).Return (
224+ configv1.Release {Version : "4.20.15" },
225+ []configv1.Release {{Version : "4.21.0" }},
226+ []configv1.ConditionalUpdate {},
227+ nil ,
228+ )
229+ // isGatewayToNextMinor(4.20.15) - has path to 4.21, so 4.20.15 is selected
230+ mc .EXPECT ().GetUpdates (gomock .AssignableToTypeOf (context .Background ()), api .Must (cincinatti .GetCincinnatiURI ("candidate" )), "multi" , "multi" , "candidate-4.21" , semver .MustParse ("4.20.15" )).Return (
231+ configv1.Release {Version : "4.20.15" },
232+ []configv1.Release {{Version : "4.21.0" }},
233+ []configv1.ConditionalUpdate {},
234+ nil ,
235+ )
236+ },
237+ expectedVersion : ptr .To (semver .MustParse ("4.20.15" )),
238+ expectedError : false ,
239+ },
240+ {
241+ name : "Z-stream upgrade - nightly channel, customer desired full version (4.19.0-0.nightly-multi-...) normalized to same minor" ,
242+ activeVersions : []api.HCPClusterActiveVersion {{Version : ptr .To (api .Must (semver .ParseTolerant ("4.19.0-0.nightly-multi-2026-01-10-204154" )))}},
243+ customerDesiredMinor : "4.19.0-0.nightly-multi-2026-01-12-061259" ,
244+ channelGroup : "nightly" ,
245+ mockSetup : func (mc * cincinatti.MockClient ) {
246+ activeVer := api .Must (semver .ParseTolerant ("4.19.0-0.nightly-multi-2026-01-10-204154" ))
247+ latestVer := api .Must (semver .ParseTolerant ("4.19.0-0.nightly-multi-2026-01-12-061259" ))
248+ mc .EXPECT ().GetUpdates (gomock .AssignableToTypeOf (context .Background ()), api .Must (cincinatti .GetCincinnatiURI ("nightly" )), "multi" , "multi" , "nightly-4.19" , activeVer ).Return (
249+ configv1.Release {Version : "4.19.0-0.nightly-multi-2026-01-10-204154" },
250+ []configv1.Release {{Version : "4.19.0-0.nightly-multi-2026-01-12-061259" }},
251+ []configv1.ConditionalUpdate {},
252+ nil ,
253+ )
254+ // Check if next minor (4.20) exists using latest candidate - it doesn't; return latest
255+ mc .EXPECT ().GetUpdates (gomock .AssignableToTypeOf (context .Background ()), api .Must (cincinatti .GetCincinnatiURI ("nightly" )), "multi" , "multi" , "nightly-4.20" , latestVer ).Return (
256+ configv1.Release {},
257+ nil ,
258+ nil ,
259+ & cincinnati.Error {Reason : "VersionNotFound" },
260+ )
261+ },
262+ expectedVersion : ptr .To (api .Must (semver .ParseTolerant ("4.19.0-0.nightly-multi-2026-01-12-061259" ))),
263+ expectedError : false ,
264+ },
210265 }
211266
212267 for _ , tt := range tests {
0 commit comments