66 "net/http"
77 "net/http/httptest"
88 "net/url"
9- "strings"
109 "testing"
1110 "time"
1211
@@ -363,37 +362,6 @@ func TestGraphiteClient_DoGet_NonOKStatus(t *testing.T) {
363362 assert .Contains (t , err .Error (), "500" )
364363}
365364
366- // --- graphiteDensityBucketSize ---
367-
368- func TestGraphiteDensityBucketSize (t * testing.T ) {
369- tests := []struct {
370- from string
371- want string
372- }{
373- {"-30m" , "5m" },
374- {"-1h" , "5m" },
375- {"-3h" , "5m" },
376- {"-4h" , "30m" },
377- {"-12h" , "30m" },
378- {"-24h" , "30m" },
379- {"-48h" , "1h" },
380- {"-72h" , "1h" },
381- {"-7d" , "6h" },
382- {"-14d" , "6h" },
383- {"-30d" , "1d" },
384- {"-1w" , "6h" },
385- {"" , "1h" },
386- {"now" , "1h" },
387- {"2024-01-01T00:00:00Z" , "1h" },
388- {"-5x" , "1h" }, // unknown unit
389- }
390- for _ , tc := range tests {
391- t .Run (tc .from , func (t * testing.T ) {
392- assert .Equal (t , tc .want , graphiteDensityBucketSize (tc .from ))
393- })
394- }
395- }
396-
397365// --- computeSeriesDensity ---
398366
399367func TestComputeSeriesDensity_AllNull (t * testing.T ) {
@@ -607,171 +575,3 @@ func TestQueryGraphiteDensity_MixedCluster(t *testing.T) {
607575 assert .Equal (t , int64 (60 ), s2 .EstimatedInterval )
608576}
609577
610- func TestQueryGraphiteDensity_IsNonNullUsedWhenCountMatches (t * testing.T ) {
611- // The isNonNull+summarize call reports 3 non-null points; the raw series has
612- // 2 non-null points (could differ due to resolution). When counts match,
613- // the isNonNull value is used for NonNullPoints / FillRatio.
614- isNonNullResp := []graphiteRawSeries {
615- {
616- Target : `summarize(isNonNull(a.b.c),"5m","sum")` ,
617- Datapoints : [][]json.RawMessage {
618- {json .RawMessage ("2" ), json .RawMessage ("1704067200" )},
619- {json .RawMessage ("1" ), json .RawMessage ("1704067500" )},
620- },
621- },
622- }
623- rawResp := []graphiteRawSeries {
624- {
625- Target : "a.b.c" ,
626- Datapoints : [][]json.RawMessage {
627- {json .RawMessage ("1.0" ), json .RawMessage ("1704067200" )},
628- {json .RawMessage ("null" ), json .RawMessage ("1704067260" )},
629- {json .RawMessage ("2.0" ), json .RawMessage ("1704067320" )},
630- {json .RawMessage ("null" ), json .RawMessage ("1704067380" )},
631- },
632- },
633- }
634-
635- ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
636- w .Header ().Set ("Content-Type" , "application/json" )
637- target := r .URL .Query ().Get ("target" )
638- if strings .HasPrefix (target , "summarize" ) {
639- _ = json .NewEncoder (w ).Encode (isNonNullResp )
640- } else {
641- _ = json .NewEncoder (w ).Encode (rawResp )
642- }
643- }))
644- t .Cleanup (ts .Close )
645-
646- client := & GraphiteClient {httpClient : http .DefaultClient , baseURL : ts .URL }
647- ctx := context .Background ()
648-
649- // Fetch isNonNull
650- innParams := url.Values {}
651- innParams .Set ("target" , `summarize(isNonNull(a.b.c),"5m","sum")` )
652- innParams .Set ("format" , "json" )
653- innData , err := client .doGet (ctx , "/render" , innParams )
654- require .NoError (t , err )
655- var innSeries []graphiteRawSeries
656- require .NoError (t , json .Unmarshal (innData , & innSeries ))
657-
658- isNonNullCounts := make ([]int , len (innSeries ))
659- for i , s := range innSeries {
660- for _ , dp := range parseGraphiteDatapoints (s .Datapoints ) {
661- if dp .Value != nil {
662- isNonNullCounts [i ] += int (* dp .Value )
663- }
664- }
665- }
666- assert .Equal (t , []int {3 }, isNonNullCounts ) // 2+1 buckets
667-
668- // Fetch raw
669- rawParams := url.Values {}
670- rawParams .Set ("target" , "a.b.c" )
671- rawParams .Set ("format" , "json" )
672- rawData , err := client .doGet (ctx , "/render" , rawParams )
673- require .NoError (t , err )
674- var raws []graphiteRawSeries
675- require .NoError (t , json .Unmarshal (rawData , & raws ))
676-
677- // Counts match (1 == 1) → use isNonNull count
678- useIsNonNull := len (isNonNullCounts ) == len (raws )
679- assert .True (t , useIsNonNull )
680-
681- stats := computeSeriesDensity (raws [0 ].Target , parseGraphiteDatapoints (raws [0 ].Datapoints ))
682- if useIsNonNull {
683- stats .NonNullPoints = isNonNullCounts [0 ]
684- if stats .TotalPoints > 0 {
685- stats .FillRatio = float64 (stats .NonNullPoints ) / float64 (stats .TotalPoints )
686- }
687- }
688- assert .Equal (t , 3 , stats .NonNullPoints ) // from isNonNull, not raw count (2)
689- assert .InDelta (t , 0.75 , stats .FillRatio , 1e-9 ) // 3/4
690- }
691-
692- func TestQueryGraphiteDensity_IsNonNullCountMismatch_FallsBackToRaw (t * testing.T ) {
693- // isNonNull returns 2 series; raw returns 3 → mismatch → use raw counts.
694- isNonNullResp := []graphiteRawSeries {
695- {Target : `summarize(isNonNull(a.b.1),"5m","sum")` ,
696- Datapoints : [][]json.RawMessage {{json .RawMessage ("3" ), json .RawMessage ("1704067200" )}}},
697- {Target : `summarize(isNonNull(a.b.2),"5m","sum")` ,
698- Datapoints : [][]json.RawMessage {{json .RawMessage ("null" ), json .RawMessage ("1704067200" )}}},
699- }
700- rawResp := []graphiteRawSeries {
701- {
702- Target : "a.b.1" ,
703- Datapoints : [][]json.RawMessage {
704- {json .RawMessage ("1.0" ), json .RawMessage ("1704067200" )},
705- {json .RawMessage ("null" ), json .RawMessage ("1704067260" )},
706- },
707- },
708- {
709- Target : "a.b.2" ,
710- Datapoints : [][]json.RawMessage {
711- {json .RawMessage ("null" ), json .RawMessage ("1704067200" )},
712- {json .RawMessage ("null" ), json .RawMessage ("1704067260" )},
713- },
714- },
715- {
716- Target : "a.b.3" , // extra series absent from isNonNull result
717- Datapoints : [][]json.RawMessage {
718- {json .RawMessage ("2.0" ), json .RawMessage ("1704067200" )},
719- {json .RawMessage ("3.0" ), json .RawMessage ("1704067260" )},
720- },
721- },
722- }
723-
724- ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
725- w .Header ().Set ("Content-Type" , "application/json" )
726- target := r .URL .Query ().Get ("target" )
727- if strings .HasPrefix (target , "summarize" ) {
728- _ = json .NewEncoder (w ).Encode (isNonNullResp )
729- } else {
730- _ = json .NewEncoder (w ).Encode (rawResp )
731- }
732- }))
733- t .Cleanup (ts .Close )
734-
735- client := & GraphiteClient {httpClient : http .DefaultClient , baseURL : ts .URL }
736- ctx := context .Background ()
737-
738- // Fetch isNonNull
739- innParams := url.Values {}
740- innParams .Set ("target" , `summarize(isNonNull(a.b.*),"5m","sum")` )
741- innParams .Set ("format" , "json" )
742- innData , err := client .doGet (ctx , "/render" , innParams )
743- require .NoError (t , err )
744- var innSeries []graphiteRawSeries
745- require .NoError (t , json .Unmarshal (innData , & innSeries ))
746-
747- isNonNullCounts := make ([]int , len (innSeries ))
748- for i , s := range innSeries {
749- for _ , dp := range parseGraphiteDatapoints (s .Datapoints ) {
750- if dp .Value != nil {
751- isNonNullCounts [i ] += int (* dp .Value )
752- }
753- }
754- }
755-
756- // Fetch raw
757- rawParams := url.Values {}
758- rawParams .Set ("target" , "a.b.*" )
759- rawParams .Set ("format" , "json" )
760- rawData , err := client .doGet (ctx , "/render" , rawParams )
761- require .NoError (t , err )
762- var raws []graphiteRawSeries
763- require .NoError (t , json .Unmarshal (rawData , & raws ))
764-
765- // 2 isNonNull vs 3 raw → mismatch → do NOT use isNonNull
766- useIsNonNull := len (isNonNullCounts ) == len (raws )
767- assert .False (t , useIsNonNull )
768-
769- // Compute stats from raw only
770- var results []* GraphiteSeriesDensity
771- for _ , rs := range raws {
772- results = append (results , computeSeriesDensity (rs .Target , parseGraphiteDatapoints (rs .Datapoints )))
773- }
774- assert .Equal (t , 1 , results [0 ].NonNullPoints ) // a.b.1: from raw
775- assert .Equal (t , 0 , results [1 ].NonNullPoints ) // a.b.2: from raw
776- assert .Equal (t , 2 , results [2 ].NonNullPoints ) // a.b.3: from raw
777- }
0 commit comments