1+ /*
2+ Copyright 2024 The Aibrix Team.
3+
4+ Licensed under the Apache License, Version 2.0 (the "License");
5+ you may not use this file except in compliance with the License.
6+ You may obtain a copy of the License at
7+
8+ http://www.apache.org/licenses/LICENSE-2.0
9+
10+ Unless required by applicable law or agreed to in writing, software
11+ distributed under the License is distributed on an "AS IS" BASIS,
12+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ See the License for the specific language governing permissions and
14+ limitations under the License.
15+ */
16+
17+ package algorithm
18+
19+ import (
20+ "testing"
21+
22+ "github.com/vllm-project/aibrix/pkg/controller/podautoscaler/common"
23+ )
24+
25+ func TestApaScalingAlgorithm_ComputeTargetReplicas (t * testing.T ) {
26+ algorithm := & ApaScalingAlgorithm {}
27+
28+ tests := []struct {
29+ name string
30+ currentPodCount float64
31+ context * common.MockScalingContext
32+ expected int32
33+ description string
34+ }{
35+ {
36+ name : "no_scaling_within_tolerance" ,
37+ currentPodCount : 3.0 ,
38+ context : & common.MockScalingContext {
39+ TargetValue : 50.0 ,
40+ UpFluctuationTolerance : 0.1 , // 10% tolerance
41+ DownFluctuationTolerance : 0.2 , // 20% tolerance
42+ MaxScaleUpRate : 2.0 , // Can scale up by 100%
43+ MaxScaleDownRate : 2.0 , // Can scale down by 50%
44+ CurrentUsePerPod : 50.0 , // Exactly at target
45+ MinReplicas : 1 ,
46+ MaxReplicas : 10 ,
47+ },
48+ expected : 3 ,
49+ description : "Should not scale when current use per pod equals target value" ,
50+ },
51+ {
52+ name : "no_scaling_within_up_tolerance" ,
53+ currentPodCount : 3.0 ,
54+ context : & common.MockScalingContext {
55+ TargetValue : 50.0 ,
56+ UpFluctuationTolerance : 0.1 , // 10% tolerance
57+ DownFluctuationTolerance : 0.2 , // 20% tolerance
58+ MaxScaleUpRate : 2.0 ,
59+ MaxScaleDownRate : 2.0 ,
60+ CurrentUsePerPod : 54.0 , // 54/50 = 1.08, within 1+0.1=1.1 tolerance
61+ MinReplicas : 1 ,
62+ MaxReplicas : 10 ,
63+ },
64+ expected : 3 ,
65+ description : "Should not scale when within up tolerance (8% above target)" ,
66+ },
67+ {
68+ name : "no_scaling_within_down_tolerance" ,
69+ currentPodCount : 3.0 ,
70+ context : & common.MockScalingContext {
71+ TargetValue : 50.0 ,
72+ UpFluctuationTolerance : 0.1 , // 10% tolerance
73+ DownFluctuationTolerance : 0.2 , // 20% tolerance
74+ MaxScaleUpRate : 2.0 ,
75+ MaxScaleDownRate : 2.0 ,
76+ CurrentUsePerPod : 42.0 , // 42/50 = 0.84, within 1-0.2=0.8 tolerance
77+ MinReplicas : 1 ,
78+ MaxReplicas : 10 ,
79+ },
80+ expected : 3 ,
81+ description : "Should not scale when within down tolerance (16% below target)" ,
82+ },
83+ {
84+ name : "scale_up_beyond_tolerance" ,
85+ currentPodCount : 3.0 ,
86+ context : & common.MockScalingContext {
87+ TargetValue : 50.0 ,
88+ UpFluctuationTolerance : 0.1 , // 10% tolerance
89+ DownFluctuationTolerance : 0.2 , // 20% tolerance
90+ MaxScaleUpRate : 2.0 , // Can scale up by 100%
91+ MaxScaleDownRate : 2.0 ,
92+ CurrentUsePerPod : 60.0 , // 60/50 = 1.2, exceeds 1+0.1=1.1 tolerance
93+ MinReplicas : 1 ,
94+ MaxReplicas : 10 ,
95+ },
96+ expected : 4 , // ceil(3 * (60/50)) = ceil(3.6) = 4
97+ description : "Should scale up when current use exceeds up tolerance threshold" ,
98+ },
99+ {
100+ name : "scale_down_beyond_tolerance" ,
101+ currentPodCount : 5.0 ,
102+ context : & common.MockScalingContext {
103+ TargetValue : 50.0 ,
104+ UpFluctuationTolerance : 0.1 , // 10% tolerance
105+ DownFluctuationTolerance : 0.2 , // 20% tolerance
106+ MaxScaleUpRate : 2.0 ,
107+ MaxScaleDownRate : 2.0 , // Can scale down by 50%
108+ CurrentUsePerPod : 30.0 , // 30/50 = 0.6, below 1-0.2=0.8 tolerance
109+ MinReplicas : 1 ,
110+ MaxReplicas : 10 ,
111+ },
112+ expected : 3 , // ceil(5 * (30/50)) = ceil(3.0) = 3
113+ description : "Should scale down when current use falls below down tolerance threshold" ,
114+ },
115+ {
116+ name : "scale_up_limited_by_max_scale_up_rate" ,
117+ currentPodCount : 3.0 ,
118+ context : & common.MockScalingContext {
119+ TargetValue : 50.0 ,
120+ UpFluctuationTolerance : 0.1 , // 10% tolerance
121+ DownFluctuationTolerance : 0.2 , // 20% tolerance
122+ MaxScaleUpRate : 1.5 , // Can only scale up by 50%
123+ MaxScaleDownRate : 2.0 ,
124+ CurrentUsePerPod : 100.0 , // 100/50 = 2.0, would need 6 pods but limited
125+ MinReplicas : 1 ,
126+ MaxReplicas : 10 ,
127+ },
128+ expected : 5 , // ceil(1.5 * 3) = ceil(4.5) = 5 (limited by max scale up rate)
129+ description : "Should be limited by max scale up rate" ,
130+ },
131+ {
132+ name : "scale_down_limited_by_max_scale_down_rate" ,
133+ currentPodCount : 6.0 ,
134+ context : & common.MockScalingContext {
135+ TargetValue : 50.0 ,
136+ UpFluctuationTolerance : 0.1 , // 10% tolerance
137+ DownFluctuationTolerance : 0.2 , // 20% tolerance
138+ MaxScaleUpRate : 2.0 ,
139+ MaxScaleDownRate : 3.0 , // Can scale down to 1/3 = 33% of current (6/3=2 minimum)
140+ CurrentUsePerPod : 10.0 , // 10/50 = 0.2, would need 1.2 pods but limited
141+ MinReplicas : 1 ,
142+ MaxReplicas : 10 ,
143+ },
144+ expected : 2 , // floor(6/3) = floor(2) = 2
145+ description : "Should be limited by max scale down rate" ,
146+ },
147+ {
148+ name : "extreme_scale_up_case" ,
149+ currentPodCount : 2.0 ,
150+ context : & common.MockScalingContext {
151+ TargetValue : 10.0 ,
152+ UpFluctuationTolerance : 0.1 , // 10% tolerance
153+ DownFluctuationTolerance : 0.2 , // 20% tolerance
154+ MaxScaleUpRate : 3.0 , // Can scale up by 200%
155+ MaxScaleDownRate : 2.0 ,
156+ CurrentUsePerPod : 50.0 , // 50/10 = 5.0, would need 10 pods
157+ MinReplicas : 1 ,
158+ MaxReplicas : 20 ,
159+ },
160+ expected : 6 , // ceil(3.0 * 2) = 6 (limited by max scale up rate)
161+ description : "Should handle extreme scale up scenarios with rate limiting" ,
162+ },
163+ }
164+
165+ for _ , tt := range tests {
166+ t .Run (tt .name , func (t * testing.T ) {
167+ result := algorithm .ComputeTargetReplicas (tt .currentPodCount , tt .context )
168+ if result != tt .expected {
169+ t .Errorf ("ComputeTargetReplicas() = %d, expected %d. %s" , result , tt .expected , tt .description )
170+ t .Logf ("Current pod count: %.1f" , tt .currentPodCount )
171+ t .Logf ("Current use per pod: %.1f" , tt .context .CurrentUsePerPod )
172+ t .Logf ("Target value: %.1f" , tt .context .TargetValue )
173+ t .Logf ("Up tolerance: %.3f" , tt .context .UpFluctuationTolerance )
174+ t .Logf ("Down tolerance: %.3f" , tt .context .DownFluctuationTolerance )
175+ t .Logf ("Ratio (current/expected): %.6f" , tt .context .CurrentUsePerPod / tt .context .TargetValue )
176+ t .Logf ("Up threshold: %.6f" , 1 + tt .context .UpFluctuationTolerance )
177+ t .Logf ("Down threshold: %.6f" , 1 - tt .context .DownFluctuationTolerance )
178+ }
179+ })
180+ }
181+ }
0 commit comments