@@ -19,7 +19,9 @@ package saturationdetector
19
19
import (
20
20
"context"
21
21
"errors"
22
- "sync"
22
+ "fmt"
23
+ "os"
24
+ "strconv"
23
25
"testing"
24
26
"time"
25
27
@@ -44,22 +46,6 @@ func (fds *mockDatastore) PodGetAll() []backendmetrics.PodMetrics {
44
46
return pm
45
47
}
46
48
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
-
63
49
func newMockPodMetrics (name string , metrics * backendmetrics.MetricsState ) * backendmetrics.FakePodMetrics {
64
50
return & backendmetrics.FakePodMetrics {
65
51
Pod : & backend.Pod {
@@ -73,61 +59,82 @@ func newMockPodMetrics(name string, metrics *backendmetrics.MetricsState) *backe
73
59
74
60
func TestNewDetector (t * testing.T ) {
75
61
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
81
69
}{
82
70
{
83
71
name : "Valid config" ,
84
- config : Config {
72
+ config : & Config {
85
73
QueueDepthThreshold : 10 ,
86
74
KVCacheUtilThreshold : 0.8 ,
87
75
MetricsStalenessThreshold : 100 * time .Millisecond ,
88
76
},
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 ,
92
82
},
93
83
{
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 ,
99
88
},
100
89
{
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 ,
106
108
},
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 ,
110
114
},
111
115
}
112
116
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 ())
116
124
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 )
119
127
}
120
128
121
129
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 )
125
132
}
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 )
128
135
}
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 )
131
138
}
132
139
}
133
140
})
@@ -136,15 +143,15 @@ func TestNewDetector(t *testing.T) {
136
143
137
144
func TestDetector_IsSaturated (t * testing.T ) {
138
145
baseTime := time .Now ()
139
- defaultConfig := Config {
146
+ defaultConfig := & Config {
140
147
QueueDepthThreshold : 5 ,
141
148
KVCacheUtilThreshold : 0.90 ,
142
149
MetricsStalenessThreshold : 100 * time .Millisecond ,
143
150
}
144
151
145
152
tests := []struct {
146
153
name string
147
- config Config
154
+ config * Config
148
155
pods []* backendmetrics.FakePodMetrics
149
156
expectedSaturat bool
150
157
}{
@@ -307,18 +314,6 @@ func TestDetector_IsSaturated(t *testing.T) {
307
314
},
308
315
expectedSaturat : false ,
309
316
},
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
- },
322
317
{
323
318
name : "Metrics age just over staleness threshold" ,
324
319
config : defaultConfig ,
@@ -333,18 +328,15 @@ func TestDetector_IsSaturated(t *testing.T) {
333
328
},
334
329
}
335
330
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 ())
341
334
if err != nil {
342
335
t .Fatalf ("NewDetector() failed: %v" , err )
343
336
}
344
- detector .clock = newMockClock (baseTime )
345
337
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 )
348
340
}
349
341
})
350
342
}
0 commit comments