Unistore Chore: Add OTEL testing harness (#94835)

* add testing harness

* fix mockery and linters

* fix data race in tests

* fix data race in tests

* reduce cardinality of data
This commit is contained in:
Diego Augusto Molina
2024-10-17 08:41:06 -03:00
committed by GitHub
parent 8b9bb2acf6
commit cf08f6762d
14 changed files with 756 additions and 41 deletions
+24 -9
View File
@@ -14,6 +14,17 @@ import (
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
)
//nolint:unused
const (
otelAttrBaseKey = "dbutil_"
otelAttrTemplateNameKey = otelAttrBaseKey + "template"
otelAttrDialectKey = otelAttrBaseKey + "dialect"
)
func withOtelAttrs(ctx context.Context, tmplName, dialectName string) context.Context {
return ctx // TODO: in next PR
}
// SQLError is an error returned by the database, which includes additionally
// debugging information about what was sent to the database.
type SQLError struct {
@@ -79,7 +90,7 @@ func Debug(err error) error {
// Exec uses `req` as input for a non-data returning query generated with
// `tmpl`, and executed in `x`.
func Exec(ctx context.Context, x db.ContextExecer, tmpl *template.Template, req sqltemplate.SQLTemplate) (sql.Result, error) {
func Exec(ctx context.Context, x db.ContextExecer, tmpl *template.Template, req sqltemplate.SQLTemplate) (db.Result, error) {
if err := req.Validate(); err != nil {
return nil, fmt.Errorf("Exec: invalid request for template %q: %w",
tmpl.Name(), err)
@@ -91,13 +102,15 @@ func Exec(ctx context.Context, x db.ContextExecer, tmpl *template.Template, req
}
query := sqltemplate.FormatSQL(rawQuery)
res, err := x.ExecContext(ctx, query, req.GetArgs()...)
args := req.GetArgs()
ctx = withOtelAttrs(ctx, tmpl.Name(), req.DialectName())
res, err := x.ExecContext(ctx, query, args...)
if err != nil {
return nil, SQLError{
Err: err,
CallType: "Exec",
TemplateName: tmpl.Name(),
arguments: req.GetArgs(),
arguments: args,
Query: query,
RawQuery: rawQuery,
}
@@ -108,7 +121,7 @@ func Exec(ctx context.Context, x db.ContextExecer, tmpl *template.Template, req
// Query uses `req` as input for a single-statement, set-returning query
// generated with `tmpl`, and executed in `x`.
func QueryRows(ctx context.Context, x db.ContextExecer, tmpl *template.Template, req sqltemplate.SQLTemplate) (*sql.Rows, error) {
func QueryRows(ctx context.Context, x db.ContextExecer, tmpl *template.Template, req sqltemplate.SQLTemplate) (db.Rows, error) {
if err := req.Validate(); err != nil {
return nil, fmt.Errorf("Query: invalid request for template %q: %w",
tmpl.Name(), err)
@@ -120,13 +133,15 @@ func QueryRows(ctx context.Context, x db.ContextExecer, tmpl *template.Template,
}
query := sqltemplate.FormatSQL(rawQuery)
rows, err := x.QueryContext(ctx, query, req.GetArgs()...)
args := req.GetArgs()
ctx = withOtelAttrs(ctx, tmpl.Name(), req.DialectName())
rows, err := x.QueryContext(ctx, query, args...)
if err != nil {
return nil, SQLError{
Err: err,
CallType: "Query",
TemplateName: tmpl.Name(),
arguments: req.GetArgs(),
arguments: args,
ScanDest: req.GetScanDest(),
Query: query,
RawQuery: rawQuery,
@@ -186,13 +201,13 @@ func QueryRow[T any](ctx context.Context, x db.ContextExecer, tmpl *template.Tem
}
}
// DiscardRows discards all the ResultSets in the given *sql.Rows and returns
// DiscardRows discards all the ResultSets in the given db.Rows and returns
// the final rows error and the number of times NextResultSet was called. This
// is useful to check for errors in queries with multiple SQL statements where
// there is no interesting output, since some drivers may omit an error returned
// by a SQL statement found in a statement that is not the first one. Note that
// not all drivers support multi-statement calls, though.
func DiscardRows(rows *sql.Rows) (int, error) {
func DiscardRows(rows db.Rows) (int, error) {
discardedResultSets := 1
for ; rows.NextResultSet(); discardedResultSets++ {
}
@@ -203,7 +218,7 @@ type scanner interface {
Scan(dest ...any) error
}
// scanRow is used on *sql.Row and *sql.Rows, and is factored out here not to
// scanRow is used on db.Row and db.Rows, and is factored out here not to
// improving code reuse, but rather for ease of testing.
func scanRow[T any](sc scanner, req sqltemplate.WithResults[T]) (zero T, err error) {
if err = sc.Scan(req.GetScanDest()...); err != nil {
@@ -87,6 +87,8 @@ func TestQuery(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil)
req.EXPECT().GetScanDest().Return(nil).Maybe()
@@ -108,6 +110,8 @@ func TestQuery(t *testing.T) {
rows := newReturnsRow(rdb.SQLMock, req)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rows.Add(1, nil)
@@ -131,6 +135,8 @@ func TestQuery(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(errTest).Once()
// execute and assert
@@ -152,6 +158,8 @@ func TestQuery(t *testing.T) {
req.EXPECT().Validate().Return(nil).Once()
// execute and assert
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
res, err := Query(ctx, rdb.DB, invalidTestTmpl, req)
require.Zero(t, res)
require.Error(t, err)
@@ -167,6 +175,8 @@ func TestQuery(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil)
req.EXPECT().GetScanDest().Return(nil).Maybe()
@@ -189,6 +199,8 @@ func TestQuery(t *testing.T) {
rows := newReturnsRow(rdb.SQLMock, req)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rows.Add(0, errTest)
@@ -211,6 +223,8 @@ func TestQuery(t *testing.T) {
rows := newReturnsRow(rdb.SQLMock, req)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rows.Rows.AddRow() // we don't expect GetScanDest or Results here
@@ -235,6 +249,8 @@ func TestQuery(t *testing.T) {
rows2 := newReturnsRow(rdb.SQLMock, req)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rows1.Add(1, nil)
@@ -262,6 +278,8 @@ func TestQueryRow(t *testing.T) {
rows := newReturnsRow(rdb.SQLMock, req)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rows.Add(1, nil)
@@ -282,6 +300,8 @@ func TestQueryRow(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rdb.SQLMock.ExpectQuery("").WillReturnRows(rdb.SQLMock.NewRows(nil))
@@ -302,6 +322,8 @@ func TestQueryRow(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil)
req.EXPECT().GetScanDest().Return(nil).Maybe()
@@ -324,6 +346,8 @@ func TestQueryRow(t *testing.T) {
rows := newReturnsRow(rdb.SQLMock, req)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rows.Add(1, nil)
@@ -348,6 +372,8 @@ func TestQueryRow(t *testing.T) {
rows2 := newReturnsRow(rdb.SQLMock, req)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rows1.Add(1, nil)
@@ -445,6 +471,8 @@ func TestExec(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil).Once()
rdb.SQLMock.ExpectExec("").WillReturnResult(sqlmock.NewResult(0, 0))
@@ -464,6 +492,8 @@ func TestExec(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(errTest).Once()
// execute and assert
@@ -482,6 +512,8 @@ func TestExec(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
// execute and assert
@@ -500,6 +532,8 @@ func TestExec(t *testing.T) {
rdb := test.NewDBProviderNopSQL(t)
// setup expectations
req.EXPECT().DialectName().Return("test").Maybe()
req.EXPECT().GetColNames().Return(nil).Maybe()
req.EXPECT().Validate().Return(nil).Once()
req.EXPECT().GetArgs().Return(nil)
rdb.SQLMock.ExpectExec("").WillReturnError(errTest)