@@ -19,7 +19,9 @@ package saturationdetector
1919import (
2020 "context"
2121 "errors"
22- "sync"
22+ "fmt"
23+ "os"
24+ "strconv"
2325 "testing"
2426 "time"
2527
@@ -44,22 +46,6 @@ func (fds *mockDatastore) PodGetAll() []backendmetrics.PodMetrics {
4446 return pm
4547}
4648
47- // mockClock allows controlling time in tests.
48- type mockClock struct {
49- mu sync.RWMutex
50- time time.Time
51- }
52-
53- func newMockClock (t time.Time ) * mockClock {
54- return & mockClock {time : t }
55- }
56-
57- func (c * mockClock ) now () time.Time {
58- c .mu .RLock ()
59- defer c .mu .RUnlock ()
60- return c .time
61- }
62-
6349func newMockPodMetrics (name string , metrics * backendmetrics.MetricsState ) * backendmetrics.FakePodMetrics {
6450 return & backendmetrics.FakePodMetrics {
6551 Pod : & backend.Pod {
@@ -73,61 +59,82 @@ func newMockPodMetrics(name string, metrics *backendmetrics.MetricsState) *backe
7359
7460func TestNewDetector (t * testing.T ) {
7561 tests := []struct {
76- name string
77- config Config
78- datastore Datastore
79- expectError error
80- expectedStalenessThresh time.Duration
62+ name string
63+ config * Config
64+ datastore Datastore
65+ expectError error
66+ expectedQueueDepthThreshold int
67+ expectedKVCacheUtilThreshold float64
68+ expectedStalenessThreshold time.Duration
8169 }{
8270 {
8371 name : "Valid config" ,
84- config : Config {
72+ config : & Config {
8573 QueueDepthThreshold : 10 ,
8674 KVCacheUtilThreshold : 0.8 ,
8775 MetricsStalenessThreshold : 100 * time .Millisecond ,
8876 },
89- datastore : & mockDatastore {},
90- expectError : nil ,
91- expectedStalenessThresh : 100 * time .Millisecond ,
77+ datastore : & mockDatastore {},
78+ expectError : nil ,
79+ expectedQueueDepthThreshold : 10 ,
80+ expectedKVCacheUtilThreshold : 0.8 ,
81+ expectedStalenessThreshold : 100 * time .Millisecond ,
9282 },
9383 {
94- name : "Nil datastore" ,
95- config : Config {},
96- datastore : nil ,
97- expectError : ErrNilDatastore ,
98- expectedStalenessThresh : DefaultMetricsStalenessThreshold , // Default will be set if error didn't occur first
84+ name : "Nil datastore" ,
85+ config : & Config {},
86+ datastore : nil ,
87+ expectError : ErrNilDatastore ,
9988 },
10089 {
101- name : "Zero staleness threshold uses default" ,
102- config : Config {
103- QueueDepthThreshold : 5 ,
104- KVCacheUtilThreshold : 0.9 ,
105- MetricsStalenessThreshold : 0 , // Should use default
90+ name : "invalid thresholds, fallback to default" ,
91+ config : & Config {
92+ QueueDepthThreshold : - 1 ,
93+ KVCacheUtilThreshold : - 5 ,
94+ MetricsStalenessThreshold : 0 ,
95+ },
96+ datastore : & mockDatastore {},
97+ expectError : nil ,
98+ expectedQueueDepthThreshold : DefaultQueueDepthThreshold ,
99+ expectedKVCacheUtilThreshold : DefaultKVCacheUtilThreshold ,
100+ expectedStalenessThreshold : DefaultMetricsStalenessThreshold ,
101+ },
102+ {
103+ name : "kv cache threshold above range, fallback to default" ,
104+ config : & Config {
105+ QueueDepthThreshold : 10 ,
106+ KVCacheUtilThreshold : 1.5 ,
107+ MetricsStalenessThreshold : 100 * time .Millisecond ,
106108 },
107- datastore : & mockDatastore {},
108- expectError : nil ,
109- expectedStalenessThresh : DefaultMetricsStalenessThreshold ,
109+ datastore : & mockDatastore {},
110+ expectError : nil ,
111+ expectedQueueDepthThreshold : 10 ,
112+ expectedKVCacheUtilThreshold : DefaultKVCacheUtilThreshold ,
113+ expectedStalenessThreshold : 100 * time .Millisecond ,
110114 },
111115 }
112116
113- for _ , tt := range tests {
114- t .Run (tt .name , func (t * testing.T ) {
115- detector , err := NewDetector (tt .config , tt .datastore , logr .Discard ())
117+ for _ , test := range tests {
118+ t .Run (test .name , func (t * testing.T ) {
119+ // validate configuration values are loaded from env vars properly, including the use of default values when provided value is invalid.
120+ os .Setenv (EnvSdQueueDepthThreshold , strconv .Itoa (test .config .QueueDepthThreshold ))
121+ os .Setenv (EnvSdKVCacheUtilThreshold , fmt .Sprintf ("%v" , test .config .KVCacheUtilThreshold ))
122+ os .Setenv (EnvSdMetricsStalenessThreshold , test .config .MetricsStalenessThreshold .String ())
123+ detector , err := NewDetector (LoadConfigFromEnv (), test .datastore , logr .Discard ())
116124
117- if ! errors .Is (err , tt .expectError ) {
118- t .Errorf ("NewDetector() error = %v, wantErr %v" , err , tt .expectError )
125+ if ! errors .Is (err , test .expectError ) {
126+ t .Errorf ("NewDetector() error = %v, wantErr %v" , err , test .expectError )
119127 }
120128
121129 if err == nil && detector != nil {
122- detector .clock = newMockClock (time .Now ())
123- if detector .config .MetricsStalenessThreshold != tt .expectedStalenessThresh {
124- t .Errorf ("NewDetector() MetricsStalenessThreshold = %v, want %v" , detector .config .MetricsStalenessThreshold , tt .expectedStalenessThresh )
130+ if detector .config .QueueDepthThreshold != test .expectedQueueDepthThreshold {
131+ t .Errorf ("NewDetector() QueueDepthThreshold = %d, want %d" , detector .config .QueueDepthThreshold , test .expectedQueueDepthThreshold )
125132 }
126- if detector .config .QueueDepthThreshold != tt . config . QueueDepthThreshold {
127- t .Errorf ("NewDetector() QueueDepthThreshold = %d , want %d " , detector .config .QueueDepthThreshold , tt . config . QueueDepthThreshold )
133+ if detector .config .KVCacheUtilThreshold != test . expectedKVCacheUtilThreshold {
134+ t .Errorf ("NewDetector() KVCacheUtilThreshold = %f , want %f " , detector .config .KVCacheUtilThreshold , test . expectedKVCacheUtilThreshold )
128135 }
129- if detector .config .KVCacheUtilThreshold != tt . config . KVCacheUtilThreshold {
130- t .Errorf ("NewDetector() KVCacheUtilThreshold = %f , want %f " , detector .config .KVCacheUtilThreshold , tt . config . KVCacheUtilThreshold )
136+ if detector .config .MetricsStalenessThreshold != test . expectedStalenessThreshold {
137+ t .Errorf ("NewDetector() MetricsStalenessThreshold = %v , want %v " , detector .config .MetricsStalenessThreshold , test . expectedStalenessThreshold )
131138 }
132139 }
133140 })
@@ -136,15 +143,15 @@ func TestNewDetector(t *testing.T) {
136143
137144func TestDetector_IsSaturated (t * testing.T ) {
138145 baseTime := time .Now ()
139- defaultConfig := Config {
146+ defaultConfig := & Config {
140147 QueueDepthThreshold : 5 ,
141148 KVCacheUtilThreshold : 0.90 ,
142149 MetricsStalenessThreshold : 100 * time .Millisecond ,
143150 }
144151
145152 tests := []struct {
146153 name string
147- config Config
154+ config * Config
148155 pods []* backendmetrics.FakePodMetrics
149156 expectedSaturat bool
150157 }{
@@ -307,18 +314,6 @@ func TestDetector_IsSaturated(t *testing.T) {
307314 },
308315 expectedSaturat : false ,
309316 },
310- {
311- name : "Metrics age exactly at staleness threshold" ,
312- config : defaultConfig ,
313- pods : []* backendmetrics.FakePodMetrics {
314- newMockPodMetrics ("pod1" , & backendmetrics.MetricsState {
315- UpdateTime : baseTime .Add (- defaultConfig .MetricsStalenessThreshold ), // Exactly at threshold (good)
316- WaitingQueueSize : 1 ,
317- KVCacheUsagePercent : 0.1 ,
318- }),
319- },
320- expectedSaturat : false ,
321- },
322317 {
323318 name : "Metrics age just over staleness threshold" ,
324319 config : defaultConfig ,
@@ -333,18 +328,15 @@ func TestDetector_IsSaturated(t *testing.T) {
333328 },
334329 }
335330
336- for _ , tt := range tests {
337- t .Run (tt .name , func (t * testing.T ) {
338- mockDS := & mockDatastore {pods : tt .pods }
339-
340- detector , err := NewDetector (tt .config , mockDS , logr .Discard ())
331+ for _ , test := range tests {
332+ t .Run (test .name , func (t * testing.T ) {
333+ detector , err := NewDetector (test .config , & mockDatastore {pods : test .pods }, logr .Discard ())
341334 if err != nil {
342335 t .Fatalf ("NewDetector() failed: %v" , err )
343336 }
344- detector .clock = newMockClock (baseTime )
345337
346- if got := detector .IsSaturated (context .Background ()); got != tt .expectedSaturat {
347- t .Errorf ("IsSaturated() = %v, want %v" , got , tt .expectedSaturat )
338+ if got := detector .IsSaturated (context .Background ()); got != test .expectedSaturat {
339+ t .Errorf ("IsSaturated() = %v, want %v" , got , test .expectedSaturat )
348340 }
349341 })
350342 }
0 commit comments