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:
Joan López de la Franca Beltran 2023-01-23 14:17:56 +01:00 committed by GitHub
parent 4def287e62
commit 2b0de82aa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 6 deletions

View File

@ -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).
// 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.
func (ss *SQLStore) WithDbSession(ctx context.Context, callback DBTransactionFunc) error {
return ss.withDbSession(ctx, ss.engine, callback)

View File

@ -85,11 +85,9 @@ func (ss *SQLStore) inTransactionWithRetryCtx(ctx context.Context, engine *xorm.
return err
}
if len(sess.events) > 0 {
for _, e := range sess.events {
if err = bus.Publish(ctx, e); err != nil {
ctxLogger.Error("Failed to publish event after commit.", "error", err)
}
for _, e := range sess.events {
if err = bus.Publish(ctx, e); err != nil {
ctxLogger.Error("Failed to publish event after commit.", "error", err)
}
}

View File

@ -2,8 +2,10 @@ package sqlstore
import (
"context"
"errors"
"testing"
"github.com/stretchr/testify/assert"
"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{}