99 autoscalingv2 "k8s.io/api/autoscaling/v2"
1010 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1111 "k8s.io/apimachinery/pkg/runtime"
12+ "k8s.io/utils/ptr"
1213)
1314
1415// helper: build a valid VariantAutoscaling object
@@ -31,7 +32,8 @@ func makeValidVA() *VariantAutoscaling {
3132 Kind : "Deployment" ,
3233 Name : "va-sample-deployment" ,
3334 },
34- ModelID : "model-123" ,
35+ ModelID : "model-123" ,
36+ MaxReplicas : 10 ,
3537 },
3638 Status : VariantAutoscalingStatus {
3739 // CurrentAlloc: Allocation{...} -- Removed
@@ -218,3 +220,144 @@ func jsonContainsKey(b []byte, key string) bool {
218220 _ , ok := m [key ]
219221 return ok
220222}
223+
224+ func TestMinMaxReplicasJSON (t * testing.T ) {
225+ minVal := int32 (2 )
226+ va := & VariantAutoscaling {
227+ ObjectMeta : metav1.ObjectMeta {Name : "va-replicas" , Namespace : "default" },
228+ Spec : VariantAutoscalingSpec {
229+ ScaleTargetRef : autoscalingv2.CrossVersionObjectReference {
230+ Kind : "Deployment" ,
231+ Name : "my-deploy" ,
232+ },
233+ ModelID : "model-x" ,
234+ MinReplicas : & minVal ,
235+ MaxReplicas : 5 ,
236+ },
237+ }
238+
239+ b , err := json .Marshal (va )
240+ if err != nil {
241+ t .Fatalf ("marshal failed: %v" , err )
242+ }
243+
244+ var probe struct {
245+ Spec struct {
246+ MinReplicas * int32 `json:"minReplicas"`
247+ MaxReplicas int32 `json:"maxReplicas"`
248+ } `json:"spec"`
249+ }
250+ if err := json .Unmarshal (b , & probe ); err != nil {
251+ t .Fatalf ("unmarshal failed: %v" , err )
252+ }
253+ if probe .Spec .MinReplicas == nil || * probe .Spec .MinReplicas != 2 {
254+ t .Errorf ("expected minReplicas=2, got %v" , probe .Spec .MinReplicas )
255+ }
256+ if probe .Spec .MaxReplicas != 5 {
257+ t .Errorf ("expected maxReplicas=5, got %d" , probe .Spec .MaxReplicas )
258+ }
259+
260+ // minReplicas must be absent from JSON when nil (omitempty)
261+ vaNoMin := & VariantAutoscaling {
262+ ObjectMeta : metav1.ObjectMeta {Name : "va-no-min" , Namespace : "default" },
263+ Spec : VariantAutoscalingSpec {
264+ ScaleTargetRef : autoscalingv2.CrossVersionObjectReference {
265+ Kind : "Deployment" ,
266+ Name : "my-deploy" ,
267+ },
268+ ModelID : "model-x" ,
269+ MaxReplicas : 5 ,
270+ },
271+ }
272+ b2 , err := json .Marshal (vaNoMin )
273+ if err != nil {
274+ t .Fatalf ("marshal failed: %v" , err )
275+ }
276+ var probeSpec struct {
277+ Spec map [string ]any `json:"spec"`
278+ }
279+ if err := json .Unmarshal (b2 , & probeSpec ); err != nil {
280+ t .Fatalf ("unmarshal failed: %v" , err )
281+ }
282+ if _ , ok := probeSpec .Spec ["minReplicas" ]; ok {
283+ t .Errorf ("expected minReplicas to be absent when nil, but it was present" )
284+ }
285+ }
286+
287+ func TestBehaviorOmitEmpty (t * testing.T ) {
288+ va := makeValidVA ()
289+ // behavior should be absent when nil
290+ b , err := json .Marshal (va )
291+ if err != nil {
292+ t .Fatalf ("marshal failed: %v" , err )
293+ }
294+ var probeSpec struct {
295+ Spec map [string ]any `json:"spec"`
296+ }
297+ if err := json .Unmarshal (b , & probeSpec ); err != nil {
298+ t .Fatalf ("unmarshal failed: %v" , err )
299+ }
300+ if _ , ok := probeSpec .Spec ["behavior" ]; ok {
301+ t .Errorf ("expected behavior to be absent when nil, but it was present" )
302+ }
303+ }
304+
305+ func TestBehaviorJSONRoundTrip (t * testing.T ) {
306+ va := makeValidVA ()
307+ va .Spec .Behavior = & autoscalingv2.HorizontalPodAutoscalerBehavior {
308+ ScaleUp : & autoscalingv2.HPAScalingRules {
309+ StabilizationWindowSeconds : ptr .To (int32 (0 )),
310+ Policies : []autoscalingv2.HPAScalingPolicy {
311+ {
312+ Type : autoscalingv2 .PodsScalingPolicy ,
313+ Value : 4 ,
314+ PeriodSeconds : 60 ,
315+ },
316+ },
317+ },
318+ ScaleDown : & autoscalingv2.HPAScalingRules {
319+ StabilizationWindowSeconds : ptr .To (int32 (300 )),
320+ Policies : []autoscalingv2.HPAScalingPolicy {
321+ {
322+ Type : autoscalingv2 .PercentScalingPolicy ,
323+ Value : 10 ,
324+ PeriodSeconds : 60 ,
325+ },
326+ },
327+ },
328+ }
329+
330+ b , err := json .Marshal (va )
331+ if err != nil {
332+ t .Fatalf ("marshal failed: %v" , err )
333+ }
334+
335+ var back VariantAutoscaling
336+ if err := json .Unmarshal (b , & back ); err != nil {
337+ t .Fatalf ("unmarshal failed: %v" , err )
338+ }
339+
340+ if back .Spec .Behavior == nil {
341+ t .Fatal ("expected behavior to be present after round-trip" )
342+ }
343+ if back .Spec .Behavior .ScaleUp == nil {
344+ t .Fatal ("expected scaleUp to be present after round-trip" )
345+ }
346+ if * back .Spec .Behavior .ScaleUp .StabilizationWindowSeconds != 0 {
347+ t .Errorf ("expected scaleUp.stabilizationWindowSeconds=0, got %d" ,
348+ * back .Spec .Behavior .ScaleUp .StabilizationWindowSeconds )
349+ }
350+ if len (back .Spec .Behavior .ScaleUp .Policies ) != 1 {
351+ t .Fatalf ("expected 1 scaleUp policy, got %d" , len (back .Spec .Behavior .ScaleUp .Policies ))
352+ }
353+ if back .Spec .Behavior .ScaleUp .Policies [0 ].Value != 4 {
354+ t .Errorf ("expected scaleUp policy value=4, got %d" , back .Spec .Behavior .ScaleUp .Policies [0 ].Value )
355+ }
356+ if back .Spec .Behavior .ScaleDown == nil {
357+ t .Fatal ("expected scaleDown to be present after round-trip" )
358+ }
359+ if * back .Spec .Behavior .ScaleDown .StabilizationWindowSeconds != 300 {
360+ t .Errorf ("expected scaleDown.stabilizationWindowSeconds=300, got %d" ,
361+ * back .Spec .Behavior .ScaleDown .StabilizationWindowSeconds )
362+ }
363+ }
0 commit comments