@@ -11,6 +11,7 @@ import (
1111 "time"
1212
1313 "github.com/prometheus/prometheus/model/labels"
14+ "github.com/prometheus/prometheus/prompb"
1415 "github.com/stretchr/testify/assert"
1516 "github.com/stretchr/testify/require"
1617 "github.com/thanos-io/thanos/pkg/runutil"
@@ -134,3 +135,67 @@ func Test_AllUserStats_WhenIngesterRollingUpdate(t *testing.T) {
134135 require .Len (t , userStats , 1 )
135136 require .Equal (t , uint64 (2 ), userStats [0 ].QueriedIngesters )
136137}
138+
139+ func TestTSDBStatus (t * testing.T ) {
140+ s , err := e2e .NewScenario (networkName )
141+ require .NoError (t , err )
142+ defer s .Close ()
143+
144+ flags := BlocksStorageFlags ()
145+ flags ["-distributor.replication-factor" ] = "1"
146+
147+ // Start dependencies.
148+ consul := e2edb .NewConsul ()
149+ minio := e2edb .NewMinio (9000 , flags ["-blocks-storage.s3.bucket-name" ])
150+ require .NoError (t , s .StartAndWaitReady (consul , minio ))
151+
152+ // Start Cortex in single binary mode.
153+ cortex := e2ecortex .NewSingleBinary ("cortex-1" , flags , "" )
154+ require .NoError (t , s .StartAndWaitReady (cortex ))
155+
156+ // Wait until the ingester ring is active.
157+ require .NoError (t , cortex .WaitSumMetricsWithOptions (e2e .Equals (1 ), []string {"cortex_ring_members" }, e2e .WithLabelMatchers (
158+ labels .MustNewMatcher (labels .MatchEqual , "name" , "ingester" ),
159+ labels .MustNewMatcher (labels .MatchEqual , "state" , "ACTIVE" ))))
160+
161+ client , err := e2ecortex .NewClient (cortex .HTTPEndpoint (), cortex .HTTPEndpoint (), "" , "" , "test-tenant" )
162+ require .NoError (t , err )
163+
164+ now := time .Now ()
165+
166+ // Push multiple series to create interesting cardinality:
167+ // - http_requests_total with 3 label combinations
168+ // - process_cpu_seconds_total with 1 label combination
169+ series1 , _ := generateSeries ("http_requests_total" , now , prompb.Label {Name : "method" , Value : "GET" }, prompb.Label {Name : "status" , Value : "200" })
170+ series2 , _ := generateSeries ("http_requests_total" , now , prompb.Label {Name : "method" , Value : "POST" }, prompb.Label {Name : "status" , Value : "200" })
171+ series3 , _ := generateSeries ("http_requests_total" , now , prompb.Label {Name : "method" , Value : "GET" }, prompb.Label {Name : "status" , Value : "500" })
172+ series4 , _ := generateSeries ("process_cpu_seconds_total" , now , prompb.Label {Name : "instance" , Value : "a" })
173+
174+ allSeries := append (series1 , series2 ... )
175+ allSeries = append (allSeries , series3 ... )
176+ allSeries = append (allSeries , series4 ... )
177+
178+ res , err := client .Push (allSeries )
179+ require .NoError (t , err )
180+ require .Equal (t , 200 , res .StatusCode )
181+
182+ // Query TSDB status with default limit.
183+ status , err := client .TSDBStatus (10 )
184+ require .NoError (t , err )
185+
186+ assert .Equal (t , uint64 (4 ), status .NumSeries )
187+ require .GreaterOrEqual (t , len (status .SeriesCountByMetricName ), 2 )
188+ assert .Equal (t , "http_requests_total" , status .SeriesCountByMetricName [0 ].Name )
189+ assert .Equal (t , uint64 (3 ), status .SeriesCountByMetricName [0 ].Value )
190+ assert .Equal (t , "process_cpu_seconds_total" , status .SeriesCountByMetricName [1 ].Name )
191+ assert .Equal (t , uint64 (1 ), status .SeriesCountByMetricName [1 ].Value )
192+ assert .NotEmpty (t , status .LabelValueCountByLabelName )
193+ assert .Greater (t , status .MinTime , int64 (0 ))
194+ assert .Greater (t , status .MaxTime , int64 (0 ))
195+
196+ // Query TSDB status with limit=1 to verify truncation.
197+ status , err = client .TSDBStatus (1 )
198+ require .NoError (t , err )
199+ assert .Len (t , status .SeriesCountByMetricName , 1 )
200+ assert .Equal (t , "http_requests_total" , status .SeriesCountByMetricName [0 ].Name )
201+ }
0 commit comments