Pārlūkot izejas kodu

stackdriver: add first test for parsing frontend queries

Daniel Lee 7 gadi atpakaļ
vecāks
revīzija
54f16d5558

+ 70 - 46
pkg/tsdb/stackdriver/stackdriver.go

@@ -10,7 +10,6 @@ import (
 	"net/url"
 	"path"
 	"regexp"
-	"strings"
 	"time"
 
 	"golang.org/x/net/context/ctxhttp"
@@ -27,11 +26,18 @@ import (
 )
 
 type StackdriverExecutor struct {
-	HttpClient *http.Client
+	HTTPClient *http.Client
 }
 
-func NewStackdriverExecutor(datasource *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
-	return &StackdriverExecutor{}, nil
+func NewStackdriverExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
+	httpClient, err := dsInfo.GetHttpClient()
+	if err != nil {
+		return nil, err
+	}
+
+	return &StackdriverExecutor{
+		HTTPClient: httpClient,
+	}, nil
 }
 
 var glog = log.New("tsdb.stackdriver")
@@ -40,57 +46,35 @@ func init() {
 	tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewStackdriverExecutor)
 }
 
+// Query takes in the frontend queries, parses them into the Stackdriver query format
+// executes the queries against the Stackdriver API and parses the response into
+// the time series or table format
 func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
 	result := &tsdb.Response{
 		Results: make(map[string]*tsdb.QueryResult),
 	}
-	var target string
-
-	startTime, err := tsdbQuery.TimeRange.ParseFrom()
-	if err != nil {
-		return nil, err
-	}
 
-	endTime, err := tsdbQuery.TimeRange.ParseTo()
+	queries, err := e.parseQueries(tsdbQuery)
 	if err != nil {
 		return nil, err
 	}
 
-	logger.Info("tsdbQuery", "req.URL.RawQuery", tsdbQuery.TimeRange.From)
-
-	for _, query := range tsdbQuery.Queries {
-		if fullTarget, err := query.Model.Get("targetFull").String(); err == nil {
-			target = fixIntervalFormat(fullTarget)
-		} else {
-			target = fixIntervalFormat(query.Model.Get("target").MustString())
-		}
-
-		if setting.Env == setting.DEV {
-			glog.Debug("Stackdriver request", "params")
-		}
-
+	for _, query := range queries {
 		req, err := e.createRequest(ctx, dsInfo)
-		metricType := query.Model.Get("metricType").MustString()
-
-		q := req.URL.Query()
-		q.Add("interval.startTime", startTime.UTC().Format(time.RFC3339))
-		q.Add("interval.endTime", endTime.UTC().Format(time.RFC3339))
-		q.Add("aggregation.perSeriesAligner", "ALIGN_NONE")
-		q.Add("filter", metricType)
-		req.URL.RawQuery = q.Encode()
-		logger.Info("tsdbQuery", "req.URL.RawQuery", req.URL.RawQuery)
-
 		if err != nil {
 			return nil, err
 		}
 
+		req.URL.RawQuery = query.Params.Encode()
+		logger.Info("tsdbQuery", "req.URL.RawQuery", req.URL.RawQuery)
+
 		httpClient, err := dsInfo.GetHttpClient()
 		if err != nil {
 			return nil, err
 		}
 
 		span, ctx := opentracing.StartSpanFromContext(ctx, "stackdriver query")
-		span.SetTag("target", target)
+		span.SetTag("target", query.Target)
 		span.SetTag("from", tsdbQuery.TimeRange.From)
 		span.SetTag("until", tsdbQuery.TimeRange.To)
 		span.SetTag("datasource_id", dsInfo.Id)
@@ -113,13 +97,60 @@ func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSour
 			return nil, err
 		}
 
-		queryRes, err := e.parseResponse(data, query.RefId)
-		result.Results[query.RefId] = queryRes
+		queryRes, err := e.parseResponse(data, query.RefID)
+		if err != nil {
+			return nil, err
+		}
+		result.Results[query.RefID] = queryRes
 	}
 
 	return result, nil
 }
 
