2017-04-19 03:09:52 -05:00
package mysql
import (
2018-04-12 11:53:12 -05:00
"fmt"
2021-06-11 07:56:29 -05:00
"sync"
2017-04-19 03:09:52 -05:00
"testing"
2018-04-12 11:53:12 -05:00
"time"
2017-04-19 03:09:52 -05:00
2021-09-07 02:35:37 -05:00
"github.com/grafana/grafana-plugin-sdk-go/backend"
2019-09-24 13:50:49 -05:00
"github.com/grafana/grafana/pkg/infra/log"
2023-06-16 10:46:47 -05:00
"github.com/grafana/grafana/pkg/setting"
2021-10-26 06:18:17 -05:00
2021-06-11 07:56:29 -05:00
"github.com/stretchr/testify/require"
2017-04-19 03:09:52 -05:00
)
func TestMacroEngine ( t * testing . T ) {
2021-10-26 06:18:17 -05:00
engine := & mySQLMacroEngine {
2023-06-16 10:46:47 -05:00
logger : log . New ( "test" ) ,
userError : "inspect Grafana server log for details" ,
2021-10-26 06:18:17 -05:00
}
query := & backend . DataQuery { }
t . Run ( "Given a time range between 2018-04-12 00:00 and 2018-04-12 00:05" , func ( t * testing . T ) {
from := time . Date ( 2018 , 4 , 12 , 18 , 0 , 0 , 0 , time . UTC )
to := from . Add ( 5 * time . Minute )
timeRange := backend . TimeRange { From : from , To : to }
t . Run ( "interpolate __time function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__time(time_column)" )
require . Nil ( t , err )
require . Equal ( t , "select UNIX_TIMESTAMP(time_column) as time_sec" , sql )
} )
t . Run ( "interpolate __time function wrapped in aggregation" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select min($__time(time_column))" )
require . Nil ( t , err )
require . Equal ( t , "select min(UNIX_TIMESTAMP(time_column) as time_sec)" , sql )
} )
t . Run ( "interpolate __timeGroup function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "GROUP BY $__timeGroup(time_column,'5m')" )
require . Nil ( t , err )
sql2 , err := engine . Interpolate ( query , timeRange , "GROUP BY $__timeGroupAlias(time_column,'5m')" )
require . Nil ( t , err )
require . Equal ( t , "GROUP BY UNIX_TIMESTAMP(time_column) DIV 300 * 300" , sql )
require . Equal ( t , sql + " AS \"time\"" , sql2 )
} )
t . Run ( "interpolate __timeGroup function with spaces around arguments" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "GROUP BY $__timeGroup(time_column , '5m')" )
require . Nil ( t , err )
sql2 , err := engine . Interpolate ( query , timeRange , "GROUP BY $__timeGroupAlias(time_column , '5m')" )
require . Nil ( t , err )
require . Equal ( t , "GROUP BY UNIX_TIMESTAMP(time_column) DIV 300 * 300" , sql )
require . Equal ( t , sql + " AS \"time\"" , sql2 )
} )
t . Run ( "interpolate __timeFilter function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "WHERE $__timeFilter(time_column)" )
require . Nil ( t , err )
2017-04-19 03:09:52 -05:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , fmt . Sprintf ( "WHERE time_column BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)" , from . Unix ( ) , to . Unix ( ) ) , sql )
} )
2017-04-19 03:09:52 -05:00
2021-10-26 06:18:17 -05:00
t . Run ( "interpolate __timeFrom function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__timeFrom()" )
require . Nil ( t , err )
2017-04-19 03:09:52 -05:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , fmt . Sprintf ( "select FROM_UNIXTIME(%d)" , from . Unix ( ) ) , sql )
} )
2017-04-20 04:59:11 -05:00
2021-10-26 06:18:17 -05:00
t . Run ( "interpolate __timeTo function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__timeTo()" )
require . Nil ( t , err )
2017-04-20 04:59:11 -05:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , fmt . Sprintf ( "select FROM_UNIXTIME(%d)" , to . Unix ( ) ) , sql )
} )
2017-04-19 10:26:29 -05:00
2021-10-26 06:18:17 -05:00
t . Run ( "interpolate __unixEpochFilter function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__unixEpochFilter(time)" )
require . Nil ( t , err )
2017-08-08 07:38:03 -05:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , fmt . Sprintf ( "select time >= %d AND time <= %d" , from . Unix ( ) , to . Unix ( ) ) , sql )
} )
2017-08-08 07:38:03 -05:00
2021-10-26 06:18:17 -05:00
t . Run ( "interpolate __unixEpochNanoFilter function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__unixEpochNanoFilter(time)" )
require . Nil ( t , err )
2017-10-27 04:26:25 -05:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , fmt . Sprintf ( "select time >= %d AND time <= %d" , from . UnixNano ( ) , to . UnixNano ( ) ) , sql )
} )
2018-03-02 12:24:15 -06:00
2021-10-26 06:18:17 -05:00
t . Run ( "interpolate __unixEpochNanoFrom function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__unixEpochNanoFrom()" )
require . Nil ( t , err )
2018-03-02 12:24:15 -06:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , fmt . Sprintf ( "select %d" , from . UnixNano ( ) ) , sql )
} )
2018-03-02 12:24:15 -06:00
2021-10-26 06:18:17 -05:00
t . Run ( "interpolate __unixEpochNanoTo function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__unixEpochNanoTo()" )
require . Nil ( t , err )
2018-11-30 07:18:33 -06:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , fmt . Sprintf ( "select %d" , to . UnixNano ( ) ) , sql )
} )
2018-11-30 07:18:33 -06:00
2021-10-26 06:18:17 -05:00
t . Run ( "interpolate __unixEpochGroup function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "SELECT $__unixEpochGroup(time_column,'5m')" )
require . Nil ( t , err )
sql2 , err := engine . Interpolate ( query , timeRange , "SELECT $__unixEpochGroupAlias(time_column,'5m')" )
require . Nil ( t , err )
2018-11-30 07:18:33 -06:00
2021-10-26 06:18:17 -05:00
require . Equal ( t , "SELECT time_column DIV 300 * 300" , sql )
require . Equal ( t , sql + " AS \"time\"" , sql2 )
2019-09-24 13:50:49 -05:00
} )
2017-04-19 03:09:52 -05:00
} )
2021-10-26 06:18:17 -05:00
t . Run ( "Given a time range between 1960-02-01 07:00 and 1965-02-03 08:00" , func ( t * testing . T ) {
from := time . Date ( 1960 , 2 , 1 , 7 , 0 , 0 , 0 , time . UTC )
to := time . Date ( 1965 , 2 , 3 , 8 , 0 , 0 , 0 , time . UTC )
timeRange := backend . TimeRange {
From : from ,
To : to ,
}
t . Run ( "interpolate __timeFilter function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "WHERE $__timeFilter(time_column)" )
require . Nil ( t , err )
2022-02-22 13:06:04 -06:00
require . Equal ( t , fmt . Sprintf ( "WHERE time_column BETWEEN DATE_ADD(FROM_UNIXTIME(0), INTERVAL %d SECOND) AND FROM_UNIXTIME(%d)" , from . Unix ( ) , to . Unix ( ) ) , sql )
2021-10-26 06:18:17 -05:00
} )
t . Run ( "interpolate __unixEpochFilter function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__unixEpochFilter(time)" )
require . Nil ( t , err )
require . Equal ( t , fmt . Sprintf ( "select time >= %d AND time <= %d" , from . Unix ( ) , to . Unix ( ) ) , sql )
} )
} )
t . Run ( "Given a time range between 1960-02-01 07:00 and 1980-02-03 08:00" , func ( t * testing . T ) {
from := time . Date ( 1960 , 2 , 1 , 7 , 0 , 0 , 0 , time . UTC )
to := time . Date ( 1980 , 2 , 3 , 8 , 0 , 0 , 0 , time . UTC )
timeRange := backend . TimeRange {
From : from ,
To : to ,
}
t . Run ( "interpolate __timeFilter function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "WHERE $__timeFilter(time_column)" )
require . Nil ( t , err )
2022-02-22 13:06:04 -06:00
require . Equal ( t , fmt . Sprintf ( "WHERE time_column BETWEEN DATE_ADD(FROM_UNIXTIME(0), INTERVAL %d SECOND) AND FROM_UNIXTIME(%d)" , from . Unix ( ) , to . Unix ( ) ) , sql )
2021-10-26 06:18:17 -05:00
} )
t . Run ( "interpolate __unixEpochFilter function" , func ( t * testing . T ) {
sql , err := engine . Interpolate ( query , timeRange , "select $__unixEpochFilter(time)" )
require . Nil ( t , err )
require . Equal ( t , fmt . Sprintf ( "select time >= %d AND time <= %d" , from . Unix ( ) , to . Unix ( ) ) , sql )
} )
} )
t . Run ( "Given queries that contains unallowed user functions" , func ( t * testing . T ) {
tcs := [ ] string {
"select \nSESSION_USER(), abc" ,
"SELECT session_User( ) " ,
"SELECT session_User( )\n" ,
"SELECT current_user" ,
"SELECT current_USER" ,
"SELECT current_user()" ,
"SELECT Current_User()" ,
"SELECT current_user( )" ,
"SELECT current_user(\t )" ,
"SELECT user()" ,
"SELECT USER()" ,
"SELECT SYSTEM_USER()" ,
"SELECT System_User()" ,
"SELECT System_User( )" ,
"SELECT System_User(\t \t)" ,
"SHOW \t grants" ,
" show Grants\n" ,
"show grants;" ,
}
for _ , tc := range tcs {
_ , err := engine . Interpolate ( & backend . DataQuery { } , backend . TimeRange { } , tc )
require . Equal ( t , "invalid query - inspect Grafana server log for details" , err . Error ( ) )
}
} )
2017-04-19 03:09:52 -05:00
}
2021-06-11 07:56:29 -05:00
func TestMacroEngineConcurrency ( t * testing . T ) {
2023-06-16 10:46:47 -05:00
engine := newMysqlMacroEngine ( log . New ( "test" ) , setting . NewCfg ( ) )
2021-09-07 02:35:37 -05:00
query1 := backend . DataQuery {
JSON : [ ] byte { } ,
2021-06-11 07:56:29 -05:00
}
2021-09-07 02:35:37 -05:00
query2 := backend . DataQuery {
JSON : [ ] byte { } ,
2021-06-11 07:56:29 -05:00
}
from := time . Date ( 2018 , 4 , 12 , 18 , 0 , 0 , 0 , time . UTC )
to := from . Add ( 5 * time . Minute )
2021-09-07 02:35:37 -05:00
timeRange := backend . TimeRange { From : from , To : to }
2021-06-11 07:56:29 -05:00
var wg sync . WaitGroup
wg . Add ( 2 )
2021-09-07 02:35:37 -05:00
go func ( query backend . DataQuery ) {
2021-06-11 07:56:29 -05:00
defer wg . Done ( )
2021-09-07 02:35:37 -05:00
_ , err := engine . Interpolate ( & query , timeRange , "SELECT $__timeGroup(time_column,'5m')" )
2021-06-11 07:56:29 -05:00
require . NoError ( t , err )
} ( query1 )
2021-09-07 02:35:37 -05:00
go func ( query backend . DataQuery ) {
_ , err := engine . Interpolate ( & query , timeRange , "SELECT $__timeGroup(time_column,'5m')" )
2021-06-11 07:56:29 -05:00
require . NoError ( t , err )
defer wg . Done ( )
} ( query2 )
wg . Wait ( )
}