@@ -19,6 +19,7 @@ package metrics
1919import (
2020 "fmt"
2121 "testing"
22+ "time"
2223
2324 promtestutil "github.com/prometheus/client_golang/prometheus/testutil"
2425 "github.com/stretchr/testify/require"
@@ -98,3 +99,139 @@ func TestRecordRequestCounterBoundsModelCardinality(t *testing.T) {
9899 require .LessOrEqualf (t , count , testCap + 1 ,
99100 "model_name cardinality must stay bounded by the cap, got %d series" , count )
100101}
102+
103+ // The fairness_id label is populated from a client request header, so the package-level limiter
104+ // must collapse an unbounded flood of distinct IDs into the overflow bucket instead of minting a
105+ // series per ID.
106+ func TestFairnessLabelFloodCollapsesToOverflow (t * testing.T ) {
107+ const testCap = 5
108+ old := fairnessLabelLimiter
109+ fairnessLabelLimiter = newBoundedLabel (testCap )
110+ flowControlRequestEnqueueDuration .Reset ()
111+ llmdFlowControlRequestEnqueueDuration .Reset ()
112+ t .Cleanup (func () {
113+ fairnessLabelLimiter = old
114+ flowControlRequestEnqueueDuration .Reset ()
115+ llmdFlowControlRequestEnqueueDuration .Reset ()
116+ })
117+
118+ for i := 0 ; i < 1000 ; i ++ {
119+ RecordFlowControlRequestEnqueueDuration (fmt .Sprintf ("tenant-%d" , i ), "0" , "Dispatched" , time .Millisecond )
120+ }
121+
122+ // testCap admitted IDs + 1 overflow series, per family.
123+ require .Equal (t , testCap + 1 , promtestutil .CollectAndCount (flowControlRequestEnqueueDuration ),
124+ "1000 distinct fairness IDs must collapse to cap+overflow series, not one series each" )
125+ require .Equal (t , testCap + 1 , promtestutil .CollectAndCount (llmdFlowControlRequestEnqueueDuration ),
126+ "the llm_d_epp family must be bounded identically" )
127+ }
128+
129+ // DeleteFlowControlFlowSeries backs the flow registry's GC hook: once a flow is collected, its
130+ // series must not linger for the lifetime of the process.
131+ func TestDeleteFlowControlFlowSeries (t * testing.T ) {
132+ old := fairnessLabelLimiter
133+ fairnessLabelLimiter = newBoundedLabel (10 )
134+ flowControlRequestEnqueueDuration .Reset ()
135+ llmdFlowControlRequestEnqueueDuration .Reset ()
136+ t .Cleanup (func () {
137+ fairnessLabelLimiter = old
138+ flowControlRequestEnqueueDuration .Reset ()
139+ llmdFlowControlRequestEnqueueDuration .Reset ()
140+ })
141+
142+ RecordFlowControlRequestEnqueueDuration ("tenant-a" , "0" , "Dispatched" , time .Millisecond )
143+ RecordFlowControlRequestEnqueueDuration ("tenant-a" , "0" , "Rejected" , time .Millisecond )
144+ RecordFlowControlRequestEnqueueDuration ("tenant-b" , "0" , "Dispatched" , time .Millisecond )
145+ require .Equal (t , 3 , promtestutil .CollectAndCount (flowControlRequestEnqueueDuration ),
146+ "setup: expected one series per (fairness_id, outcome) pair" )
147+
148+ DeleteFlowControlFlowSeries ("tenant-a" , "0" )
149+
150+ require .Equal (t , 1 , promtestutil .CollectAndCount (flowControlRequestEnqueueDuration ),
151+ "all of tenant-a's series (every outcome) must be pruned; tenant-b's must survive" )
152+ require .Equal (t , 1 , promtestutil .CollectAndCount (llmdFlowControlRequestEnqueueDuration ),
153+ "the llm_d_epp family must be pruned identically" )
154+ }
155+
156+ // The bound is applied mechanically in every record function that takes a fairness ID; this guards
157+ // the request-metric family (distinct label ordering from the flow control family) against the
158+ // pattern regressing there.
159+ func TestFairnessLabelBoundOnRequestMetrics (t * testing.T ) {
160+ const testCap = 3
161+ oldFairness := fairnessLabelLimiter
162+ fairnessLabelLimiter = newBoundedLabel (testCap )
163+ oldModels := modelLabelLimiter
164+ modelLabelLimiter = newBoundedLabel (10 )
165+ requestCounter .Reset ()
166+ llmdRequestCounter .Reset ()
167+ t .Cleanup (func () {
168+ fairnessLabelLimiter = oldFairness
169+ modelLabelLimiter = oldModels
170+ requestCounter .Reset ()
171+ llmdRequestCounter .Reset ()
172+ })
173+
174+ for i := 0 ; i < 100 ; i ++ {
175+ RecordRequestCounter ("model-a" , "model-a" , fmt .Sprintf ("tenant-%d" , i ), 0 )
176+ }
177+
178+ require .Equal (t , testCap + 1 , promtestutil .CollectAndCount (llmdRequestCounter ),
179+ "100 distinct fairness IDs must collapse to cap+overflow series on the request family" )
180+ require .Equal (t , 1 , promtestutil .CollectAndCount (requestCounter ),
181+ "the deprecated family has no fairness_id label and must stay a single series" )
182+ }
183+
184+ // RecordFlowControlRequestQueueDuration takes request-body model names; they must flow through the
185+ // model limiter like every sibling record function.
186+ func TestQueueDurationBoundsModelLabels (t * testing.T ) {
187+ const testCap = 3
188+ oldModels := modelLabelLimiter
189+ modelLabelLimiter = newBoundedLabel (testCap )
190+ oldFairness := fairnessLabelLimiter
191+ fairnessLabelLimiter = newBoundedLabel (10 )
192+ flowControlRequestQueueDuration .Reset ()
193+ llmdFlowControlRequestQueueDuration .Reset ()
194+ t .Cleanup (func () {
195+ modelLabelLimiter = oldModels
196+ fairnessLabelLimiter = oldFairness
197+ flowControlRequestQueueDuration .Reset ()
198+ llmdFlowControlRequestQueueDuration .Reset ()
199+ })
200+
201+ for i := 0 ; i < 100 ; i ++ {
202+ m := fmt .Sprintf ("model-%d" , i )
203+ RecordFlowControlRequestQueueDuration ("tenant" , "0" , "Dispatched" , "pool" , m , m , time .Millisecond )
204+ }
205+
206+ require .Equal (t , testCap + 1 , promtestutil .CollectAndCount (flowControlRequestQueueDuration ),
207+ "100 distinct model names must collapse to cap+overflow series, not one series each" )
208+ require .Equal (t , testCap + 1 , promtestutil .CollectAndCount (llmdFlowControlRequestQueueDuration ),
209+ "the llm_d_epp family must be bounded identically" )
210+ }
211+
212+ // A client can choose the overflow value itself as its fairness ID; GC of that flow must not
213+ // delete the shared overflow series that aggregates every capped-out tenant.
214+ func TestDeleteFlowControlFlowSeriesPreservesOverflowSeries (t * testing.T ) {
215+ old := fairnessLabelLimiter
216+ fairnessLabelLimiter = newBoundedLabel (1 )
217+ flowControlRequestEnqueueDuration .Reset ()
218+ llmdFlowControlRequestEnqueueDuration .Reset ()
219+ t .Cleanup (func () {
220+ fairnessLabelLimiter = old
221+ flowControlRequestEnqueueDuration .Reset ()
222+ llmdFlowControlRequestEnqueueDuration .Reset ()
223+ })
224+
225+ // tenant-a fills the single cap slot; tenant-b folds to the overflow series.
226+ RecordFlowControlRequestEnqueueDuration ("tenant-a" , "0" , "Dispatched" , time .Millisecond )
227+ RecordFlowControlRequestEnqueueDuration ("tenant-b" , "0" , "Dispatched" , time .Millisecond )
228+ require .Equal (t , 2 , promtestutil .CollectAndCount (flowControlRequestEnqueueDuration ),
229+ "setup: expected the admitted series plus the overflow series" )
230+
231+ DeleteFlowControlFlowSeries (overflowValue , "0" )
232+
233+ require .Equal (t , 2 , promtestutil .CollectAndCount (flowControlRequestEnqueueDuration ),
234+ "deleting the overflow value must be a no-op; the shared overflow series must survive" )
235+ require .Equal (t , 2 , promtestutil .CollectAndCount (llmdFlowControlRequestEnqueueDuration ),
236+ "the llm_d_epp family must be preserved identically" )
237+ }
0 commit comments