1package testdatasource
2
3import (
4	"context"
5	"fmt"
6	"testing"
7	"time"
8
9	"github.com/grafana/grafana-plugin-sdk-go/backend"
10	"github.com/grafana/grafana-plugin-sdk-go/data"
11	"github.com/grafana/grafana/pkg/components/simplejson"
12	"github.com/grafana/grafana/pkg/tsdb/legacydata"
13	"github.com/stretchr/testify/assert"
14	"github.com/stretchr/testify/require"
15)
16
17func TestTestdataScenarios(t *testing.T) {
18	s := &Service{}
19
20	t.Run("random walk ", func(t *testing.T) {
21		t.Run("Should start at the requested value", func(t *testing.T) {
22			timeRange := legacydata.DataTimeRange{From: "5m", To: "now", Now: time.Now()}
23
24			model := simplejson.New()
25			model.Set("startValue", 1.234)
26			modelBytes, err := model.MarshalJSON()
27			require.NoError(t, err)
28
29			query := backend.DataQuery{
30				RefID: "A",
31				TimeRange: backend.TimeRange{
32					From: timeRange.MustGetFrom(),
33					To:   timeRange.MustGetTo(),
34				},
35				Interval:      100 * time.Millisecond,
36				MaxDataPoints: 100,
37				JSON:          modelBytes,
38			}
39
40			req := &backend.QueryDataRequest{
41				PluginContext: backend.PluginContext{},
42				Queries:       []backend.DataQuery{query},
43			}
44
45			resp, err := s.handleRandomWalkScenario(context.Background(), req)
46			require.NoError(t, err)
47			require.NotNil(t, resp)
48
49			dResp, exists := resp.Responses[query.RefID]
50			require.True(t, exists)
51			require.NoError(t, dResp.Error)
52
53			require.Len(t, dResp.Frames, 1)
54			frame := dResp.Frames[0]
55			require.Len(t, frame.Fields, 2)
56			require.Equal(t, "time", frame.Fields[0].Name)
57			require.Equal(t, "A-series", frame.Fields[1].Name)
58			val, ok := frame.Fields[1].ConcreteAt(0)
59			require.True(t, ok)
60			require.Equal(t, 1.234, val)
61		})
62	})
63
64	t.Run("random walk table", func(t *testing.T) {
65		t.Run("Should return a table that looks like value/min/max", func(t *testing.T) {
66			timeRange := legacydata.DataTimeRange{From: "5m", To: "now", Now: time.Now()}
67
68			model := simplejson.New()
69			modelBytes, err := model.MarshalJSON()
70			require.NoError(t, err)
71
72			query := backend.DataQuery{
73				RefID: "A",
74				TimeRange: backend.TimeRange{
75					From: timeRange.MustGetFrom(),
76					To:   timeRange.MustGetTo(),
77				},
78				Interval:      100 * time.Millisecond,
79				MaxDataPoints: 100,
80				JSON:          modelBytes,
81			}
82
83			req := &backend.QueryDataRequest{
84				PluginContext: backend.PluginContext{},
85				Queries:       []backend.DataQuery{query},
86			}
87
88			resp, err := s.handleRandomWalkTableScenario(context.Background(), req)
89			require.NoError(t, err)
90			require.NotNil(t, resp)
91
92			dResp, exists := resp.Responses[query.RefID]
93			require.True(t, exists)
94			require.NoError(t, dResp.Error)
95
96			require.Len(t, dResp.Frames, 1)
97			frame := dResp.Frames[0]
98			require.Greater(t, frame.Rows(), 50)
99			require.Len(t, frame.Fields, 5)
100			require.Equal(t, "Time", frame.Fields[0].Name)
101			require.Equal(t, "Value", frame.Fields[1].Name)
102			require.Equal(t, "Min", frame.Fields[2].Name)
103			require.Equal(t, "Max", frame.Fields[3].Name)
104			require.Equal(t, "Info", frame.Fields[4].Name)
105
106			for i := 0; i < frame.Rows(); i++ {
107				value, ok := frame.ConcreteAt(1, i)
108				require.True(t, ok)
109				min, ok := frame.ConcreteAt(2, i)
110				require.True(t, ok)
111				max, ok := frame.ConcreteAt(3, i)
112				require.True(t, ok)
113
114				require.Less(t, min, value)
115				require.Greater(t, max, value)
116			}
117		})
118
119		t.Run("Should return a table with some nil values", func(t *testing.T) {
120			timeRange := legacydata.DataTimeRange{From: "5m", To: "now", Now: time.Now()}
121
122			model := simplejson.New()
123			model.Set("withNil", true)
124
125			modelBytes, err := model.MarshalJSON()
126			require.NoError(t, err)
127
128			query := backend.DataQuery{
129				RefID: "A",
130				TimeRange: backend.TimeRange{
131					From: timeRange.MustGetFrom(),
132					To:   timeRange.MustGetTo(),
133				},
134				Interval:      100 * time.Millisecond,
135				MaxDataPoints: 100,
136				JSON:          modelBytes,
137			}
138
139			req := &backend.QueryDataRequest{
140				PluginContext: backend.PluginContext{},
141				Queries:       []backend.DataQuery{query},
142			}
143
144			resp, err := s.handleRandomWalkTableScenario(context.Background(), req)
145			require.NoError(t, err)
146			require.NotNil(t, resp)
147
148			dResp, exists := resp.Responses[query.RefID]
149			require.True(t, exists)
150			require.NoError(t, dResp.Error)
151
152			require.Len(t, dResp.Frames, 1)
153			frame := dResp.Frames[0]
154			require.Greater(t, frame.Rows(), 50)
155			require.Len(t, frame.Fields, 5)
156			require.Equal(t, "Time", frame.Fields[0].Name)
157			require.Equal(t, "Value", frame.Fields[1].Name)
158			require.Equal(t, "Min", frame.Fields[2].Name)
159			require.Equal(t, "Max", frame.Fields[3].Name)
160			require.Equal(t, "Info", frame.Fields[4].Name)
161
162			valNil := false
163			minNil := false
164			maxNil := false
165
166			for i := 0; i < frame.Rows(); i++ {
167				_, ok := frame.ConcreteAt(1, i)
168				if !ok {
169					valNil = true
170				}
171
172				_, ok = frame.ConcreteAt(2, i)
173				if !ok {
174					minNil = true
175				}
176
177				_, ok = frame.ConcreteAt(3, i)
178				if !ok {
179					maxNil = true
180				}
181			}
182
183			require.True(t, valNil)
184			require.True(t, minNil)
185			require.True(t, maxNil)
186		})
187	})
188}
189
190func TestParseLabels(t *testing.T) {
191	expectedTags := data.Labels{
192		"job":      "foo",
193		"instance": "bar",
194	}
195
196	tcs := []struct {
197		model map[string]interface{}
198	}{
199		{model: map[string]interface{}{
200			"labels": `{job="foo", instance="bar"}`,
201		}},
202		{model: map[string]interface{}{
203			"labels": `job=foo, instance=bar`,
204		}},
205		{model: map[string]interface{}{
206			"labels": `job = foo,instance = bar`,
207		}},
208	}
209
210	for i, tc := range tcs {
211		model := simplejson.NewFromAny(tc.model)
212		assert.Equal(t, expectedTags, parseLabels(model), fmt.Sprintf("Actual tags in test case %d doesn't match expected tags", i+1))
213	}
214}
215