Skip to content

Commit dda2dc0

Browse files
authored
error source (#103)
error source
1 parent 9c6e751 commit dda2dc0

8 files changed

+359
-472
lines changed

.drone.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ services:
1818

1919
steps:
2020
- name: "test"
21-
image: golang:1.20
21+
image: golang:1.21
2222
commands:
2323
- go test ./...
2424
- name: "integraiton_tests"
25-
image: golang:1.20
25+
image: golang:1.21
2626
environment:
2727
INTEGRATION_TESTS: "true"
2828
MYSQL_URL: "mysql:mysql@tcp(mysql:3306)/mysql"
@@ -31,6 +31,6 @@ steps:
3131

3232
---
3333
kind: signature
34-
hmac: a87eed3ff4ff31806a1f22daad4f283b9c6b0e4f8a8be84ae611016a7c4ac474
34+
hmac: ee935b524c92f8c6eadfef904268c9a9d8ac6f0309d8a46597e5ae2ec49f1995
3535

3636
...

datasource.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,11 @@ func (ds *SQLDatasource) QueryData(ctx context.Context, req *backend.QueryDataRe
135135
}
136136
}
137137
}
138+
138139
response.Set(query.RefID, backend.DataResponse{
139-
Frames: frames,
140-
Error: err,
140+
Frames: frames,
141+
Error: err,
142+
ErrorSource: ErrorSource(err),
141143
})
142144

143145
wg.Done()
@@ -241,8 +243,6 @@ func (ds *SQLDatasource) handleQuery(ctx context.Context, req backend.DataQuery,
241243
return res, nil
242244
}
243245

244-
// err = Unwrap(err)
245-
246246
if errors.Is(err, ErrorNoResults) {
247247
return res, nil
248248
}

datasource_connect_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package sqlds
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"encoding/json"
7+
"errors"
8+
"testing"
9+
10+
"github.com/grafana/grafana-plugin-sdk-go/backend"
11+
"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
12+
)
13+
14+
type fakeDriver struct {
15+
openDBfn func(msg json.RawMessage) (*sql.DB, error)
16+
17+
Driver
18+
}
19+
20+
func (d fakeDriver) Connect(_ context.Context, _ backend.DataSourceInstanceSettings, msg json.RawMessage) (db *sql.DB, err error) {
21+
return d.openDBfn(msg)
22+
}
23+
24+
func (d fakeDriver) Macros() Macros {
25+
return Macros{}
26+
}
27+
28+
func (d fakeDriver) Converters() []sqlutil.Converter {
29+
return []sqlutil.Converter{}
30+
}
31+
32+
func Test_getDBConnectionFromQuery(t *testing.T) {
33+
db := &sql.DB{}
34+
db2 := &sql.DB{}
35+
db3 := &sql.DB{}
36+
d := &fakeDriver{openDBfn: func(msg json.RawMessage) (*sql.DB, error) { return db3, nil }}
37+
tests := []struct {
38+
desc string
39+
dsUID string
40+
args string
41+
existingDB *sql.DB
42+
expectedKey string
43+
expectedDB *sql.DB
44+
}{
45+
{
46+
desc: "it should return the default db with no args",
47+
dsUID: "uid1",
48+
args: "",
49+
expectedKey: "uid1-default",
50+
expectedDB: db,
51+
},
52+
{
53+
desc: "it should return the cached connection for the given args",
54+
dsUID: "uid1",
55+
args: "foo",
56+
expectedKey: "uid1-foo",
57+
existingDB: db2,
58+
expectedDB: db2,
59+
},
60+
{
61+
desc: "it should create a new connection with the given args",
62+
dsUID: "uid1",
63+
args: "foo",
64+
expectedKey: "uid1-foo",
65+
expectedDB: db3,
66+
},
67+
}
68+
for _, tt := range tests {
69+
t.Run(tt.desc, func(t *testing.T) {
70+
ds := &SQLDatasource{c: d, EnableMultipleConnections: true}
71+
settings := backend.DataSourceInstanceSettings{UID: tt.dsUID}
72+
key := defaultKey(tt.dsUID)
73+
// Add the mandatory default db
74+
ds.storeDBConnection(key, dbConnection{db, settings})
75+
if tt.existingDB != nil {
76+
key = keyWithConnectionArgs(tt.dsUID, []byte(tt.args))
77+
ds.storeDBConnection(key, dbConnection{tt.existingDB, settings})
78+
}
79+
80+
key, dbConn, err := ds.getDBConnectionFromQuery(context.Background(), &Query{ConnectionArgs: json.RawMessage(tt.args)}, tt.dsUID)
81+
if err != nil {
82+
t.Fatalf("unexpected error %v", err)
83+
}
84+
if key != tt.expectedKey {
85+
t.Fatalf("unexpected cache key %s", key)
86+
}
87+
if dbConn.db != tt.expectedDB {
88+
t.Fatalf("unexpected result %v", dbConn.db)
89+
}
90+
})
91+
}
92+
93+
t.Run("it should return an error if connection args are used without enabling multiple connections", func(t *testing.T) {
94+
ds := &SQLDatasource{c: d, EnableMultipleConnections: false}
95+
_, _, err := ds.getDBConnectionFromQuery(context.Background(), &Query{ConnectionArgs: json.RawMessage("foo")}, "dsUID")
96+
if err == nil || !errors.Is(err, MissingMultipleConnectionsConfig) {
97+
t.Errorf("expecting error: %v", MissingMultipleConnectionsConfig)
98+
}
99+
})
100+
101+
t.Run("it should return an error if the default connection is missing", func(t *testing.T) {
102+
ds := &SQLDatasource{c: d}
103+
_, _, err := ds.getDBConnectionFromQuery(context.Background(), &Query{}, "dsUID")
104+
if err == nil || !errors.Is(err, MissingDBConnection) {
105+
t.Errorf("expecting error: %v", MissingDBConnection)
106+
}
107+
})
108+
}
109+
110+
func Test_Dispose(t *testing.T) {
111+
t.Run("it should not delete connections", func(t *testing.T) {
112+
ds := &SQLDatasource{}
113+
ds.dbConnections.Store(defaultKey("uid1"), dbConnection{})
114+
ds.dbConnections.Store("foo", dbConnection{})
115+
ds.Dispose()
116+
count := 0
117+
ds.dbConnections.Range(func(key, value interface{}) bool {
118+
count++
119+
return true
120+
})
121+
if count != 2 {
122+
t.Errorf("missing connections")
123+
}
124+
})
125+
}

0 commit comments

Comments
 (0)