@@ -518,6 +518,122 @@ func TestVerticalShardingFuzz(t *testing.T) {
518518 runQueryFuzzTestCases (t , ps , c1 , c2 , now , start , end , scrapeInterval , 1000 )
519519}
520520
521+ func TestProtobufCodecFuzz (t * testing.T ) {
522+ s , err := e2e .NewScenario (networkName )
523+ require .NoError (t , err )
524+ defer s .Close ()
525+
526+ // Start dependencies.
527+ consul1 := e2edb .NewConsulWithName ("consul1" )
528+ consul2 := e2edb .NewConsulWithName ("consul2" )
529+ require .NoError (t , s .StartAndWaitReady (consul1 , consul2 ))
530+
531+ flags := mergeFlags (
532+ AlertmanagerLocalFlags (),
533+ map [string ]string {
534+ "-store.engine" : blocksStorageEngine ,
535+ "-blocks-storage.backend" : "filesystem" ,
536+ "-blocks-storage.tsdb.head-compaction-interval" : "4m" ,
537+ "-blocks-storage.tsdb.block-ranges-period" : "2h" ,
538+ "-blocks-storage.tsdb.ship-interval" : "1h" ,
539+ "-blocks-storage.bucket-store.sync-interval" : "15m" ,
540+ "-blocks-storage.tsdb.retention-period" : "2h" ,
541+ "-blocks-storage.bucket-store.index-cache.backend" : tsdb .IndexCacheBackendInMemory ,
542+ "-querier.query-store-for-labels-enabled" : "true" ,
543+ // Ingester.
544+ "-ring.store" : "consul" ,
545+ "-consul.hostname" : consul1 .NetworkHTTPEndpoint (),
546+ // Distributor.
547+ "-distributor.replication-factor" : "1" ,
548+ // Store-gateway.
549+ "-store-gateway.sharding-enabled" : "false" ,
550+ // alert manager
551+ "-alertmanager.web.external-url" : "http://localhost/alertmanager" ,
552+ },
553+ )
554+ // make alert manager config dir
555+ require .NoError (t , writeFileToSharedDir (s , "alertmanager_configs" , []byte {}))
556+
557+ path1 := path .Join (s .SharedDir (), "cortex-1" )
558+ path2 := path .Join (s .SharedDir (), "cortex-2" )
559+
560+ flags1 := mergeFlags (flags , map [string ]string {"-blocks-storage.filesystem.dir" : path1 })
561+ // Start Cortex replicas.
562+ cortex1 := e2ecortex .NewSingleBinary ("cortex-1" , flags1 , "" )
563+ // Enable protobuf codec for the second Cortex instance.
564+ flags2 := mergeFlags (flags , map [string ]string {
565+ "-api.querier-default-codec" : "protobuf" ,
566+ "-blocks-storage.filesystem.dir" : path2 ,
567+ "-consul.hostname" : consul2 .NetworkHTTPEndpoint (),
568+ })
569+ cortex2 := e2ecortex .NewSingleBinary ("cortex-2" , flags2 , "" )
570+ require .NoError (t , s .StartAndWaitReady (cortex1 , cortex2 ))
571+
572+ // Wait until Cortex replicas have updated the ring state.
573+ require .NoError (t , cortex1 .WaitSumMetrics (e2e .Equals (float64 (512 )), "cortex_ring_tokens_total" ))
574+ require .NoError (t , cortex2 .WaitSumMetrics (e2e .Equals (float64 (512 )), "cortex_ring_tokens_total" ))
575+
576+ c1 , err := e2ecortex .NewClient (cortex1 .HTTPEndpoint (), cortex1 .HTTPEndpoint (), "" , "" , "user-1" )
577+ require .NoError (t , err )
578+ c2 , err := e2ecortex .NewClient (cortex2 .HTTPEndpoint (), cortex2 .HTTPEndpoint (), "" , "" , "user-1" )
579+ require .NoError (t , err )
580+
581+ now := time .Now ()
582+ // Push some series to Cortex.
583+ start := now .Add (- time .Minute * 10 )
584+ end := now .Add (- time .Minute * 1 )
585+ numSeries := 3
586+ numSamples := 20
587+ lbls := make ([]labels.Labels , numSeries * 2 )
588+ serieses := make ([]prompb.TimeSeries , numSeries * 2 )
589+ scrapeInterval := 30 * time .Second
590+ for i := 0 ; i < numSeries ; i ++ {
591+ series := e2e .GenerateSeriesWithSamples ("test_series_a" , start , scrapeInterval , i * numSamples , numSamples , prompb.Label {Name : "job" , Value : "test" }, prompb.Label {Name : "series" , Value : strconv .Itoa (i )})
592+ serieses [i ] = series
593+ builder := labels .NewBuilder (labels .EmptyLabels ())
594+ for _ , lbl := range series .Labels {
595+ builder .Set (lbl .Name , lbl .Value )
596+ }
597+ lbls [i ] = builder .Labels ()
598+ }
599+ // Generate another set of series for testing binary expression and vector matching.
600+ for i := numSeries ; i < 2 * numSeries ; i ++ {
601+ prompbLabels := []prompb.Label {{Name : "job" , Value : "test" }, {Name : "series" , Value : strconv .Itoa (i )}}
602+ if i % 3 == 0 {
603+ prompbLabels = append (prompbLabels , prompb.Label {Name : "status_code" , Value : "200" })
604+ } else if i % 3 == 1 {
605+ prompbLabels = append (prompbLabels , prompb.Label {Name : "status_code" , Value : "400" })
606+ } else {
607+ prompbLabels = append (prompbLabels , prompb.Label {Name : "status_code" , Value : "500" })
608+ }
609+ series := e2e .GenerateSeriesWithSamples ("test_series_b" , start , scrapeInterval , i * numSamples , numSamples , prompbLabels ... )
610+ serieses [i ] = series
611+ builder := labels .NewBuilder (labels .EmptyLabels ())
612+ for _ , lbl := range series .Labels {
613+ builder .Set (lbl .Name , lbl .Value )
614+ }
615+ lbls [i ] = builder .Labels ()
616+ }
617+ res , err := c1 .Push (serieses )
618+ require .NoError (t , err )
619+ require .Equal (t , 200 , res .StatusCode )
620+ res , err = c2 .Push (serieses )
621+ require .NoError (t , err )
622+ require .Equal (t , 200 , res .StatusCode )
623+
624+ waitUntilReady (t , context .Background (), c1 , c2 , `{job="test"}` , start , end )
625+
626+ rnd := rand .New (rand .NewSource (now .Unix ()))
627+ opts := []promqlsmith.Option {
628+ promqlsmith .WithEnableOffset (true ),
629+ promqlsmith .WithEnableAtModifier (true ),
630+ promqlsmith .WithEnabledFunctions (enabledFunctions ),
631+ }
632+ ps := promqlsmith .New (rnd , lbls , opts ... )
633+
634+ runQueryFuzzTestCases (t , ps , c1 , c2 , now , start , end , scrapeInterval , 1000 )
635+ }
636+
521637// comparer should be used to compare promql results between engines.
522638var comparer = cmp .Comparer (func (x , y model.Value ) bool {
523639 if x .Type () != y .Type () {
0 commit comments