grafana/pkg/services/sqlstore/transactions_test.go
Serge Zaitsev 522a98c126
Chore: Make Cfg field private in SQLStore (#85593)
* make cfg private in sqlstore

* fix db init in tests

* fix case

* fix folder test init

* fix imports

* make another Cfg private

* remove another Cfg

* remove unused variable

* use store cfg, it has side-effects

* fix mutated cfg in tests
2024-04-24 10:38:40 +02:00

142 lines
4.3 KiB
Go

package sqlstore
import (
"context"
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIntegrationReuseSessionWithTransaction(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
ss, _ := InitTestDB(t)
t.Run("top level transaction", func(t *testing.T) {
var outerSession *DBSession
err := ss.InTransaction(context.Background(), func(ctx context.Context) error {
value := ctx.Value(ContextSessionKey{})
var ok bool
outerSession, ok = value.(*DBSession)
require.True(t, ok, "Session should be available in the context but it does not exist")
require.True(t, outerSession.transactionOpen, "Transaction should be open")
require.NoError(t, ss.WithDbSession(ctx, func(sess *DBSession) error {
require.Equal(t, outerSession, sess)
require.False(t, sess.IsClosed(), "Session is closed but it should not be")
return nil
}))
require.NoError(t, ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
require.Equal(t, outerSession, sess)
require.False(t, sess.IsClosed(), "Session is closed but it should not be")
return nil
}))
require.False(t, outerSession.IsClosed(), "Session is closed but it should not be")
return nil
})
require.NoError(t, err)
require.True(t, outerSession.IsClosed())
})
t.Run("fails if reuses session without transaction", func(t *testing.T) {
require.NoError(t, ss.WithDbSession(context.Background(), func(outerSession *DBSession) error {
require.NotNil(t, outerSession)
require.NotNil(t, outerSession.DB()) // init the session
require.False(t, outerSession.IsClosed(), "Session is closed but it should not be")
ctx := context.WithValue(context.Background(), ContextSessionKey{}, outerSession)
require.NoError(t, ss.WithDbSession(ctx, func(sess *DBSession) error {
require.Equal(t, outerSession, sess)
require.False(t, sess.IsClosed(), "Session is closed but it should not be")
return nil
}))
require.Error(t, ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
require.FailNow(t, "WithTransactionalDbSession should not be able to reuse session that did not open the transaction ")
return nil
}))
return nil
}))
})
}
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{}