2021-09-01 09:38:56 -05:00
//go:build integration
2020-07-10 09:09:21 -05:00
// +build integration
2017-10-10 08:19:14 -05:00
package postgres
import (
pkg/tsdb/postgres/postgres_test.go: pass context.Background() instead of nil
See,
$ gometalinter --vendor --disable-all --enable=megacheck --disable=gotype --deadline 6m ./...
pkg/tsdb/postgres/postgres_test.go:120:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:200:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:257:34:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:282:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:336:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:363:32:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:453:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:475:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:497:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:519:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:541:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:563:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:585:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:607:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:629:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:652:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:677:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:738:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:761:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:787:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:817:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:847:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:877:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:905:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
pkg/tsdb/postgres/postgres_test.go:933:33:warning: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (SA1012) (megacheck)
2018-10-03 03:32:02 -05:00
"context"
2018-03-22 09:27:12 -05:00
"fmt"
"math/rand"
2018-04-10 04:08:30 -05:00
"strings"
2017-10-10 08:19:14 -05:00
"testing"
"time"
2021-09-07 02:35:37 -05:00
"github.com/grafana/grafana-plugin-sdk-go/backend"
2021-05-05 09:46:07 -05:00
"github.com/grafana/grafana-plugin-sdk-go/data"
2018-04-10 04:08:30 -05:00
"github.com/grafana/grafana/pkg/services/sqlstore"
2017-10-10 08:19:14 -05:00
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
2021-02-23 15:10:55 -06:00
"github.com/grafana/grafana/pkg/setting"
2019-09-10 14:50:04 -05:00
"github.com/grafana/grafana/pkg/tsdb/sqleng"
2020-07-09 07:57:09 -05:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2020-04-01 08:57:21 -05:00
"xorm.io/xorm"
2019-09-10 14:50:04 -05:00
2017-10-10 08:19:14 -05:00
_ "github.com/lib/pq"
)
2020-07-09 07:57:09 -05:00
// Test generateConnectionString.
func TestGenerateConnectionString ( t * testing . T ) {
2021-02-23 15:10:55 -06:00
cfg := setting . NewCfg ( )
cfg . DataPath = t . TempDir ( )
2020-07-09 07:57:09 -05:00
testCases := [ ] struct {
2021-02-23 15:10:55 -06:00
desc string
host string
user string
password string
database string
tlsSettings tlsSettings
expConnStr string
expErr string
uid string
2020-07-09 07:57:09 -05:00
} {
{
2021-02-23 15:10:55 -06:00
desc : "Unix socket host" ,
host : "/var/run/postgresql" ,
user : "user" ,
password : "password" ,
database : "database" ,
tlsSettings : tlsSettings { Mode : "verify-full" } ,
expConnStr : "user='user' password='password' host='/var/run/postgresql' dbname='database' sslmode='verify-full'" ,
2020-07-09 07:57:09 -05:00
} ,
{
2021-02-23 15:10:55 -06:00
desc : "TCP host" ,
host : "host" ,
user : "user" ,
password : "password" ,
database : "database" ,
tlsSettings : tlsSettings { Mode : "verify-full" } ,
expConnStr : "user='user' password='password' host='host' dbname='database' sslmode='verify-full'" ,
2020-07-09 07:57:09 -05:00
} ,
{
2021-02-23 15:10:55 -06:00
desc : "TCP/port host" ,
host : "host:1234" ,
user : "user" ,
password : "password" ,
database : "database" ,
tlsSettings : tlsSettings { Mode : "verify-full" } ,
expConnStr : "user='user' password='password' host='host' dbname='database' port=1234 sslmode='verify-full'" ,
2020-07-09 07:57:09 -05:00
} ,
2022-03-31 05:45:49 -05:00
{
desc : "Ipv6 host" ,
host : "[::1]" ,
user : "user" ,
password : "password" ,
database : "database" ,
tlsSettings : tlsSettings { Mode : "verify-full" } ,
2022-04-12 05:11:11 -05:00
expConnStr : "user='user' password='password' host='::1' dbname='database' sslmode='verify-full'" ,
2022-03-31 05:45:49 -05:00
} ,
{
desc : "Ipv6/port host" ,
host : "[::1]:1234" ,
user : "user" ,
password : "password" ,
database : "database" ,
tlsSettings : tlsSettings { Mode : "verify-full" } ,
2022-04-12 05:11:11 -05:00
expConnStr : "user='user' password='password' host='::1' dbname='database' port=1234 sslmode='verify-full'" ,
2022-03-31 05:45:49 -05:00
} ,
2020-07-09 07:57:09 -05:00
{
2021-02-23 15:10:55 -06:00
desc : "Invalid port" ,
host : "host:invalid" ,
user : "user" ,
database : "database" ,
tlsSettings : tlsSettings { } ,
expErr : "invalid port in host specifier" ,
2020-07-09 07:57:09 -05:00
} ,
{
2021-02-23 15:10:55 -06:00
desc : "Password with single quote and backslash" ,
host : "host" ,
user : "user" ,
password : ` p'\assword ` ,
database : "database" ,
tlsSettings : tlsSettings { Mode : "verify-full" } ,
expConnStr : ` user='user' password='p\'\\assword' host='host' dbname='database' sslmode='verify-full' ` ,
2020-07-09 07:57:09 -05:00
} ,
2022-03-31 05:45:49 -05:00
{
desc : "User/DB with single quote and backslash" ,
host : "host" ,
user : ` u'\ser ` ,
password : ` password ` ,
database : ` d'\atabase ` ,
tlsSettings : tlsSettings { Mode : "verify-full" } ,
expConnStr : ` user='u\'\\ser' password='password' host='host' dbname='d\'\\atabase' sslmode='verify-full' ` ,
} ,
2020-07-09 07:57:09 -05:00
{
2021-02-23 15:10:55 -06:00
desc : "Custom TLS mode disabled" ,
host : "host" ,
user : "user" ,
password : "password" ,
database : "database" ,
tlsSettings : tlsSettings { Mode : "disable" } ,
expConnStr : "user='user' password='password' host='host' dbname='database' sslmode='disable'" ,
} ,
{
desc : "Custom TLS mode verify-full with certificate files" ,
host : "host" ,
user : "user" ,
password : "password" ,
database : "database" ,
tlsSettings : tlsSettings {
Mode : "verify-full" ,
RootCertFile : "i/am/coding/ca.crt" ,
CertFile : "i/am/coding/client.crt" ,
CertKeyFile : "i/am/coding/client.key" ,
} ,
expConnStr : "user='user' password='password' host='host' dbname='database' sslmode='verify-full' " +
"sslrootcert='i/am/coding/ca.crt' sslcert='i/am/coding/client.crt' sslkey='i/am/coding/client.key'" ,
2020-07-09 07:57:09 -05:00
} ,
}
for _ , tt := range testCases {
t . Run ( tt . desc , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
svc := Service {
2021-02-23 15:10:55 -06:00
tlsManager : & tlsTestManager { settings : tt . tlsSettings } ,
2020-07-09 07:57:09 -05:00
}
2021-02-23 15:10:55 -06:00
2021-09-07 02:35:37 -05:00
ds := sqleng . DataSourceInfo {
URL : tt . host ,
User : tt . user ,
DecryptedSecureJSONData : map [ string ] string { "password" : tt . password } ,
Database : tt . database ,
UID : tt . uid ,
2020-07-09 07:57:09 -05:00
}
2021-02-23 15:10:55 -06:00
connStr , err := svc . generateConnectionString ( ds )
2020-07-09 07:57:09 -05:00
if tt . expErr == "" {
require . NoError ( t , err , tt . desc )
2021-02-23 15:10:55 -06:00
assert . Equal ( t , tt . expConnStr , connStr )
2020-07-09 07:57:09 -05:00
} else {
require . Error ( t , err , tt . desc )
assert . True ( t , strings . HasPrefix ( err . Error ( ) , tt . expErr ) ,
fmt . Sprintf ( "%s: %q doesn't start with %q" , tt . desc , err , tt . expErr ) )
}
} )
}
}
2018-04-16 04:06:23 -05:00
// To run this test, set runPostgresTests=true
2021-07-13 02:36:24 -05:00
// Or from the commandline: GRAFANA_TEST_DB=postgres go test -tags=integration -v ./pkg/tsdb/postgres
2018-04-16 04:06:23 -05:00
// The tests require a PostgreSQL db named grafanadstest and a user/password grafanatest/grafanatest!
2018-03-22 09:27:12 -05:00
// Use the docker/blocks/postgres_tests/docker-compose.yaml to spin up a
// preconfigured Postgres server suitable for running these tests.
2018-07-26 11:10:17 -05:00
// There is also a datasource and dashboard provisioned by devenv scripts that you can
2020-06-01 10:11:25 -05:00
// use to verify that the generated data are visualized as expected, see
2018-07-26 11:10:17 -05:00
// devenv/README.md for setup instructions.
2017-10-10 08:19:14 -05:00
func TestPostgres ( t * testing . T ) {
2018-07-21 13:00:26 -05:00
// change to true to run the PostgreSQL tests
2021-05-05 09:46:07 -05:00
const runPostgresTests = false
2018-04-10 04:08:30 -05:00
2021-05-05 09:46:07 -05:00
if ! ( sqlstore . IsTestDbPostgres ( ) || runPostgresTests ) {
2018-04-10 04:08:30 -05:00
t . Skip ( )
}
2021-01-22 09:34:53 -06:00
x := InitPostgresTestDB ( t )
2017-10-10 08:19:14 -05:00
2021-01-22 09:34:53 -06:00
origXormEngine := sqleng . NewXormEngine
origInterpolate := sqleng . Interpolate
t . Cleanup ( func ( ) {
sqleng . NewXormEngine = origXormEngine
sqleng . Interpolate = origInterpolate
} )
sqleng . NewXormEngine = func ( d , c string ) ( * xorm . Engine , error ) {
return x , nil
}
2021-09-07 02:35:37 -05:00
sqleng . Interpolate = func ( query backend . DataQuery , timeRange backend . TimeRange , timeInterval string , sql string ) ( string , error ) {
2021-01-22 09:34:53 -06:00
return sql , nil
}
2017-10-10 08:19:14 -05:00
2021-02-23 15:10:55 -06:00
cfg := setting . NewCfg ( )
cfg . DataPath = t . TempDir ( )
2021-09-07 02:35:37 -05:00
jsonData := sqleng . JsonData {
MaxOpenConns : 0 ,
MaxIdleConns : 2 ,
ConnMaxLifetime : 14400 ,
Timescaledb : false ,
ConfigurationMethod : "file-path" ,
2021-02-23 15:10:55 -06:00
}
2021-09-07 02:35:37 -05:00
dsInfo := sqleng . DataSourceInfo {
JsonData : jsonData ,
DecryptedSecureJSONData : map [ string ] string { } ,
}
config := sqleng . DataPluginConfiguration {
DriverName : "postgres" ,
ConnectionString : "" ,
DSInfo : dsInfo ,
MetricColumnTypes : [ ] string { "UNKNOWN" , "TEXT" , "VARCHAR" , "CHAR" } ,
2021-09-13 08:27:51 -05:00
RowLimit : 1000000 ,
2021-09-07 02:35:37 -05:00
}
queryResultTransformer := postgresQueryResultTransformer {
log : logger ,
}
exe , err := sqleng . NewQueryDataHandler ( config , & queryResultTransformer , newPostgresMacroEngine ( dsInfo . JsonData . Timescaledb ) ,
logger )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
sess := x . NewSession ( )
t . Cleanup ( sess . Close )
fromStart := time . Date ( 2018 , 3 , 15 , 13 , 0 , 0 , 0 , time . UTC ) . In ( time . Local )
t . Run ( "Given a table with different native data types" , func ( t * testing . T ) {
sql := `
DROP TABLE IF EXISTS postgres_types ;
CREATE TABLE postgres_types (
c00_smallint smallint ,
c01_integer integer ,
c02_bigint bigint ,
c03_real real ,
c04_double double precision ,
c05_decimal decimal ( 10 , 2 ) ,
c06_numeric numeric ( 10 , 2 ) ,
c07_char char ( 10 ) ,
c08_varchar varchar ( 10 ) ,
c09_text text ,
c10_timestamp timestamp without time zone ,
c11_timestamptz timestamp with time zone ,
c12_date date ,
c13_time time without time zone ,
c14_timetz time with time zone ,
2021-05-05 09:46:07 -05:00
time date ,
2021-07-13 02:36:24 -05:00
c15_interval interval ,
c16_smallint smallint
2021-01-22 09:34:53 -06:00
) ;
`
_ , err := sess . Exec ( sql )
require . NoError ( t , err )
sql = `
INSERT INTO postgres_types VALUES (
1 , 2 , 3 ,
4.5 , 6.7 , 1.1 , 1.2 ,
' char10 ',' varchar10 ',' text ' ,
2021-07-13 02:36:24 -05:00
now ( ) , now ( ) , now ( ) , now ( ) , now ( ) , now ( ) , ' 15 m ' : : interval ,
null
2021-01-22 09:34:53 -06:00
) ;
`
_ , err = sess . Exec ( sql )
require . NoError ( t , err )
t . Run ( "When doing a table query should map Postgres column types to Go types" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
2021-01-22 09:34:53 -06:00
"rawSql" : "SELECT * FROM postgres_types" ,
2021-09-07 02:35:37 -05:00
"format" : "table"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2021-01-22 09:34:53 -06:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Len ( t , frames , 1 )
2021-07-13 02:36:24 -05:00
require . Len ( t , frames [ 0 ] . Fields , 18 )
2021-05-05 09:46:07 -05:00
2021-07-13 02:36:24 -05:00
require . Equal ( t , int16 ( 1 ) , * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * int16 ) )
2021-05-05 09:46:07 -05:00
require . Equal ( t , int32 ( 2 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 0 ) . ( * int32 ) )
require . Equal ( t , int64 ( 3 ) , * frames [ 0 ] . Fields [ 2 ] . At ( 0 ) . ( * int64 ) )
2021-01-22 09:34:53 -06:00
2021-05-05 09:46:07 -05:00
require . Equal ( t , float64 ( 4.5 ) , * frames [ 0 ] . Fields [ 3 ] . At ( 0 ) . ( * float64 ) )
require . Equal ( t , float64 ( 6.7 ) , * frames [ 0 ] . Fields [ 4 ] . At ( 0 ) . ( * float64 ) )
require . Equal ( t , float64 ( 1.1 ) , * frames [ 0 ] . Fields [ 5 ] . At ( 0 ) . ( * float64 ) )
require . Equal ( t , float64 ( 1.2 ) , * frames [ 0 ] . Fields [ 6 ] . At ( 0 ) . ( * float64 ) )
2021-01-22 09:34:53 -06:00
2021-05-05 09:46:07 -05:00
require . Equal ( t , "char10 " , * frames [ 0 ] . Fields [ 7 ] . At ( 0 ) . ( * string ) )
require . Equal ( t , "varchar10" , * frames [ 0 ] . Fields [ 8 ] . At ( 0 ) . ( * string ) )
require . Equal ( t , "text" , * frames [ 0 ] . Fields [ 9 ] . At ( 0 ) . ( * string ) )
2021-01-22 09:34:53 -06:00
2021-05-05 09:46:07 -05:00
_ , ok := frames [ 0 ] . Fields [ 10 ] . At ( 0 ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . True ( t , ok )
2021-05-05 09:46:07 -05:00
_ , ok = frames [ 0 ] . Fields [ 11 ] . At ( 0 ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . True ( t , ok )
2021-05-05 09:46:07 -05:00
_ , ok = frames [ 0 ] . Fields [ 12 ] . At ( 0 ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . True ( t , ok )
2021-05-05 09:46:07 -05:00
_ , ok = frames [ 0 ] . Fields [ 13 ] . At ( 0 ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . True ( t , ok )
2021-05-05 09:46:07 -05:00
_ , ok = frames [ 0 ] . Fields [ 14 ] . At ( 0 ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . True ( t , ok )
2021-05-05 09:46:07 -05:00
_ , ok = frames [ 0 ] . Fields [ 15 ] . At ( 0 ) . ( * time . Time )
require . True ( t , ok )
require . Equal ( t , "00:15:00" , * frames [ 0 ] . Fields [ 16 ] . At ( 0 ) . ( * string ) )
2021-07-13 02:36:24 -05:00
require . Nil ( t , frames [ 0 ] . Fields [ 17 ] . At ( 0 ) )
2018-07-26 11:10:17 -05:00
} )
2021-01-22 09:34:53 -06:00
} )
2018-07-26 11:10:17 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "Given a table with metrics that lacks data for some series " , func ( t * testing . T ) {
sql := `
DROP TABLE IF EXISTS metric ;
CREATE TABLE metric (
time timestamp ,
value integer
)
2018-03-22 09:27:12 -05:00
`
2021-01-22 09:34:53 -06:00
_ , err := sess . Exec ( sql )
require . NoError ( t , err )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
type metric struct {
Time time . Time
Value int64
}
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
series := [ ] * metric { }
firstRange := genTimeRangeByInterval ( fromStart , 10 * time . Minute , 10 * time . Second )
secondRange := genTimeRangeByInterval ( fromStart . Add ( 20 * time . Minute ) , 10 * time . Minute , 10 * time . Second )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
for _ , t := range firstRange {
series = append ( series , & metric {
Time : t ,
Value : 15 ,
} )
}
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
for _ , t := range secondRange {
series = append ( series , & metric {
Time : t ,
Value : 20 ,
2018-03-22 09:27:12 -05:00
} )
2021-01-22 09:34:53 -06:00
}
_ , err = sess . InsertMulti ( series )
require . NoError ( t , err )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query using timeGroup" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT $__timeGroup(time, '5m') AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2021-01-22 09:34:53 -06:00
} ,
} ,
2018-03-22 09:27:12 -05:00
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Len ( t , frames , 1 )
require . Equal ( t , 4 , frames [ 0 ] . Fields [ 0 ] . Len ( ) )
2021-01-22 09:34:53 -06:00
// without fill this should result in 4 buckets
dt := fromStart
for i := 0 ; i < 2 ; i ++ {
2021-05-05 09:46:07 -05:00
aValue := * frames [ 0 ] . Fields [ 1 ] . At ( i ) . ( * float64 )
aTime := * frames [ 0 ] . Fields [ 0 ] . At ( i ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . Equal ( t , float64 ( 15 ) , aValue )
require . Equal ( t , dt , aTime )
dt = dt . Add ( 5 * time . Minute )
2018-03-22 09:27:12 -05:00
}
2021-01-22 09:34:53 -06:00
// adjust for 10 minute gap between first and second set of points
dt = dt . Add ( 10 * time . Minute )
for i := 2 ; i < 4 ; i ++ {
2021-05-05 09:46:07 -05:00
aValue := * frames [ 0 ] . Fields [ 1 ] . At ( i ) . ( * float64 )
aTime := * frames [ 0 ] . Fields [ 0 ] . At ( i ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . Equal ( t , float64 ( 20 ) , aValue )
require . Equal ( t , dt , aTime )
dt = dt . Add ( 5 * time . Minute )
2018-03-22 09:27:12 -05:00
}
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query using timeGroup and $__interval" , func ( t * testing . T ) {
mockInterpolate := sqleng . Interpolate
sqleng . Interpolate = origInterpolate
t . Cleanup ( func ( ) {
sqleng . Interpolate = mockInterpolate
2018-09-13 09:51:00 -05:00
} )
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
2021-01-22 09:34:53 -06:00
"rawSql" : "SELECT $__timeGroup(time, $__interval) AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1" ,
2021-09-07 02:35:37 -05:00
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : fromStart ,
To : fromStart . Add ( 30 * time . Minute ) ,
} ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
require . Equal ( t ,
"SELECT floor(extract(epoch from time)/60)*60 AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1" ,
2021-05-05 09:46:07 -05:00
frames [ 0 ] . Meta . ExecutedQueryString )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query using timeGroup with NULL fill enabled" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
2021-01-22 09:34:53 -06:00
"rawSql" : "SELECT $__timeGroup(time, '5m', NULL) AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1" ,
2021-09-07 02:35:37 -05:00
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : fromStart ,
To : fromStart . Add ( 34 * time . Minute ) ,
} ,
2021-01-22 09:34:53 -06:00
} ,
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 7 , frames [ 0 ] . Fields [ 0 ] . Len ( ) )
2018-07-01 08:55:46 -05:00
2021-01-22 09:34:53 -06:00
dt := fromStart
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
for i := 0 ; i < 2 ; i ++ {
2021-05-05 09:46:07 -05:00
aValue := * frames [ 0 ] . Fields [ 1 ] . At ( i ) . ( * float64 )
aTime := * frames [ 0 ] . Fields [ 0 ] . At ( i ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . Equal ( t , float64 ( 15 ) , aValue )
2021-05-05 09:46:07 -05:00
require . True ( t , aTime . Equal ( dt ) )
2021-01-22 09:34:53 -06:00
dt = dt . Add ( 5 * time . Minute )
}
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
// check for NULL values inserted by fill
2021-05-05 09:46:07 -05:00
require . Nil ( t , frames [ 0 ] . Fields [ 1 ] . At ( 2 ) )
require . Nil ( t , frames [ 0 ] . Fields [ 1 ] . At ( 3 ) )
2021-01-22 09:34:53 -06:00
// adjust for 10 minute gap between first and second set of points
dt = dt . Add ( 10 * time . Minute )
for i := 4 ; i < 6 ; i ++ {
2021-05-05 09:46:07 -05:00
aValue := * frames [ 0 ] . Fields [ 1 ] . At ( i ) . ( * float64 )
aTime := * frames [ 0 ] . Fields [ 0 ] . At ( i ) . ( * time . Time )
2021-01-22 09:34:53 -06:00
require . Equal ( t , float64 ( 20 ) , aValue )
2021-05-05 09:46:07 -05:00
require . True ( t , aTime . Equal ( dt ) )
2021-01-22 09:34:53 -06:00
dt = dt . Add ( 5 * time . Minute )
}
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
// check for NULL values inserted by fill
2021-05-05 09:46:07 -05:00
require . Nil ( t , frames [ 0 ] . Fields [ 1 ] . At ( 6 ) )
2018-03-22 09:27:12 -05:00
} )
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query using timeGroup with value fill enabled" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-07-30 04:04:04 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
2021-01-22 09:34:53 -06:00
"rawSql" : "SELECT $__timeGroup(time, '5m', 1.5) AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1" ,
2021-09-07 02:35:37 -05:00
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : fromStart ,
To : fromStart . Add ( 34 * time . Minute ) ,
} ,
2018-07-30 04:04:04 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-07-30 04:04:04 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 1.5 , * frames [ 0 ] . Fields [ 1 ] . At ( 3 ) . ( * float64 ) )
2018-07-30 04:04:04 -05:00
} )
2021-01-22 09:34:53 -06:00
} )
2018-07-30 04:04:04 -05:00
2021-07-29 01:38:41 -05:00
t . Run ( "Given a table with one data point" , func ( t * testing . T ) {
type metric struct {
Time time . Time
Value int64
}
startTime := time . Now ( ) . UTC ( ) . Add ( - time . Minute * 5 )
series := [ ] * metric {
{
Time : startTime ,
Value : 33 ,
} ,
}
_ , err = sess . InsertMulti ( series )
require . NoError ( t , err )
t . Run ( "querying with time group with default value" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-07-29 01:38:41 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
2021-07-29 01:38:41 -05:00
"rawSql" : "WITH data AS (SELECT now()-'3m'::interval AS ts, 42 AS n) SELECT $__timeGroup(ts, '1m', 0), n FROM data" ,
2021-09-07 02:35:37 -05:00
"format" : "time_series"
} ` ) ,
2021-07-29 01:38:41 -05:00
RefID : "A" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : startTime ,
To : startTime . Add ( 5 * time . Minute ) ,
} ,
2021-07-29 01:38:41 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-07-29 01:38:41 -05:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-07-29 01:38:41 -05:00
require . NoError ( t , queryResult . Error )
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-07-29 01:38:41 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , "Time" , frames [ 0 ] . Fields [ 0 ] . Name )
require . Equal ( t , "n" , frames [ 0 ] . Fields [ 1 ] . Name )
require . Equal ( t , float64 ( 0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 0 ) . ( * float64 ) )
require . Equal ( t , float64 ( 0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 1 ) . ( * float64 ) )
require . Equal ( t , float64 ( 42 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 2 ) . ( * float64 ) )
require . Equal ( t , float64 ( 0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 3 ) . ( * float64 ) )
require . Equal ( t , float64 ( 0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 4 ) . ( * float64 ) )
require . Equal ( t , float64 ( 0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 5 ) . ( * float64 ) )
} )
} )
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query using timeGroup with previous fill enabled" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
2021-01-22 09:34:53 -06:00
"rawSql" : "SELECT $__timeGroup(time, '5m', previous), avg(value) as value FROM metric GROUP BY 1 ORDER BY 1" ,
2021-09-07 02:35:37 -05:00
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : fromStart ,
To : fromStart . Add ( 34 * time . Minute ) ,
} ,
2021-01-22 09:34:53 -06:00
} ,
} ,
}
2017-10-10 08:19:14 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2017-10-10 08:19:14 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , float64 ( 15.0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 2 ) . ( * float64 ) )
require . Equal ( t , float64 ( 15.0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 3 ) . ( * float64 ) )
require . Equal ( t , float64 ( 20.0 ) , * frames [ 0 ] . Fields [ 1 ] . At ( 6 ) . ( * float64 ) )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "Given a table with metrics having multiple values and measurements" , func ( t * testing . T ) {
type metric_values struct {
Time time . Time
TimeInt64 int64 ` xorm:"bigint 'timeInt64' not null" `
TimeInt64Nullable * int64 ` xorm:"bigint 'timeInt64Nullable' null" `
TimeFloat64 float64 ` xorm:"double 'timeFloat64' not null" `
TimeFloat64Nullable * float64 ` xorm:"double 'timeFloat64Nullable' null" `
TimeInt32 int32 ` xorm:"int(11) 'timeInt32' not null" `
TimeInt32Nullable * int32 ` xorm:"int(11) 'timeInt32Nullable' null" `
TimeFloat32 float32 ` xorm:"double 'timeFloat32' not null" `
TimeFloat32Nullable * float32 ` xorm:"double 'timeFloat32Nullable' null" `
Measurement string
ValueOne int64 ` xorm:"integer 'valueOne'" `
ValueTwo int64 ` xorm:"integer 'valueTwo'" `
}
2018-04-10 04:03:58 -05:00
2021-02-23 15:10:55 -06:00
if exists , err := sess . IsTableExist ( metric_values { } ) ; err != nil || exists {
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-02-23 15:10:55 -06:00
err := sess . DropTable ( metric_values { } )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
}
err := sess . CreateTable ( metric_values { } )
require . NoError ( t , err )
rand . Seed ( time . Now ( ) . Unix ( ) )
rnd := func ( min , max int64 ) int64 {
return rand . Int63n ( max - min ) + min
}
var tInitial time . Time
2018-04-10 04:03:58 -05:00
2021-01-22 09:34:53 -06:00
series := [ ] * metric_values { }
for i , t := range genTimeRangeByInterval ( fromStart . Add ( - 30 * time . Minute ) , 90 * time . Minute , 5 * time . Minute ) {
if i == 0 {
tInitial = t
2018-04-10 04:03:58 -05:00
}
2021-01-22 09:34:53 -06:00
tSeconds := t . Unix ( )
tSecondsInt32 := int32 ( tSeconds )
tSecondsFloat32 := float32 ( tSeconds )
tMilliseconds := tSeconds * 1e3
tMillisecondsFloat := float64 ( tMilliseconds )
first := metric_values {
Time : t ,
TimeInt64 : tMilliseconds ,
TimeInt64Nullable : & ( tMilliseconds ) ,
TimeFloat64 : tMillisecondsFloat ,
TimeFloat64Nullable : & tMillisecondsFloat ,
TimeInt32 : tSecondsInt32 ,
TimeInt32Nullable : & tSecondsInt32 ,
TimeFloat32 : tSecondsFloat32 ,
TimeFloat32Nullable : & tSecondsFloat32 ,
Measurement : "Metric A" ,
ValueOne : rnd ( 0 , 100 ) ,
ValueTwo : rnd ( 0 , 100 ) ,
}
second := first
second . Measurement = "Metric B"
second . ValueOne = rnd ( 0 , 100 )
second . ValueTwo = rnd ( 0 , 100 )
series = append ( series , & first )
series = append ( series , & second )
}
2018-04-10 04:03:58 -05:00
2021-01-22 09:34:53 -06:00
_ , err = sess . InsertMulti ( series )
require . NoError ( t , err )
2018-04-10 04:03:58 -05:00
2021-01-22 09:34:53 -06:00
t . Run (
2021-05-05 09:46:07 -05:00
"When doing a metric query using epoch (int64) as time column and value column (int64) should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeInt64\" as time, \"timeInt64\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Len ( t , frames , 1 )
require . True ( t , tInitial . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:03:58 -05:00
} )
2021-05-05 09:46:07 -05:00
t . Run ( "When doing a metric query using epoch (int64 nullable) as time column and value column (int64 nullable,) should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeInt64Nullable\" as time, \"timeInt64Nullable\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Len ( t , frames , 1 )
require . True ( t , tInitial . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:03:58 -05:00
} )
2021-05-05 09:46:07 -05:00
t . Run ( "When doing a metric query using epoch (float64) as time column and value column (float64), should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeFloat64\" as time, \"timeFloat64\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Len ( t , frames , 1 )
require . True ( t , tInitial . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:03:58 -05:00
} )
2021-05-05 09:46:07 -05:00
t . Run ( "When doing a metric query using epoch (float64 nullable) as time column and value column (float64 nullable), should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeFloat64Nullable\" as time, \"timeFloat64Nullable\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . True ( t , tInitial . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:03:58 -05:00
} )
2021-05-05 09:46:07 -05:00
t . Run ( "When doing a metric query using epoch (int32) as time column and value column (int32), should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeInt32\" as time, \"timeInt32\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . True ( t , tInitial . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:08:30 -05:00
} )
2018-04-10 04:03:58 -05:00
2021-05-05 09:46:07 -05:00
t . Run ( "When doing a metric query using epoch (int32 nullable) as time column and value column (int32 nullable), should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeInt32Nullable\" as time, \"timeInt32Nullable\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
}
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . True ( t , tInitial . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:08:30 -05:00
} )
2018-04-10 04:03:58 -05:00
2021-05-05 09:46:07 -05:00
t . Run ( "When doing a metric query using epoch (float32) as time column and value column (float32), should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeFloat32\" as time, \"timeFloat32\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
2018-04-10 04:08:30 -05:00
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
aTime := time . Unix ( 0 , int64 ( float64 ( float32 ( tInitial . Unix ( ) ) ) * 1e3 ) * int64 ( time . Millisecond ) )
require . True ( t , aTime . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:03:58 -05:00
} )
2021-05-05 09:46:07 -05:00
t . Run ( "When doing a metric query using epoch (float32 nullable) as time column and value column (float32 nullable), should return metric with time in time.Time" ,
2021-01-22 09:34:53 -06:00
func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2018-04-10 04:03:58 -05:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"timeFloat32Nullable\" as time, \"timeFloat32Nullable\" FROM metric_values ORDER BY time LIMIT 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-04-10 04:03:58 -05:00
} ,
} ,
2018-04-10 04:08:30 -05:00
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-04-10 04:03:58 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
aTime := time . Unix ( 0 , int64 ( float64 ( float32 ( tInitial . Unix ( ) ) ) * 1e3 ) * int64 ( time . Millisecond ) )
require . True ( t , aTime . Equal ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) )
2018-04-10 04:03:58 -05:00
} )
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query grouping by time and select metric column should return correct series" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT $__timeEpoch(time), measurement || ' - value one' as metric, \"valueOne\" FROM metric_values ORDER BY 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
2021-06-18 01:05:23 -05:00
require . Equal ( t , "Metric A - value one" , frames [ 0 ] . Fields [ 1 ] . Name )
require . Equal ( t , "Metric B - value one" , frames [ 0 ] . Fields [ 2 ] . Name )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query with metric column and multiple value columns" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT $__timeEpoch(time), measurement as metric, \"valueOne\", \"valueTwo\" FROM metric_values ORDER BY 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-07-24 11:31:47 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-07-24 11:31:47 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-07-24 11:31:47 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . NoError ( t , err )
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 5 , len ( frames [ 0 ] . Fields ) )
require . Equal ( t , "valueOne" , frames [ 0 ] . Fields [ 1 ] . Name )
require . Equal ( t , data . Labels { "metric" : "Metric A" } , frames [ 0 ] . Fields [ 1 ] . Labels )
require . Equal ( t , "valueOne" , frames [ 0 ] . Fields [ 2 ] . Name )
require . Equal ( t , data . Labels { "metric" : "Metric B" } , frames [ 0 ] . Fields [ 2 ] . Labels )
require . Equal ( t , "valueTwo" , frames [ 0 ] . Fields [ 3 ] . Name )
require . Equal ( t , data . Labels { "metric" : "Metric A" } , frames [ 0 ] . Fields [ 3 ] . Labels )
require . Equal ( t , "valueTwo" , frames [ 0 ] . Fields [ 4 ] . Name )
require . Equal ( t , data . Labels { "metric" : "Metric B" } , frames [ 0 ] . Fields [ 4 ] . Labels )
2021-01-22 09:34:53 -06:00
} )
2018-07-24 11:31:47 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing a metric query grouping by time should return correct series" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT $__timeEpoch(time), \"valueOne\", \"valueTwo\" FROM metric_values ORDER BY 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
require . Equal ( t , "valueOne" , frames [ 0 ] . Fields [ 1 ] . Name )
require . Equal ( t , "valueTwo" , frames [ 0 ] . Fields [ 2 ] . Name )
2021-01-22 09:34:53 -06:00
} )
t . Run ( "When doing a query with timeFrom,timeTo,unixEpochFrom,unixEpochTo macros" , func ( t * testing . T ) {
fakeInterpolate := sqleng . Interpolate
t . Cleanup ( func ( ) {
sqleng . Interpolate = fakeInterpolate
2018-03-22 09:27:12 -05:00
} )
2021-01-22 09:34:53 -06:00
sqleng . Interpolate = origInterpolate
2018-10-03 02:35:42 -05:00
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT time FROM metric_values WHERE time > $__timeFrom() OR time < $__timeFrom() OR 1 < $__unixEpochFrom() OR $__unixEpochTo() > 1 ORDER BY 1" ,
"format" : "time_series"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : fromStart . Add ( - 5 * time . Minute ) ,
To : fromStart ,
} ,
2018-10-03 02:35:42 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-10-03 02:35:42 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Len ( t , frames , 1 )
2021-01-22 09:34:53 -06:00
require . Equal ( t ,
"SELECT time FROM metric_values WHERE time > '2018-03-15T12:55:00Z' OR time < '2018-03-15T12:55:00Z' OR 1 < 1521118500 OR 1521118800 > 1 ORDER BY 1" ,
2021-05-05 09:46:07 -05:00
frames [ 0 ] . Meta . ExecutedQueryString )
2018-03-22 09:27:12 -05:00
} )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "Given a table with event data" , func ( t * testing . T ) {
type event struct {
TimeSec int64
Description string
Tags string
}
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
if exists , err := sess . IsTableExist ( event { } ) ; err != nil || exists {
require . NoError ( t , err )
err := sess . DropTable ( event { } )
require . NoError ( t , err )
}
err := sess . CreateTable ( event { } )
require . NoError ( t , err )
events := [ ] * event { }
for _ , t := range genTimeRangeByInterval ( fromStart . Add ( - 20 * time . Minute ) , 60 * time . Minute , 25 * time . Minute ) {
events = append ( events , & event {
TimeSec : t . Unix ( ) ,
Description : "Someone deployed something" ,
Tags : "deploy" ,
} )
events = append ( events , & event {
TimeSec : t . Add ( 5 * time . Minute ) . Unix ( ) ,
Description : "New support ticket registered" ,
Tags : "ticket" ,
} )
}
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
for _ , e := range events {
_ , err := sess . Insert ( e )
require . NoError ( t , err )
}
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing an annotation query of deploy events should return expected result" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"time_sec\" as time, description as text, tags FROM event WHERE $__unixEpochFilter(time_sec) AND tags='deploy' ORDER BY 1 ASC" ,
"format" : "table"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "Deploys" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : fromStart . Add ( - 20 * time . Minute ) ,
To : fromStart . Add ( 40 * time . Minute ) ,
} ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-05-05 09:46:07 -05:00
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "Deploys" ]
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Len ( t , frames , 1 )
require . Len ( t , frames [ 0 ] . Fields , 3 )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing an annotation query of ticket events should return expected result" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT \"time_sec\" as time, description as text, tags FROM event WHERE $__unixEpochFilter(time_sec) AND tags='ticket' ORDER BY 1 ASC" ,
"format" : "table"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "Tickets" ,
2021-09-07 02:35:37 -05:00
TimeRange : backend . TimeRange {
From : fromStart . Add ( - 20 * time . Minute ) ,
To : fromStart . Add ( 40 * time . Minute ) ,
} ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-05-05 09:46:07 -05:00
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "Tickets" ]
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing an annotation query with a time column in datetime format" , func ( t * testing . T ) {
dt := time . Date ( 2018 , 3 , 14 , 21 , 20 , 6 , 527e6 , time . UTC )
dtFormat := "2006-01-02 15:04:05.999999999"
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
queryjson := fmt . Sprintf ( "{\"rawSql\": \"SELECT CAST('%s' AS TIMESTAMP) as time, 'message' as text, 'tag1,tag2' as tags\", \"format\": \"table\" }" , dt . Format ( dtFormat ) )
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( queryjson ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
2018-03-22 09:27:12 -05:00
2021-05-05 09:46:07 -05:00
// Should be in time.Time
require . Equal ( t , dt . Unix ( ) , ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) . Unix ( ) )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-05-05 09:46:07 -05:00
t . Run ( "When doing an annotation query with a time column in epoch second format should return time.Time" , func ( t * testing . T ) {
2021-01-22 09:34:53 -06:00
dt := time . Date ( 2018 , 3 , 14 , 21 , 20 , 6 , 527e6 , time . UTC )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
queryjson := fmt . Sprintf ( "{\"rawSql\": \"SELECT %d as time, 'message' as text, 'tag1,tag2' as tags\", \"format\": \"table\"}" , dt . Unix ( ) )
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( queryjson ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
// Should be in time.Time
require . Equal ( t , dt . Unix ( ) , ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) . Unix ( ) )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-05-05 09:46:07 -05:00
t . Run ( "When doing an annotation query with a time column in epoch second format (t *testing.Tint) should return time.Time" , func ( t * testing . T ) {
2021-01-22 09:34:53 -06:00
dt := time . Date ( 2018 , 3 , 14 , 21 , 20 , 6 , 527e6 , time . UTC )
2021-09-07 02:35:37 -05:00
queryjson := fmt . Sprintf ( "{\"rawSql\": \"SELECT cast(%d as bigint) as time, 'message' as text, 'tag1,tag2' as tags\", \"format\": \"table\"}" , dt . Unix ( ) )
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( queryjson ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
// Should be in time.Time
require . Equal ( t , dt . Unix ( ) , ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) . Unix ( ) )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-05-05 09:46:07 -05:00
t . Run ( "When doing an annotation query with a time column in epoch millisecond format should return time.Time" , func ( t * testing . T ) {
2021-01-22 09:34:53 -06:00
dt := time . Date ( 2018 , 3 , 14 , 21 , 20 , 6 , 527e6 , time . UTC )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
queryjson := fmt . Sprintf ( "{\"rawSql\":\"SELECT %d as time, 'message' as text, 'tag1,tag2' as tags\", \"format\": \"table\"}" , dt . Unix ( ) * 1000 )
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( queryjson ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
// Should be in time.Time
require . Equal ( t , dt . Unix ( ) , ( * frames [ 0 ] . Fields [ 0 ] . At ( 0 ) . ( * time . Time ) ) . Unix ( ) )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing an annotation query with a time column holding a bigint null value should return nil" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT cast(null as bigint) as time, 'message' as text, 'tag1,tag2' as tags" ,
"format" : "table"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
// Should be in time.Time
require . Nil ( t , frames [ 0 ] . Fields [ 0 ] . At ( 0 ) )
2021-01-22 09:34:53 -06:00
} )
2018-03-22 09:27:12 -05:00
2021-01-22 09:34:53 -06:00
t . Run ( "When doing an annotation query with a time column holding a timestamp null value should return nil" , func ( t * testing . T ) {
2021-09-07 02:35:37 -05:00
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
2021-01-22 09:34:53 -06:00
{
2021-09-07 02:35:37 -05:00
JSON : [ ] byte ( ` {
"rawSql" : "SELECT cast(null as timestamp) as time, 'message' as text, 'tag1,tag2' as tags" ,
"format" : "table"
} ` ) ,
2021-03-08 00:02:49 -06:00
RefID : "A" ,
2018-03-22 09:27:12 -05:00
} ,
2021-01-22 09:34:53 -06:00
} ,
}
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
resp , err := exe . QueryData ( context . Background ( ) , query )
2021-01-22 09:34:53 -06:00
require . NoError ( t , err )
2021-09-07 02:35:37 -05:00
queryResult := resp . Responses [ "A" ]
2021-01-22 09:34:53 -06:00
require . NoError ( t , queryResult . Error )
2018-03-22 09:27:12 -05:00
2021-09-07 02:35:37 -05:00
frames := queryResult . Frames
2021-05-05 09:46:07 -05:00
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 3 , len ( frames [ 0 ] . Fields ) )
// Should be in time.Time
assert . Nil ( t , frames [ 0 ] . Fields [ 0 ] . At ( 0 ) )
2017-10-10 08:19:14 -05:00
} )
2021-09-07 18:54:48 -05:00
t . Run ( "When doing an annotation query with a time and timeend column should return two fields of type time" , func ( t * testing . T ) {
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
{
JSON : [ ] byte ( ` {
"rawSql" : "SELECT 1631053772276 as time, 1631054012276 as timeend, '' as text, '' as tags" ,
"format" : "table"
} ` ) ,
RefID : "A" ,
} ,
} ,
}
resp , err := exe . QueryData ( context . Background ( ) , query )
require . NoError ( t , err )
queryResult := resp . Responses [ "A" ]
require . NoError ( t , queryResult . Error )
frames := queryResult . Frames
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 4 , len ( frames [ 0 ] . Fields ) )
require . Equal ( t , data . FieldTypeNullableTime , frames [ 0 ] . Fields [ 0 ] . Type ( ) )
require . Equal ( t , data . FieldTypeNullableTime , frames [ 0 ] . Fields [ 1 ] . Type ( ) )
} )
2021-09-13 08:27:51 -05:00
t . Run ( "When row limit set to 1" , func ( t * testing . T ) {
dsInfo := sqleng . DataSourceInfo { }
config := sqleng . DataPluginConfiguration {
DriverName : "postgres" ,
ConnectionString : "" ,
DSInfo : dsInfo ,
MetricColumnTypes : [ ] string { "UNKNOWN" , "TEXT" , "VARCHAR" , "CHAR" } ,
RowLimit : 1 ,
}
queryResultTransformer := postgresQueryResultTransformer {
log : logger ,
}
handler , err := sqleng . NewQueryDataHandler ( config , & queryResultTransformer , newPostgresMacroEngine ( false ) , logger )
require . NoError ( t , err )
t . Run ( "When doing a table query that returns 2 rows should limit the result to 1 row" , func ( t * testing . T ) {
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
{
JSON : [ ] byte ( ` {
"rawSql" : "SELECT 1 as value UNION ALL select 2 as value" ,
"format" : "table"
} ` ) ,
RefID : "A" ,
TimeRange : backend . TimeRange {
From : time . Now ( ) ,
To : time . Now ( ) ,
} ,
} ,
} ,
}
resp , err := handler . QueryData ( context . Background ( ) , query )
require . NoError ( t , err )
queryResult := resp . Responses [ "A" ]
require . NoError ( t , queryResult . Error )
frames := queryResult . Frames
require . NoError ( t , err )
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 1 , len ( frames [ 0 ] . Fields ) )
require . Equal ( t , 1 , frames [ 0 ] . Rows ( ) )
require . Len ( t , frames [ 0 ] . Meta . Notices , 1 )
require . Equal ( t , data . NoticeSeverityWarning , frames [ 0 ] . Meta . Notices [ 0 ] . Severity )
} )
t . Run ( "When doing a time series query that returns 2 rows should limit the result to 1 row" , func ( t * testing . T ) {
query := & backend . QueryDataRequest {
Queries : [ ] backend . DataQuery {
{
JSON : [ ] byte ( ` {
"rawSql" : "SELECT 1 as time, 1 as value UNION ALL select 2 as time, 2 as value" ,
"format" : "time_series"
} ` ) ,
RefID : "A" ,
TimeRange : backend . TimeRange {
From : time . Now ( ) ,
To : time . Now ( ) ,
} ,
} ,
} ,
}
resp , err := handler . QueryData ( context . Background ( ) , query )
require . NoError ( t , err )
queryResult := resp . Responses [ "A" ]
require . NoError ( t , queryResult . Error )
frames := queryResult . Frames
require . NoError ( t , err )
require . Equal ( t , 1 , len ( frames ) )
require . Equal ( t , 2 , len ( frames [ 0 ] . Fields ) )
require . Equal ( t , 1 , frames [ 0 ] . Rows ( ) )
require . Len ( t , frames [ 0 ] . Meta . Notices , 1 )
require . Equal ( t , data . NoticeSeverityWarning , frames [ 0 ] . Meta . Notices [ 0 ] . Severity )
} )
} )
2017-10-10 08:19:14 -05:00
} )
}
func InitPostgresTestDB ( t * testing . T ) * xorm . Engine {
2020-07-10 09:09:21 -05:00
testDB := sqlutil . PostgresTestDB ( )
x , err := xorm . NewEngine ( testDB . DriverName , strings . Replace ( testDB . ConnStr , "dbname=grafanatest" ,
"dbname=grafanadstest" , 1 ) )
2021-02-23 15:10:55 -06:00
require . NoError ( t , err , "Failed to init postgres DB" )
2018-04-10 04:08:30 -05:00
2018-03-22 09:27:12 -05:00
x . DatabaseTZ = time . UTC
x . TZLocation = time . UTC
2017-10-10 08:19:14 -05:00
// x.ShowSQL()
return x
}
2018-03-22 09:27:12 -05:00
func genTimeRangeByInterval ( from time . Time , duration time . Duration , interval time . Duration ) [ ] time . Time {
durationSec := int64 ( duration . Seconds ( ) )
intervalSec := int64 ( interval . Seconds ( ) )
timeRange := [ ] time . Time { }
for i := int64 ( 0 ) ; i < durationSec ; i += intervalSec {
timeRange = append ( timeRange , from )
from = from . Add ( time . Duration ( int64 ( time . Second ) * intervalSec ) )
}
return timeRange
}
2021-02-23 15:10:55 -06:00
type tlsTestManager struct {
settings tlsSettings
}
2021-09-07 02:35:37 -05:00
func ( m * tlsTestManager ) getTLSSettings ( dsInfo sqleng . DataSourceInfo ) ( tlsSettings , error ) {
2021-02-23 15:10:55 -06:00
return m . settings , nil
}