mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
SQLStore: Add test for nested transactions events (#60500)
* SQLStore: Add test for nested transactions events * Replace fmt.Print* with t.Log* * Add different test cases
This commit is contained in:
parent
4def287e62
commit
2b0de82aa9
@ -68,7 +68,7 @@ func startSessionOrUseExisting(ctx context.Context, engine *xorm.Engine, beginTr
|
|||||||
|
|
||||||
// WithDbSession calls the callback with the session in the context (if exists).
|
// WithDbSession calls the callback with the session in the context (if exists).
|
||||||
// Otherwise it creates a new one that is closed upon completion.
|
// Otherwise it creates a new one that is closed upon completion.
|
||||||
// A session is stored in the context if sqlstore.InTransaction() has been been previously called with the same context (and it's not committed/rolledback yet).
|
// A session is stored in the context if sqlstore.InTransaction() has been previously called with the same context (and it's not committed/rolledback yet).
|
||||||
// In case of sqlite3.ErrLocked or sqlite3.ErrBusy failure it will be retried at most five times before giving up.
|
// In case of sqlite3.ErrLocked or sqlite3.ErrBusy failure it will be retried at most five times before giving up.
|
||||||
func (ss *SQLStore) WithDbSession(ctx context.Context, callback DBTransactionFunc) error {
|
func (ss *SQLStore) WithDbSession(ctx context.Context, callback DBTransactionFunc) error {
|
||||||
return ss.withDbSession(ctx, ss.engine, callback)
|
return ss.withDbSession(ctx, ss.engine, callback)
|
||||||
|
@ -85,11 +85,9 @@ func (ss *SQLStore) inTransactionWithRetryCtx(ctx context.Context, engine *xorm.
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sess.events) > 0 {
|
for _, e := range sess.events {
|
||||||
for _, e := range sess.events {
|
if err = bus.Publish(ctx, e); err != nil {
|
||||||
if err = bus.Publish(ctx, e); err != nil {
|
ctxLogger.Error("Failed to publish event after commit.", "error", err)
|
||||||
ctxLogger.Error("Failed to publish event after commit.", "error", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,10 @@ package sqlstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,3 +67,75 @@ func TestIntegrationReuseSessionWithTransaction(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPublishAfterCommitWithNestedTransactions(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test")
|
||||||
|
}
|
||||||
|
|
||||||
|
ss := InitTestDB(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// On X success
|
||||||
|
var xHasSucceeded bool
|
||||||
|
ss.Bus().AddEventListener(func(ctx context.Context, e *X) error {
|
||||||
|
xHasSucceeded = true
|
||||||
|
t.Logf("Succeeded and committed: %T\n", e)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// On Y success
|
||||||
|
var yHasSucceeded bool
|
||||||
|
ss.Bus().AddEventListener(func(ctx context.Context, e *Y) error {
|
||||||
|
yHasSucceeded = true
|
||||||
|
t.Logf("Succeeded and committed: %T\n", e)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("When no session is stored into the context, each transaction should be independent", func(t *testing.T) {
|
||||||
|
t.Cleanup(func() { xHasSucceeded = false; yHasSucceeded = false })
|
||||||
|
|
||||||
|
err := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
t.Logf("Outer transaction: doing X... success!")
|
||||||
|
sess.PublishAfterCommit(&X{})
|
||||||
|
|
||||||
|
require.NoError(t, ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
t.Log("Inner transaction: doing Y... success!")
|
||||||
|
sess.PublishAfterCommit(&Y{})
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
t.Log("Outer transaction: doing Z... failure, rolling back...")
|
||||||
|
return errors.New("z failed")
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.False(t, xHasSucceeded)
|
||||||
|
assert.True(t, yHasSucceeded)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("When the session is stored into the context, the inner transaction should depend on the outer one", func(t *testing.T) {
|
||||||
|
t.Cleanup(func() { xHasSucceeded = false; yHasSucceeded = false })
|
||||||
|
|
||||||
|
err := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
t.Logf("Outer transaction: doing X... success!")
|
||||||
|
sess.PublishAfterCommit(&X{})
|
||||||
|
|
||||||
|
require.NoError(t, ss.InTransaction(ctx, func(ctx context.Context) error {
|
||||||
|
t.Log("Inner transaction: doing Y... success!")
|
||||||
|
sess.PublishAfterCommit(&Y{})
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
t.Log("Outer transaction: doing Z... failure, rolling back...")
|
||||||
|
return errors.New("z failed")
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.False(t, xHasSucceeded)
|
||||||
|
assert.False(t, yHasSucceeded)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type X struct{}
|
||||||
|
type Y struct{}
|
||||||
|
Loading…
Reference in New Issue
Block a user