mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 21:22:19 +08:00
149 lines
3.7 KiB
Go
149 lines
3.7 KiB
Go
package sqlstore
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/mattn/go-sqlite3"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
|
)
|
|
|
|
func TestIntegration_RetryingDisabled(t *testing.T) {
|
|
store, _ := InitTestDB(t)
|
|
retryErrors := getRetryErrors(t, store)
|
|
|
|
require.Equal(t, 0, store.dbCfg.QueryRetries)
|
|
|
|
funcToTest := map[string]func(ctx context.Context, callback DBTransactionFunc) error{
|
|
"WithDbSession": store.WithDbSession,
|
|
}
|
|
|
|
for name, f := range funcToTest {
|
|
t.Run(fmt.Sprintf("%s should return the error immediately", name), func(t *testing.T) {
|
|
i := 0
|
|
callback := func(sess *DBSession) error {
|
|
i++
|
|
return errors.New("some error")
|
|
}
|
|
err := f(context.Background(), callback)
|
|
require.Error(t, err)
|
|
require.Equal(t, 1, i)
|
|
})
|
|
|
|
for _, e := range retryErrors {
|
|
t.Run(fmt.Sprintf("%s should return the sqlite3.Error %v immediately", name, e), func(t *testing.T) {
|
|
i := 0
|
|
callback := func(sess *DBSession) error {
|
|
i++
|
|
return e
|
|
}
|
|
err := f(context.Background(), callback)
|
|
require.Error(t, err)
|
|
require.Equal(t, 1, i)
|
|
})
|
|
}
|
|
|
|
t.Run(fmt.Sprintf("%s should not return error if the callback succeeds", name), func(t *testing.T) {
|
|
i := 0
|
|
callback := func(sess *DBSession) error {
|
|
i++
|
|
return nil
|
|
}
|
|
err := f(context.Background(), callback)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, i)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntegration_RetryingOnFailures(t *testing.T) {
|
|
store, _ := InitTestDB(t)
|
|
retryErrors := getRetryErrors(t, store)
|
|
store.dbCfg.QueryRetries = 5
|
|
|
|
funcToTest := map[string]func(ctx context.Context, callback DBTransactionFunc) error{
|
|
"WithDbSession": store.WithDbSession,
|
|
}
|
|
|
|
for name, f := range funcToTest {
|
|
t.Run(fmt.Sprintf("%s should return the error immediately if it's other than sqlite3.ErrLocked or sqlite3.ErrBusy", name), func(t *testing.T) {
|
|
i := 0
|
|
callback := func(sess *DBSession) error {
|
|
i++
|
|
return errors.New("some error")
|
|
}
|
|
err := f(context.Background(), callback)
|
|
require.Error(t, err)
|
|
require.Equal(t, 1, i)
|
|
})
|
|
|
|
for _, e := range retryErrors {
|
|
t.Run(fmt.Sprintf("%s should return the error %v if all retries have failed", name, e), func(t *testing.T) {
|
|
i := 0
|
|
callback := func(sess *DBSession) error {
|
|
i++
|
|
return e
|
|
}
|
|
err := f(context.Background(), callback)
|
|
require.Error(t, err)
|
|
require.Equal(t, store.dbCfg.QueryRetries, i)
|
|
})
|
|
}
|
|
|
|
t.Run(fmt.Sprintf("%s should not return the error if successive retries succeed", name), func(t *testing.T) {
|
|
i := 0
|
|
callback := func(sess *DBSession) error {
|
|
i++
|
|
var err error
|
|
switch store.dbCfg.QueryRetries {
|
|
case i:
|
|
err = nil
|
|
default:
|
|
err = retryErrors[0]
|
|
}
|
|
return err
|
|
}
|
|
err := f(context.Background(), callback)
|
|
require.NoError(t, err)
|
|
require.Equal(t, store.dbCfg.QueryRetries, i)
|
|
})
|
|
}
|
|
|
|
// Check SQL query
|
|
sess := store.GetSqlxSession()
|
|
rows, err := sess.Query(context.Background(), `SELECT "hello",2.3,4`)
|
|
t.Cleanup(func() {
|
|
err := rows.Close()
|
|
require.NoError(t, err)
|
|
})
|
|
require.NoError(t, err)
|
|
require.True(t, rows.Next()) // first row
|
|
|
|
str1 := ""
|
|
val2 := float64(100.1)
|
|
val3 := int64(200)
|
|
err = rows.Scan(&str1, &val2, &val3)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "hello", str1)
|
|
require.Equal(t, 2.3, val2)
|
|
require.Equal(t, int64(4), val3)
|
|
require.False(t, rows.Next()) // no more rows
|
|
}
|
|
|
|
func getRetryErrors(t *testing.T, store *SQLStore) []error {
|
|
var retryErrors []error
|
|
switch store.GetDialect().DriverName() {
|
|
case migrator.SQLite:
|
|
retryErrors = []error{sqlite3.Error{Code: sqlite3.ErrBusy}, sqlite3.Error{Code: sqlite3.ErrLocked}}
|
|
}
|
|
|
|
if len(retryErrors) == 0 {
|
|
t.Skip("This test only works with sqlite")
|
|
}
|
|
return retryErrors
|
|
}
|