@@ -1610,3 +1610,155 @@ func getScannedSamples(start, end, step uint64) uint64 {
16101610func getPeakSamples (start , end , step uint64 ) uint64 {
16111611 return start + ((end - start )/ step )* step
16121612}
1613+
1614+ func TestPrometheusResponseExtractor_Extract_Histograms (t * testing.T ) {
1615+ t .Parallel ()
1616+ extractor := PrometheusResponseExtractor {}
1617+
1618+ for _ , tc := range []struct {
1619+ name string
1620+ inputStream tripperware.SampleStream
1621+ extractStart int64
1622+ extractEnd int64
1623+ expectedSamplesCount int
1624+ expectedHistogramsCount int
1625+ expectedHistogramsNil bool
1626+ }{
1627+ {
1628+ name : "stream with no histograms" ,
1629+ inputStream : tripperware.SampleStream {
1630+ Labels : []cortexpb.LabelAdapter {
1631+ {Name : "foo" , Value : "bar" },
1632+ },
1633+ Samples : []cortexpb.Sample {
1634+ {TimestampMs : 1000 , Value : 1.0 },
1635+ {TimestampMs : 2000 , Value : 2.0 },
1636+ {TimestampMs : 3000 , Value : 3.0 },
1637+ },
1638+ // Histograms: nil (not set)
1639+ },
1640+ extractStart : 1500 ,
1641+ extractEnd : 2500 ,
1642+ expectedSamplesCount : 1 ,
1643+ expectedHistogramsCount : 0 ,
1644+ expectedHistogramsNil : true ,
1645+ },
1646+ {
1647+ name : "stream with histograms" ,
1648+ inputStream : tripperware.SampleStream {
1649+ Labels : []cortexpb.LabelAdapter {
1650+ {Name : "foo" , Value : "bar" },
1651+ },
1652+ Samples : []cortexpb.Sample {
1653+ {TimestampMs : 1000 , Value : 1.0 },
1654+ {TimestampMs : 2000 , Value : 2.0 },
1655+ {TimestampMs : 3000 , Value : 3.0 },
1656+ },
1657+ Histograms : []tripperware.SampleHistogramPair {
1658+ {
1659+ TimestampMs : 1500 ,
1660+ Histogram : tripperware.SampleHistogram {Count : 10 , Sum : 100.0 },
1661+ },
1662+ {
1663+ TimestampMs : 2500 ,
1664+ Histogram : tripperware.SampleHistogram {Count : 20 , Sum : 200.0 },
1665+ },
1666+ {
1667+ TimestampMs : 3500 ,
1668+ Histogram : tripperware.SampleHistogram {Count : 30 , Sum : 300.0 },
1669+ },
1670+ },
1671+ },
1672+ extractStart : 1500 ,
1673+ extractEnd : 2500 ,
1674+ expectedSamplesCount : 1 , // Only sample at 2000
1675+ expectedHistogramsCount : 2 , // Histograms at 1500 and 2500
1676+ expectedHistogramsNil : false ,
1677+ },
1678+ {
1679+ name : "stream with histograms - no samples and histograms in range" ,
1680+ inputStream : tripperware.SampleStream {
1681+ Labels : []cortexpb.LabelAdapter {
1682+ {Name : "foo" , Value : "bar" },
1683+ },
1684+ Samples : []cortexpb.Sample {
1685+ {TimestampMs : 1000 , Value : 1.0 },
1686+ },
1687+ Histograms : []tripperware.SampleHistogramPair {
1688+ {
1689+ TimestampMs : 3000 ,
1690+ Histogram : tripperware.SampleHistogram {Count : 30 , Sum : 300.0 },
1691+ },
1692+ },
1693+ },
1694+ extractStart : 1500 ,
1695+ extractEnd : 2500 ,
1696+ expectedSamplesCount : 0 ,
1697+ expectedHistogramsCount : 0 ,
1698+ expectedHistogramsNil : true ,
1699+ },
1700+ {
1701+ name : "stream with empty histograms slice" ,
1702+ inputStream : tripperware.SampleStream {
1703+ Labels : []cortexpb.LabelAdapter {
1704+ {Name : "foo" , Value : "bar" },
1705+ },
1706+ Samples : []cortexpb.Sample {
1707+ {TimestampMs : 2000 , Value : 2.0 },
1708+ },
1709+ Histograms : []tripperware.SampleHistogramPair {},
1710+ },
1711+ extractStart : 1500 ,
1712+ extractEnd : 2500 ,
1713+ expectedSamplesCount : 1 ,
1714+ expectedHistogramsCount : 0 ,
1715+ expectedHistogramsNil : true ,
1716+ },
1717+ } {
1718+ t .Run (tc .name , func (t * testing.T ) {
1719+ t .Parallel ()
1720+
1721+ response := & tripperware.PrometheusResponse {
1722+ Status : "success" ,
1723+ Data : tripperware.PrometheusData {
1724+ ResultType : "matrix" ,
1725+ Result : tripperware.PrometheusQueryResult {
1726+ Result : & tripperware.PrometheusQueryResult_Matrix {
1727+ Matrix : & tripperware.Matrix {
1728+ SampleStreams : []tripperware.SampleStream {tc .inputStream },
1729+ },
1730+ },
1731+ },
1732+ },
1733+ }
1734+
1735+ extracted := extractor .Extract (tc .extractStart , tc .extractEnd , response ).(* tripperware.PrometheusResponse )
1736+ extractedStreams := extracted .Data .Result .GetMatrix ().GetSampleStreams ()
1737+
1738+ if tc .expectedSamplesCount == 0 && tc .expectedHistogramsCount == 0 {
1739+ require .Empty (t , extractedStreams , "should have no streams when no data in range" )
1740+ return
1741+ }
1742+
1743+ require .Len (t , extractedStreams , 1 , "should have exactly one stream" )
1744+ extractedStream := extractedStreams [0 ]
1745+
1746+ require .Equal (t , tc .expectedSamplesCount , len (extractedStream .Samples ), "unexpected number of samples" )
1747+
1748+ if tc .expectedHistogramsNil {
1749+ require .Nil (t , extractedStream .Histograms , "histograms should be nil for backward compatibility" )
1750+ } else {
1751+ require .NotNil (t , extractedStream .Histograms , "histograms should not be nil when original had histograms" )
1752+ require .Equal (t , tc .expectedHistogramsCount , len (extractedStream .Histograms ), "unexpected number of histograms" )
1753+ }
1754+
1755+ if tc .expectedHistogramsCount > 0 {
1756+ for _ , hist := range extractedStream .Histograms {
1757+ require .GreaterOrEqual (t , hist .TimestampMs , tc .extractStart , "histogram timestamp should be >= start" )
1758+ require .LessOrEqual (t , hist .TimestampMs , tc .extractEnd , "histogram timestamp should be <= end" )
1759+ require .NotNil (t , hist .Histogram , "histogram data should not be nil" )
1760+ }
1761+ }
1762+ })
1763+ }
1764+ }
0 commit comments