mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
mssql: additional integration tests
Metric query of table having multiple value columns Annotation query
This commit is contained in:
parent
f0f8006d8d
commit
e97b03e930
@ -2,6 +2,7 @@ package mssql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -15,8 +16,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// To run this test, remove the Skip from SkipConvey
|
// To run this test, remove the Skip from SkipConvey
|
||||||
// and set up a MSSQL db named grafana_tests and a user/password grafana/Password!
|
// and set up a MSSQL db named grafanatest and a user/password grafana/Password!
|
||||||
// and set the variable below to the IP address of the database
|
// Use the docker/blocks/mssql_tests/docker-compose.yaml to spin up a
|
||||||
|
// preconfigured MSSQL server suitable for running these tests.
|
||||||
|
// If needed, change the variable below to the IP address of the database.
|
||||||
var serverIP string = "localhost"
|
var serverIP string = "localhost"
|
||||||
|
|
||||||
func TestMSSQL(t *testing.T) {
|
func TestMSSQL(t *testing.T) {
|
||||||
@ -146,14 +149,13 @@ func TestMSSQL(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Given a table with metrics", func() {
|
Convey("Given a table with metrics that lacks data for some series ", func() {
|
||||||
sql := `
|
sql := `
|
||||||
IF OBJECT_ID('dbo.[metric]', 'U') IS NOT NULL
|
IF OBJECT_ID('dbo.[metric]', 'U') IS NOT NULL
|
||||||
DROP TABLE dbo.[metric]
|
DROP TABLE dbo.[metric]
|
||||||
|
|
||||||
CREATE TABLE [metric] (
|
CREATE TABLE [metric] (
|
||||||
time datetime,
|
time datetime,
|
||||||
measurement nvarchar(100),
|
|
||||||
value int
|
value int
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
@ -163,20 +165,16 @@ func TestMSSQL(t *testing.T) {
|
|||||||
|
|
||||||
type metric struct {
|
type metric struct {
|
||||||
Time time.Time
|
Time time.Time
|
||||||
Measurement string
|
|
||||||
Value int64
|
Value int64
|
||||||
}
|
}
|
||||||
|
|
||||||
series := []*metric{}
|
series := []*metric{}
|
||||||
|
|
||||||
fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC)
|
|
||||||
firstRange := genTimeRangeByInterval(fromStart, 10*time.Minute, 10*time.Second)
|
firstRange := genTimeRangeByInterval(fromStart, 10*time.Minute, 10*time.Second)
|
||||||
secondRange := genTimeRangeByInterval(fromStart.Add(20*time.Minute), 10*time.Minute, 10*time.Second)
|
secondRange := genTimeRangeByInterval(fromStart.Add(20*time.Minute), 10*time.Minute, 10*time.Second)
|
||||||
|
|
||||||
for _, t := range firstRange {
|
for _, t := range firstRange {
|
||||||
series = append(series, &metric{
|
series = append(series, &metric{
|
||||||
Time: t,
|
Time: t,
|
||||||
Measurement: "test",
|
|
||||||
Value: 15,
|
Value: 15,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -184,7 +182,6 @@ func TestMSSQL(t *testing.T) {
|
|||||||
for _, t := range secondRange {
|
for _, t := range secondRange {
|
||||||
series = append(series, &metric{
|
series = append(series, &metric{
|
||||||
Time: t,
|
Time: t,
|
||||||
Measurement: "test",
|
|
||||||
Value: 20,
|
Value: 20,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -192,9 +189,9 @@ func TestMSSQL(t *testing.T) {
|
|||||||
dtFormat := "2006-01-02 15:04:05.999999999"
|
dtFormat := "2006-01-02 15:04:05.999999999"
|
||||||
for _, s := range series {
|
for _, s := range series {
|
||||||
sql = fmt.Sprintf(`
|
sql = fmt.Sprintf(`
|
||||||
INSERT INTO metric (time, measurement, value)
|
INSERT INTO metric (time, value)
|
||||||
VALUES(CAST('%s' AS DATETIME), '%s', %d)
|
VALUES(CAST('%s' AS DATETIME), %d)
|
||||||
`, s.Time.Format(dtFormat), s.Measurement, s.Value)
|
`, s.Time.Format(dtFormat), s.Value)
|
||||||
|
|
||||||
_, err = sess.Exec(sql)
|
_, err = sess.Exec(sql)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
@ -205,7 +202,7 @@ func TestMSSQL(t *testing.T) {
|
|||||||
Queries: []*tsdb.Query{
|
Queries: []*tsdb.Query{
|
||||||
{
|
{
|
||||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||||
"rawSql": "SELECT $__timeGroup(time, '5m') AS time, measurement as metric, avg(value) as value FROM metric GROUP BY $__timeGroup(time, '5m'), measurement ORDER BY 1",
|
"rawSql": "SELECT $__timeGroup(time, '5m') AS time, avg(value) as value FROM metric GROUP BY $__timeGroup(time, '5m') ORDER BY 1",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
}),
|
}),
|
||||||
RefId: "A",
|
RefId: "A",
|
||||||
@ -237,7 +234,7 @@ func TestMSSQL(t *testing.T) {
|
|||||||
Queries: []*tsdb.Query{
|
Queries: []*tsdb.Query{
|
||||||
{
|
{
|
||||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||||
"rawSql": "SELECT $__timeGroup(time, '5m', NULL) AS time, measurement as metric, avg(value) as value FROM metric GROUP BY $__timeGroup(time, '5m'), measurement ORDER BY 1",
|
"rawSql": "SELECT $__timeGroup(time, '5m', NULL) AS time, avg(value) as value FROM metric GROUP BY $__timeGroup(time, '5m') ORDER BY 1",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
}),
|
}),
|
||||||
RefId: "A",
|
RefId: "A",
|
||||||
@ -284,7 +281,7 @@ func TestMSSQL(t *testing.T) {
|
|||||||
Queries: []*tsdb.Query{
|
Queries: []*tsdb.Query{
|
||||||
{
|
{
|
||||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||||
"rawSql": "SELECT $__timeGroup(time, '5m', 1.5) AS time, measurement as metric, avg(value) as value FROM metric GROUP BY $__timeGroup(time, '5m'), measurement ORDER BY 1",
|
"rawSql": "SELECT $__timeGroup(time, '5m', 1.5) AS time, avg(value) as value FROM metric GROUP BY $__timeGroup(time, '5m') ORDER BY 1",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
}),
|
}),
|
||||||
RefId: "A",
|
RefId: "A",
|
||||||
@ -306,6 +303,202 @@ func TestMSSQL(t *testing.T) {
|
|||||||
So(points[6][0].Float64, ShouldEqual, 1.5)
|
So(points[6][0].Float64, ShouldEqual, 1.5)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("Given a table with metrics having multiple values and measurements", func() {
|
||||||
|
sql := `
|
||||||
|
IF OBJECT_ID('dbo.[metric_values]', 'U') IS NOT NULL
|
||||||
|
DROP TABLE dbo.[metric_values]
|
||||||
|
|
||||||
|
CREATE TABLE [metric_values] (
|
||||||
|
time datetime,
|
||||||
|
measurement nvarchar(100),
|
||||||
|
valueOne int,
|
||||||
|
valueTwo int,
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err := sess.Exec(sql)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
type metricValues struct {
|
||||||
|
Time time.Time
|
||||||
|
Measurement string
|
||||||
|
ValueOne int64
|
||||||
|
ValueTwo int64
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
rnd := func(min, max int64) int64 {
|
||||||
|
return rand.Int63n(max-min) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
series := []*metricValues{}
|
||||||
|
for _, t := range genTimeRangeByInterval(fromStart.Add(-30*time.Minute), 90*time.Minute, 5*time.Minute) {
|
||||||
|
series = append(series, &metricValues{
|
||||||
|
Time: t,
|
||||||
|
Measurement: "Metric A",
|
||||||
|
ValueOne: rnd(0, 100),
|
||||||
|
ValueTwo: rnd(0, 100),
|
||||||
|
})
|
||||||
|
series = append(series, &metricValues{
|
||||||
|
Time: t,
|
||||||
|
Measurement: "Metric B",
|
||||||
|
ValueOne: rnd(0, 100),
|
||||||
|
ValueTwo: rnd(0, 100),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
dtFormat := "2006-01-02 15:04:05"
|
||||||
|
for _, s := range series {
|
||||||
|
sql = fmt.Sprintf(`
|
||||||
|
INSERT metric_values (time, measurement, valueOne, valueTwo)
|
||||||
|
VALUES(CAST('%s' AS DATETIME), '%s', %d, %d)
|
||||||
|
`, s.Time.Format(dtFormat), s.Measurement, s.ValueOne, s.ValueTwo)
|
||||||
|
|
||||||
|
_, err = sess.Exec(sql)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("When doing a metric query grouping by time and select metric column should return correct series", func() {
|
||||||
|
query := &tsdb.TsdbQuery{
|
||||||
|
Queries: []*tsdb.Query{
|
||||||
|
{
|
||||||
|
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||||
|
"rawSql": "SELECT $__timeEpoch(time), measurement as metric, valueOne, valueTwo FROM metric_values ORDER BY 1",
|
||||||
|
"format": "time_series",
|
||||||
|
}),
|
||||||
|
RefId: "A",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := endpoint.Query(nil, nil, query)
|
||||||
|
queryResult := resp.Results["A"]
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(queryResult.Error, ShouldBeNil)
|
||||||
|
|
||||||
|
So(len(queryResult.Series), ShouldEqual, 4)
|
||||||
|
So(queryResult.Series[0].Name, ShouldEqual, "Metric A - valueOne")
|
||||||
|
So(queryResult.Series[1].Name, ShouldEqual, "Metric A - valueTwo")
|
||||||
|
So(queryResult.Series[2].Name, ShouldEqual, "Metric B - valueOne")
|
||||||
|
So(queryResult.Series[3].Name, ShouldEqual, "Metric B - valueTwo")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When doing a metric query grouping by time should return correct series", func() {
|
||||||
|
query := &tsdb.TsdbQuery{
|
||||||
|
Queries: []*tsdb.Query{
|
||||||
|
{
|
||||||
|
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||||
|
"rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values ORDER BY 1",
|
||||||
|
"format": "time_series",
|
||||||
|
}),
|
||||||
|
RefId: "A",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := endpoint.Query(nil, nil, query)
|
||||||
|
queryResult := resp.Results["A"]
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(queryResult.Error, ShouldBeNil)
|
||||||
|
|
||||||
|
So(len(queryResult.Series), ShouldEqual, 2)
|
||||||
|
So(queryResult.Series[0].Name, ShouldEqual, "valueOne")
|
||||||
|
So(queryResult.Series[1].Name, ShouldEqual, "valueTwo")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given a table with event data", func() {
|
||||||
|
sql := `
|
||||||
|
IF OBJECT_ID('dbo.[event]', 'U') IS NOT NULL
|
||||||
|
DROP TABLE dbo.[event]
|
||||||
|
|
||||||
|
CREATE TABLE [event] (
|
||||||
|
time_sec bigint,
|
||||||
|
description nvarchar(100),
|
||||||
|
tags nvarchar(100),
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err := sess.Exec(sql)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
type event struct {
|
||||||
|
TimeSec int64
|
||||||
|
Description string
|
||||||
|
Tags string
|
||||||
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range events {
|
||||||
|
sql = fmt.Sprintf(`
|
||||||
|
INSERT [event] (time_sec, description, tags)
|
||||||
|
VALUES(%d, '%s', '%s')
|
||||||
|
`, e.TimeSec, e.Description, e.Tags)
|
||||||
|
|
||||||
|
_, err = sess.Exec(sql)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("When doing an annotation query of deploy events should return expected result", func() {
|
||||||
|
query := &tsdb.TsdbQuery{
|
||||||
|
Queries: []*tsdb.Query{
|
||||||
|
{
|
||||||
|
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||||
|
"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",
|
||||||
|
}),
|
||||||
|
RefId: "Deploys",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeRange: &tsdb.TimeRange{
|
||||||
|
From: fmt.Sprintf("%v", fromStart.Add(-20*time.Minute).Unix()*1000),
|
||||||
|
To: fmt.Sprintf("%v", fromStart.Add(40*time.Minute).Unix()*1000),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := endpoint.Query(nil, nil, query)
|
||||||
|
queryResult := resp.Results["Deploys"]
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(queryResult.Tables[0].Rows), ShouldEqual, 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When doing an annotation query of ticket events should return expected result", func() {
|
||||||
|
query := &tsdb.TsdbQuery{
|
||||||
|
Queries: []*tsdb.Query{
|
||||||
|
{
|
||||||
|
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||||
|
"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",
|
||||||
|
}),
|
||||||
|
RefId: "Tickets",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeRange: &tsdb.TimeRange{
|
||||||
|
From: fmt.Sprintf("%v", fromStart.Add(-20*time.Minute).Unix()*1000),
|
||||||
|
To: fmt.Sprintf("%v", fromStart.Add(40*time.Minute).Unix()*1000),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := endpoint.Query(nil, nil, query)
|
||||||
|
queryResult := resp.Results["Tickets"]
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(queryResult.Tables[0].Rows), ShouldEqual, 3)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user