gorm/tests/transaction_test.go

265 lines
6.8 KiB
Go

package tests_test
import (
"errors"
"testing"
"gorm.io/gorm"
. "gorm.io/gorm/utils/tests"
)
func TestTransaction(t *testing.T) {
tx := DB.Begin()
user := *GetUser("transaction", Config{})
if err := tx.Save(&user).Error; err != nil {
t.Fatalf("No error should raise, but got %v", err)
}
if err := tx.First(&User{}, "name = ?", "transaction").Error; err != nil {
t.Fatalf("Should find saved record, but got %v", err)
}
user1 := *GetUser("transaction1-1", Config{})
if err := tx.Save(&user1).Error; err != nil {
t.Fatalf("No error should raise, but got %v", err)
}
if err := tx.First(&User{}, "name = ?", user1.Name).Error; err != nil {
t.Fatalf("Should find saved record, but got %v", err)
}
if sqlTx, ok := tx.Statement.ConnPool.(gorm.TxCommitter); !ok || sqlTx == nil {
t.Fatalf("Should return the underlying sql.Tx")
}
tx.Rollback()
if err := DB.First(&User{}, "name = ?", "transaction").Error; err == nil {
t.Fatalf("Should not find record after rollback, but got %v", err)
}
tx2 := DB.Begin()
user2 := *GetUser("transaction-2", Config{})
if err := tx2.Save(&user2).Error; err != nil {
t.Fatalf("No error should raise, but got %v", err)
}
if err := tx2.First(&User{}, "name = ?", "transaction-2").Error; err != nil {
t.Fatalf("Should find saved record, but got %v", err)
}
tx2.Commit()
if err := DB.First(&User{}, "name = ?", "transaction-2").Error; err != nil {
t.Fatalf("Should be able to find committed record, but got %v", err)
}
}
func TestTransactionWithBlock(t *testing.T) {
assertPanic := func(f func()) {
defer func() {
if r := recover(); r == nil {
t.Fatalf("The code did not panic")
}
}()
f()
}
// rollback
err := DB.Transaction(func(tx *gorm.DB) error {
user := *GetUser("transaction-block", Config{})
if err := tx.Save(&user).Error; err != nil {
t.Fatalf("No error should raise")
}
if err := tx.First(&User{}, "name = ?", user.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
return errors.New("the error message")
})
if err.Error() != "the error message" {
t.Fatalf("Transaction return error will equal the block returns error")
}
if err := DB.First(&User{}, "name = ?", "transaction-block").Error; err == nil {
t.Fatalf("Should not find record after rollback")
}
// commit
DB.Transaction(func(tx *gorm.DB) error {
user := *GetUser("transaction-block-2", Config{})
if err := tx.Save(&user).Error; err != nil {
t.Fatalf("No error should raise")
}
if err := tx.First(&User{}, "name = ?", user.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
return nil
})
if err := DB.First(&User{}, "name = ?", "transaction-block-2").Error; err != nil {
t.Fatalf("Should be able to find committed record")
}
// panic will rollback
assertPanic(func() {
DB.Transaction(func(tx *gorm.DB) error {
user := *GetUser("transaction-block-3", Config{})
if err := tx.Save(&user).Error; err != nil {
t.Fatalf("No error should raise")
}
if err := tx.First(&User{}, "name = ?", user.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
panic("force panic")
})
})
if err := DB.First(&User{}, "name = ?", "transaction-block-3").Error; err == nil {
t.Fatalf("Should not find record after panic rollback")
}
}
func TestTransactionRaiseErrorOnRollbackAfterCommit(t *testing.T) {
tx := DB.Begin()
user := User{Name: "transaction"}
if err := tx.Save(&user).Error; err != nil {
t.Fatalf("No error should raise")
}
if err := tx.Commit().Error; err != nil {
t.Fatalf("Commit should not raise error")
}
if err := tx.Rollback().Error; err == nil {
t.Fatalf("Rollback after commit should raise error")
}
}
func TestTransactionWithSavePoint(t *testing.T) {
tx := DB.Begin()
user := *GetUser("transaction-save-point", Config{})
tx.Create(&user)
if err := tx.First(&User{}, "name = ?", user.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
if err := tx.SavePoint("save_point1").Error; err != nil {
t.Fatalf("Failed to save point, got error %v", err)
}
user1 := *GetUser("transaction-save-point-1", Config{})
tx.Create(&user1)
if err := tx.First(&User{}, "name = ?", user1.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
if err := tx.RollbackTo("save_point1").Error; err != nil {
t.Fatalf("Failed to save point, got error %v", err)
}
if err := tx.First(&User{}, "name = ?", user1.Name).Error; err == nil {
t.Fatalf("Should not find rollbacked record")
}
if err := tx.SavePoint("save_point2").Error; err != nil {
t.Fatalf("Failed to save point, got error %v", err)
}
user2 := *GetUser("transaction-save-point-2", Config{})
tx.Create(&user2)
if err := tx.First(&User{}, "name = ?", user2.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
if err := tx.Commit().Error; err != nil {
t.Fatalf("Failed to commit, got error %v", err)
}
if err := DB.First(&User{}, "name = ?", user.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
if err := DB.First(&User{}, "name = ?", user1.Name).Error; err == nil {
t.Fatalf("Should not find rollbacked record")
}
if err := DB.First(&User{}, "name = ?", user2.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
}
func TestNestedTransactionWithBlock(t *testing.T) {
var (
user = *GetUser("transaction-nested", Config{})
user1 = *GetUser("transaction-nested-1", Config{})
user2 = *GetUser("transaction-nested-2", Config{})
)
if err := DB.Transaction(func(tx *gorm.DB) error {
tx.Create(&user)
if err := tx.First(&User{}, "name = ?", user.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
if err := tx.Transaction(func(tx1 *gorm.DB) error {
tx1.Create(&user1)
if err := tx1.First(&User{}, "name = ?", user1.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
return errors.New("rollback")
}); err == nil {
t.Fatalf("nested transaction should returns error")
}
if err := tx.First(&User{}, "name = ?", user1.Name).Error; err == nil {
t.Fatalf("Should not find rollbacked record")
}
if err := tx.Transaction(func(tx2 *gorm.DB) error {
tx2.Create(&user2)
if err := tx2.First(&User{}, "name = ?", user2.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
return nil
}); err != nil {
t.Fatalf("nested transaction returns error: %v", err)
}
if err := tx.First(&User{}, "name = ?", user2.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
return nil
}); err != nil {
t.Fatalf("no error should return, but got %v", err)
}
if err := DB.First(&User{}, "name = ?", user.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
if err := DB.First(&User{}, "name = ?", user1.Name).Error; err == nil {
t.Fatalf("Should not find rollbacked record")
}
if err := DB.First(&User{}, "name = ?", user2.Name).Error; err != nil {
t.Fatalf("Should find saved record")
}
}