2020-03-06 22:05:03 +00:00
package reads
import (
"fmt"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/models"
"github.com/influxdata/influxdb/storage"
2020-03-10 14:31:23 +00:00
"github.com/influxdata/influxdb/storage/reads/datatypes"
2020-03-06 22:05:03 +00:00
"github.com/influxdata/influxql"
)
func TestPlannerCondition ( t * testing . T ) {
sqry := & floatIterator {
Points : [ ] storage . SeriesCursorRow {
{
Name : [ ] byte ( "org_bucket" ) , Tags : models . Tags {
{ Key : models . MeasurementTagKeyBytes , Value : [ ] byte ( "cpu" ) } ,
{ Key : [ ] byte ( "host" ) , Value : [ ] byte ( "host1" ) } ,
{ Key : models . FieldKeyTagKeyBytes , Value : [ ] byte ( "system" ) } ,
} ,
} ,
{
Name : [ ] byte ( "org_bucket" ) , Tags : models . Tags {
{ Key : models . MeasurementTagKeyBytes , Value : [ ] byte ( "mem" ) } ,
{ Key : [ ] byte ( "host" ) , Value : [ ] byte ( "host1" ) } ,
{ Key : models . FieldKeyTagKeyBytes , Value : [ ] byte ( "user" ) } ,
} ,
} ,
} ,
}
2020-03-10 14:31:23 +00:00
expr := fmt . Sprintf ( ` (%[1]s = 'cpu' AND (%[2]s = 'user' OR %[2]s = 'system')) OR (%[1]s = 'mem' AND "_value" = 0) ` , datatypes . MeasurementKey , datatypes . FieldKey )
2020-03-06 22:05:03 +00:00
cond , err := parseExpr ( expr )
if err != nil {
t . Fatal ( "ParseExpr" , err )
}
p := & indexSeriesCursor {
sqry : sqry ,
cond : cond ,
hasValueExpr : true ,
}
var keys [ ] string
// In first row, value cond should reduce to "true" and be nil.
row := p . Next ( )
if row . ValueCond != nil {
t . Errorf ( "expected nil ValueCond, got %s" , row . ValueCond )
}
keys = append ( keys , string ( models . MakeKey ( row . Name , row . Tags ) ) )
// In second row, the value condition applies.
row = p . Next ( )
if want , got := "_value = 0" , row . ValueCond . String ( ) ; ! cmp . Equal ( want , got ) {
t . Errorf ( "unexpected, %s" , cmp . Diff ( want , got ) )
}
keys = append ( keys , string ( models . MakeKey ( row . Name , row . Tags ) ) )
expr = ` org_bucket , % [ 2 ] s = system , % [ 1 ] s = cpu , host = host1
org_bucket , % [ 2 ] s = user , % [ 1 ] s = mem , host = host1 `
2020-03-10 14:31:23 +00:00
expr = fmt . Sprintf ( expr , datatypes . MeasurementKey , datatypes . FieldKey )
2020-03-06 22:05:03 +00:00
exp := strings . Split ( expr , "\n" )
if ! cmp . Equal ( exp , keys ) {
t . Errorf ( "unexpected, %s" , cmp . Diff ( exp , keys ) )
}
}
// parseExpr parses the given InfluxQL expression and rewrites
// _measurement and _field vars as their storage tag key equivalents.
func parseExpr ( expr string ) ( influxql . Expr , error ) {
e , err := influxql . ParseExpr ( expr )
if err != nil {
return nil , err
}
e = influxql . RewriteExpr ( e , func ( expr influxql . Expr ) influxql . Expr {
if vr , ok := expr . ( * influxql . VarRef ) ; ok {
switch vr . Val {
2020-03-10 14:31:23 +00:00
case datatypes . MeasurementKey :
2020-03-06 22:05:03 +00:00
vr . Val = models . MeasurementTagKey
2020-03-10 14:31:23 +00:00
case datatypes . FieldKey :
2020-03-06 22:05:03 +00:00
vr . Val = models . FieldKeyTagKey
}
}
return expr
} )
return e , nil
}
// floatIterator is a represents an iterator that reads from a slice.
type floatIterator struct {
Points [ ] storage . SeriesCursorRow
}
// Close is a no-op closer for testing.
func ( itr * floatIterator ) Close ( ) {
}
func ( itr * floatIterator ) Next ( ) ( * storage . SeriesCursorRow , error ) {
if len ( itr . Points ) == 0 {
return nil , nil
}
v := & itr . Points [ 0 ]
itr . Points = itr . Points [ 1 : ]
return v , nil
}