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