Quellcode durchsuchen

mssql: additional integration tests

Metric query of table having multiple value columns
Annotation query
Marcus Efraimsson vor 7 Jahren
Ursprung
Commit
e97b03e930
1 geänderte Dateien mit 215 neuen und 22 gelöschten Zeilen
  1. 215 22
      pkg/tsdb/mssql/mssql_test.go

+ 215 - 22
pkg/tsdb/mssql/mssql_test.go

@@ -2,6 +2,7 @@ package mssql
 
 import (
 	"fmt"
+	"math/rand"
 	"strings"
 	"testing"
 	"time"
@@ -15,8 +16,10 @@ import (
 )
 
 // 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 the variable below to the IP address of the database
+// and set up a MSSQL db named grafanatest and a user/password grafana/Password!
+// 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"
 
 func TestMSSQL(t *testing.T) {
@@ -90,7 +93,7 @@ func TestMSSQL(t *testing.T) {
         1.11, 2.22, 3.33,
 				'char10', 'varchar10', 'text',
 				N'☺nchar12☺', N'☺nvarchar12☺', N'☺text☺',
-			  CAST('%s' AS DATETIME), CAST('%s' AS DATETIME2), CAST('%s' AS SMALLDATETIME), CAST('%s' AS DATE), CAST('%s' AS TIME), SWITCHOFFSET(CAST('%s' AS DATETIMEOFFSET), '-07:00')
+				CAST('%s' AS DATETIME), CAST('%s' AS DATETIME2), CAST('%s' AS SMALLDATETIME), CAST('%s' AS DATE), CAST('%s' AS TIME), SWITCHOFFSET(CAST('%s' AS DATETIMEOFFSET), '-07:00')
     `, d, d2, d, d, d, d2)
 
 			_, err = sess.Exec(sql)
@@ -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 := `
 				IF OBJECT_ID('dbo.[metric]', 'U') IS NOT NULL
 					DROP TABLE dbo.[metric]
 
 				CREATE TABLE [metric] (
 					time datetime,
-					measurement nvarchar(100),
 					value int
 				)
 			`
@@ -162,39 +164,34 @@ func TestMSSQL(t *testing.T) {
 			So(err, ShouldBeNil)
 
 			type metric struct {
-				Time        time.Time
-				Measurement string
-				Value       int64
+				Time  time.Time
+				Value int64
 			}
 
 			series := []*metric{}
-
-			fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC)
 			firstRange := genTimeRangeByInterval(fromStart, 10*time.Minute, 10*time.Second)
 			secondRange := genTimeRangeByInterval(fromStart.Add(20*time.Minute), 10*time.Minute, 10*time.Second)
 
 			for _, t := range firstRange {
 				series = append(series, &metric{
-					Time:        t,
-					Measurement: "test",
-					Value:       15,
+					Time:  t,
+					Value: 15,
 				})
 			}
 
 			for _, t := range secondRange {
 				series = append(series, &metric{
-					Time:        t,
-					Measurement: "test",
-					Value:       20,
+					Time:  t,
+					Value: 20,
 				})
 			}
 
 			dtFormat := "2006-01-02 15:04:05.999999999"
 			for _, s := range series {
 				sql = fmt.Sprintf(`
-					INSERT INTO metric (time, measurement, value)
-					VALUES(CAST('%s' AS DATETIME), '%s', %d)
-				`, s.Time.Format(dtFormat), s.Measurement, s.Value)
+					INSERT INTO metric (time, value)
+					VALUES(CAST('%s' AS DATETIME), %d)
+				`, s.Time.Format(dtFormat), s.Value)
 
 				_, err = sess.Exec(sql)
 				So(err, ShouldBeNil)
@@ -205,7 +202,7 @@ func TestMSSQL(t *testing.T) {
 					Queries: []*tsdb.Query{
 						{
 							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",
 							}),
 							RefId: "A",
@@ -237,7 +234,7 @@ func TestMSSQL(t *testing.T) {
 					Queries: []*tsdb.Query{
 						{
 							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",
 							}),
 							RefId: "A",
@@ -284,7 +281,7 @@ func TestMSSQL(t *testing.T) {
 					Queries: []*tsdb.Query{
 						{
 							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",
 							}),
 							RefId: "A",
@@ -306,6 +303,202 @@ func TestMSSQL(t *testing.T) {
 				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)
+			})
+		})
 	})
 }