Skip to content

Commit cc7ea33

Browse files
authored
test-driver (#93)
1 parent f35dc61 commit cc7ea33

File tree

2 files changed

+161
-1
lines changed

2 files changed

+161
-1
lines changed

datasource.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ func (ds *SQLDatasource) getDBConnectionFromQuery(q *Query, datasourceUID string
176176
return key, cachedConn, nil
177177
}
178178

179-
var err error
180179
db, err := ds.c.Connect(dbConn.settings, q.ConnectionArgs)
181180
if err != nil {
182181
return "", dbConnection{}, err

test/driver.go

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package test
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"database/sql/driver"
7+
"io"
8+
"reflect"
9+
"time"
10+
11+
"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
12+
"github.com/grafana/sqlds/v2"
13+
"github.com/grafana/sqlds/v2/mock"
14+
)
15+
16+
var registered = map[string]*SqlHandler{}
17+
18+
// NewDriver creates and registers a new test datasource driver
19+
func NewDriver(name string, dbdata Data, converters []sqlutil.Converter, opts DriverOpts) (TestDS, *SqlHandler) {
20+
if registered[name] == nil {
21+
handler := NewDriverHandler(dbdata, opts)
22+
registered[name] = &handler
23+
mock.RegisterDriver(name, &handler)
24+
}
25+
26+
return NewTestDS(
27+
func() (*sql.DB, error) {
28+
return sql.Open(name, "")
29+
},
30+
converters,
31+
), registered[name]
32+
}
33+
34+
// NewTestDS creates a new test datasource driver
35+
func NewTestDS(openDBfn func() (*sql.DB, error), converters []sqlutil.Converter) TestDS {
36+
return TestDS{
37+
openDBfn: openDBfn,
38+
converters: converters,
39+
}
40+
}
41+
42+
// NewDriverHandler creates a new driver handler
43+
func NewDriverHandler(data Data, opts DriverOpts) SqlHandler {
44+
return SqlHandler{
45+
Data: data,
46+
Opts: opts,
47+
}
48+
}
49+
50+
// SqlHandler handles driver functions
51+
type SqlHandler struct {
52+
mock.DBHandler
53+
Data Data
54+
Opts DriverOpts
55+
State State
56+
row int
57+
}
58+
59+
// Ping represents a database ping
60+
func (s *SqlHandler) Ping(ctx context.Context) error {
61+
s.State.ConnectAttempts += 1
62+
if s.Opts.ConnectDelay > 0 {
63+
time.Sleep(time.Duration(s.Opts.ConnectDelay * int(time.Second))) // simulate a connection delay
64+
}
65+
if s.Opts.ConnectError != nil {
66+
return s.Opts.ConnectError
67+
}
68+
return nil
69+
}
70+
71+
// Query represents a database query
72+
func (s *SqlHandler) Query(args []driver.Value) (driver.Rows, error) {
73+
s.State.QueryAttempts += 1
74+
if s.Opts.QueryDelay > 0 {
75+
time.Sleep(time.Duration(s.Opts.QueryDelay * int(time.Second))) // simulate a query delay
76+
}
77+
s.row = 0
78+
if s.Opts.QueryError != nil {
79+
return s, s.Opts.QueryError
80+
}
81+
return s, nil
82+
}
83+
84+
// Columns represents columns from a query
85+
func (s *SqlHandler) Columns() []string {
86+
var cols []string
87+
for _, c := range s.Data.Cols {
88+
cols = append(cols, c.Name)
89+
}
90+
return cols
91+
}
92+
93+
// Next iterates over rows
94+
func (s *SqlHandler) Next(dest []driver.Value) error {
95+
if s.row+1 > len(s.Data.Rows) {
96+
return io.EOF
97+
}
98+
99+
s.row++
100+
for _, row := range s.Data.Rows {
101+
for i, col := range row {
102+
dest[i] = col
103+
}
104+
}
105+
return nil
106+
}
107+
108+
// Close implements the database Close interface
109+
func (s SqlHandler) Close() error {
110+
return nil
111+
}
112+
113+
// ColumnTypeScanType returns the scan type for the column
114+
func (s SqlHandler) ColumnTypeScanType(index int) reflect.Type {
115+
kind := s.Data.Cols[index].Kind
116+
return reflect.TypeOf(kind)
117+
}
118+
119+
// ColumnTypeDatabaseTypeName returns the database type for the column
120+
func (s SqlHandler) ColumnTypeDatabaseTypeName(index int) string {
121+
return s.Data.Cols[index].DataType
122+
}
123+
124+
// Data - the columns/rows
125+
type Data struct {
126+
Cols []Column
127+
Rows [][]any
128+
}
129+
130+
// Column - the column meta
131+
type Column struct {
132+
Name string
133+
Kind any
134+
DataType string
135+
}
136+
137+
// TestDS ...
138+
type TestDS struct {
139+
openDBfn func() (*sql.DB, error)
140+
converters []sqlutil.Converter
141+
sqlds.Driver
142+
}
143+
144+
// Open - opens the test database
145+
func (s TestDS) Open() (*sql.DB, error) {
146+
return s.openDBfn()
147+
}
148+
149+
// DriverOpts the optional settings
150+
type DriverOpts struct {
151+
ConnectDelay int
152+
QueryDelay int
153+
ConnectError error
154+
QueryError error
155+
}
156+
157+
// State is the state of the connections/queries
158+
type State struct {
159+
QueryAttempts int
160+
ConnectAttempts int
161+
}

0 commit comments

Comments
 (0)