package tsdb import ( "testing" "time" . "github.com/smartystreets/goconvey/convey" ) func TestMetricQuery(t *testing.T) { Convey("When batches groups for query", t, func() { Convey("Given 3 queries for 2 data sources", func() { request := &Request{ Queries: QuerySlice{ {RefId: "A", DataSource: &DataSourceInfo{Id: 1}}, {RefId: "B", DataSource: &DataSourceInfo{Id: 1}}, {RefId: "C", DataSource: &DataSourceInfo{Id: 2}}, }, } batches, err := getBatches(request) So(err, ShouldBeNil) Convey("Should group into two batches", func() { So(len(batches), ShouldEqual, 2) }) }) Convey("Given query 2 depends on query 1", func() { request := &Request{ Queries: QuerySlice{ {RefId: "A", DataSource: &DataSourceInfo{Id: 1}}, {RefId: "B", DataSource: &DataSourceInfo{Id: 2}}, {RefId: "C", DataSource: &DataSourceInfo{Id: 3}, Depends: []string{"A", "B"}}, }, } batches, err := getBatches(request) So(err, ShouldBeNil) Convey("Should return three batch groups", func() { So(len(batches), ShouldEqual, 3) }) Convey("Group 3 should have group 1 and 2 as dependencies", func() { So(batches[2].Depends["A"], ShouldEqual, true) So(batches[2].Depends["B"], ShouldEqual, true) }) }) }) Convey("When executing request with one query", t, func() { req := &Request{ Queries: QuerySlice{ {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, }, } fakeExecutor := registerFakeExecutor() fakeExecutor.Return("A", TimeSeriesSlice{&TimeSeries{Name: "argh"}}) res, err := HandleRequest(req) So(err, ShouldBeNil) Convey("Should return query results", func() { So(res.Results["A"].Series, ShouldNotBeEmpty) So(res.Results["A"].Series[0].Name, ShouldEqual, "argh") }) }) Convey("When executing one request with two queries from same data source", t, func() { req := &Request{ Queries: QuerySlice{ {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, {RefId: "B", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, }, } fakeExecutor := registerFakeExecutor() fakeExecutor.Return("A", TimeSeriesSlice{&TimeSeries{Name: "argh"}}) fakeExecutor.Return("B", TimeSeriesSlice{&TimeSeries{Name: "barg"}}) res, err := HandleRequest(req) So(err, ShouldBeNil) Convey("Should return query results", func() { So(len(res.Results), ShouldEqual, 2) So(res.Results["B"].Series[0].Name, ShouldEqual, "barg") }) Convey("Should have been batched in one request", func() { So(len(res.BatchTimings), ShouldEqual, 1) }) }) Convey("When executing one request with three queries from different datasources", t, func() { req := &Request{ Queries: QuerySlice{ {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, {RefId: "B", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, {RefId: "C", DataSource: &DataSourceInfo{Id: 2, PluginId: "test"}}, }, } res, err := HandleRequest(req) So(err, ShouldBeNil) Convey("Should have been batched in two requests", func() { So(len(res.BatchTimings), ShouldEqual, 2) }) }) Convey("When query uses data source of unknown type", t, func() { req := &Request{ Queries: QuerySlice{ {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "asdasdas"}}, }, } _, err := HandleRequest(req) So(err, ShouldNotBeNil) }) Convey("When executing request that depend on other query", t, func() { req := &Request{ Queries: QuerySlice{ { RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}, }, { RefId: "B", DataSource: &DataSourceInfo{Id: 2, PluginId: "test"}, Depends: []string{"A"}, }, }, } fakeExecutor := registerFakeExecutor() fakeExecutor.HandleQuery("A", func(c *QueryContext) *QueryResult { time.Sleep(10 * time.Millisecond) return &QueryResult{ Series: TimeSeriesSlice{ &TimeSeries{Name: "Ares"}, }} }) fakeExecutor.HandleQuery("B", func(c *QueryContext) *QueryResult { return &QueryResult{ Series: TimeSeriesSlice{ &TimeSeries{Name: "Bres+" + c.Results["A"].Series[0].Name}, }} }) res, err := HandleRequest(req) So(err, ShouldBeNil) Convey("Should have been batched in two requests", func() { So(len(res.BatchTimings), ShouldEqual, 2) }) Convey("Query B should have access to Query A results", func() { So(res.Results["B"].Series[0].Name, ShouldEqual, "Bres+Ares") }) }) } func registerFakeExecutor() *FakeExecutor { executor := NewFakeExecutor(nil) RegisterExecutor("test", func(dsInfo *DataSourceInfo) Executor { return executor }) return executor }