+func (e *StackdriverExecutor) parseQueries(tsdbQuery *tsdb.TsdbQuery) ([]*StackdriverQuery, error) {
+	stackdriverQueries := []*StackdriverQuery{}
+
+	startTime, err := tsdbQuery.TimeRange.ParseFrom()
+	if err != nil {
+		return nil, err
+	}
+
+	endTime, err := tsdbQuery.TimeRange.ParseTo()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, query := range tsdbQuery.Queries {
+		var target string
+
+		if fullTarget, err := query.Model.Get("targetFull").String(); err == nil {
+			target = fixIntervalFormat(fullTarget)
+		} else {
+			target = fixIntervalFormat(query.Model.Get("target").MustString())
+		}
+
+		metricType := query.Model.Get("metricType").MustString()
+
+		params := url.Values{}
+		params.Add("interval.startTime", startTime.UTC().Format(time.RFC3339))
+		params.Add("interval.endTime", endTime.UTC().Format(time.RFC3339))
+		params.Add("aggregation.perSeriesAligner", "ALIGN_NONE")
+		params.Add("filter", metricType)
+
+		if setting.Env == setting.DEV {
+			glog.Debug("Stackdriver request", "params", params)
+		}
+
+		stackdriverQueries = append(stackdriverQueries, &StackdriverQuery{
+			Target: target,
+			Params: params,
+			RefID:  query.RefId,
+		})
+	}
+
+	return stackdriverQueries, nil
+}
+
 func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (StackDriverResponse, error) {
 	body, err := ioutil.ReadAll(res.Body)
 	defer res.Body.Close()
@@ -142,9 +173,9 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (StackDriver
 	return data, nil
 }
 
-func (e *StackdriverExecutor) parseResponse(data StackDriverResponse, queryRefId string) (*tsdb.QueryResult, error) {
+func (e *StackdriverExecutor) parseResponse(data StackDriverResponse, queryRefID string) (*tsdb.QueryResult, error) {
 	queryRes := tsdb.NewQueryResult()
-	queryRes.RefId = queryRefId
+	queryRes.RefId = queryRefID
 
 	for _, series := range data.TimeSeries {
 		points := make([]tsdb.TimePoint, 0)
@@ -192,13 +223,6 @@ func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.
 	return req, err
 }
 
-func formatTimeRange(input string) string {
-	if input == "now" {
-		return input
-	}
-	return strings.Replace(strings.Replace(strings.Replace(input, "now", "", -1), "m", "min", -1), "M", "mon", -1)
-}
-
 func fixIntervalFormat(target string) string {
 	rMinute := regexp.MustCompile(`'(\d+)m'`)
 	rMin := regexp.MustCompile("m")

+ 47 - 0
pkg/tsdb/stackdriver/stackdriver_test.go

@@ -0,0 +1,47 @@
+package stackdriver
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	"github.com/grafana/grafana/pkg/tsdb"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestStackdriver(t *testing.T) {
+	Convey("Stackdriver", t, func() {
+		Convey("Parse query from frontend", func() {
+			executor := &StackdriverExecutor{}
+			fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC).In(time.Local)
+			tsdbQuery := &tsdb.TsdbQuery{
+				TimeRange: &tsdb.TimeRange{
+					From: fmt.Sprintf("%v", fromStart.Unix()*1000),
+					To:   fmt.Sprintf("%v", fromStart.Add(34*time.Minute).Unix()*1000),
+				},
+				Queries: []*tsdb.Query{
+					{
+						Model: simplejson.NewFromAny(map[string]interface{}{
+							"target":     "target",
+							"metricType": "time_series",
+						}),
+						RefId: "A",
+					},
+				},
+			}
+			queries, err := executor.parseQueries(tsdbQuery)
+			So(err, ShouldBeNil)
+
+			So(len(queries), ShouldEqual, 1)
+			So(queries[0].RefID, ShouldEqual, "A")
+			So(queries[0].Target, ShouldEqual, "target")
+			So(len(queries[0].Params), ShouldEqual, 4)
+			So(queries[0].Params["interval.startTime"][0], ShouldEqual, "2018-03-15T13:00:00Z")
+			So(queries[0].Params["interval.endTime"][0], ShouldEqual, "2018-03-15T13:34:00Z")
+			So(queries[0].Params["aggregation.perSeriesAligner"][0], ShouldEqual, "ALIGN_NONE")
+			So(queries[0].Params["filter"][0], ShouldEqual, "time_series")
+		})
+	})
+}

+ 10 - 1
pkg/tsdb/stackdriver/types.go

@@ -1,6 +1,15 @@
 package stackdriver
 
-import "time"
+import (
+	"net/url"
+	"time"
+)
+
+type StackdriverQuery struct {
+	Target string
+	Params url.Values
+	RefID  string
+}
 
 type StackDriverResponse struct {
 	TimeSeries []struct {