@@ -5,13 +5,15 @@ package logicalplan
55
66import (
77 "math"
8+ "math/rand"
89 "regexp"
910 "testing"
1011 "time"
1112
1213 "github.com/thanos-io/promql-engine/api"
1314 "github.com/thanos-io/promql-engine/query"
1415
16+ "github.com/cortexproject/promqlsmith"
1517 "github.com/efficientgo/core/testutil"
1618 "github.com/prometheus/prometheus/model/labels"
1719 "github.com/prometheus/prometheus/promql/parser"
@@ -1083,3 +1085,78 @@ func newEngineMock(mint, maxt int64, labelSets []labels.Labels) *engineMock {
10831085func newEngineMockWithExplicitPartition (mint , maxt int64 , labelSets , partitionLabelSets []labels.Labels ) * engineMock {
10841086 return & engineMock {minT : mint , maxT : maxt , labelSets : labelSets , partitionLabelSets : partitionLabelSets }
10851087}
1088+
1089+ func FuzzDistributedExecutionPreservesPartitionLabels (f * testing.F ) {
1090+ f .Add (int64 (0 ))
1091+ f .Fuzz (func (t * testing.T , seed int64 ) {
1092+ rnd := rand .New (rand .NewSource (seed ))
1093+
1094+ engines := []api.RemoteEngine {
1095+ newEngineMock (math .MinInt64 , math .MaxInt64 , []labels.Labels {labels .FromStrings ("region" , "east" )}),
1096+ newEngineMock (math .MinInt64 , math .MaxInt64 , []labels.Labels {labels .FromStrings ("region" , "west" )}),
1097+ }
1098+ optimizers := []Optimizer {
1099+ DistributedExecutionOptimizer {Endpoints : api .NewStaticEndpoints (engines )},
1100+ }
1101+ engineLabels := map [string ]struct {}{"region" : {}}
1102+
1103+ lbls := []labels.Labels {
1104+ labels .FromStrings ("__name__" , "http_requests_total" , "pod" , "nginx-1" , "region" , "east" ),
1105+ labels .FromStrings ("__name__" , "http_requests_total" , "pod" , "nginx-2" , "region" , "west" ),
1106+ }
1107+
1108+ psOpts := []promqlsmith.Option {
1109+ promqlsmith .WithEnableOffset (false ),
1110+ promqlsmith .WithEnableAtModifier (false ),
1111+ promqlsmith .WithEnabledAggrs ([]parser.ItemType {
1112+ parser .SUM , parser .MIN , parser .MAX , parser .AVG , parser .GROUP ,
1113+ parser .COUNT , parser .QUANTILE , parser .STDDEV , parser .STDVAR ,
1114+ parser .COUNT_VALUES , parser .TOPK , parser .BOTTOMK ,
1115+ }),
1116+ promqlsmith .WithEnableVectorMatching (true ),
1117+ }
1118+ ps := promqlsmith .New (rnd , lbls , psOpts ... )
1119+
1120+ opts := & query.Options {
1121+ Start : time .Unix (0 , 0 ),
1122+ End : time .Unix (3600 , 0 ),
1123+ Step : time .Minute ,
1124+ }
1125+ for range testRuns {
1126+ expr := ps .WalkRangeQuery ()
1127+ exprStr := expr .Pretty (0 )
1128+
1129+ parsed , err := parser .ParseExpr (exprStr )
1130+ if err != nil {
1131+ continue
1132+ }
1133+
1134+ plan , err := NewFromAST (parsed , opts , PlanOptions {})
1135+ if err != nil {
1136+ continue
1137+ }
1138+
1139+ optimizedPlan , _ := plan .Optimize (optimizers )
1140+ root := optimizedPlan .Root ()
1141+
1142+ Traverse (& root , func (node * Node ) {
1143+ remote , ok := (* node ).(RemoteExecution )
1144+ if ! ok {
1145+ return
1146+ }
1147+ if isAbsent (& remote .Query ) {
1148+ return
1149+ }
1150+ if ! preservesPartitionLabels (remote .Query , engineLabels ) {
1151+ t .Errorf (
1152+ "remote query does not preserve partition labels\n " +
1153+ " original: %s\n " +
1154+ " optimized: %s\n " +
1155+ " remote query: %s" ,
1156+ exprStr , root .String (), remote .Query .String (),
1157+ )
1158+ }
1159+ })
1160+ }
1161+ })
1162+ }
0 commit comments