fix(11-08): refuse unmanaged after-commit work
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
package lagoon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -191,21 +194,25 @@ func TestTransactionAfterCommit(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("plain_gorm_transaction_runs_now", func(t *testing.T) {
|
||||
var got *gorm.DB
|
||||
t.Run("plain_gorm_transaction_is_refused", func(t *testing.T) {
|
||||
var logs bytes.Buffer
|
||||
previous := slog.Default()
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(&logs, &slog.HandlerOptions{Level: slog.LevelWarn})))
|
||||
defer slog.SetDefault(previous)
|
||||
ran := false
|
||||
err := gdb.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
AfterCommit(ctx, tx, func(_ context.Context, d *gorm.DB) { got = d })
|
||||
if got == nil {
|
||||
t.Fatal("callback did not run immediately")
|
||||
}
|
||||
if got.Statement.ConnPool != tx.Statement.ConnPool {
|
||||
t.Error("callback did not run on the transaction's connection")
|
||||
}
|
||||
AfterCommit(ctx, tx, func(context.Context, *gorm.DB) { ran = true })
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ran {
|
||||
t.Fatal("callback ran inside an unmanaged transaction")
|
||||
}
|
||||
if !strings.Contains(logs.String(), "after-commit callback skipped inside unmanaged transaction") {
|
||||
t.Fatalf("warning = %q", logs.String())
|
||||
}
|
||||
})
|
||||
|
||||
// The handle a callback receives has an empty statement on the write's
|
||||
@@ -260,11 +267,14 @@ func TestTransactionAfterCommit(t *testing.T) {
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, name := range []string{"clean-implicit", "clean-plain-tx", "clean-lagoon-tx"} {
|
||||
for _, name := range []string{"clean-implicit", "clean-lagoon-tx"} {
|
||||
if got := labels[name]; got != "other" {
|
||||
t.Errorf("%s: query through the callback handle read %q, want the lagoon_ac_others row \"other\"", name, got)
|
||||
}
|
||||
}
|
||||
if _, ok := labels["clean-plain-tx"]; ok {
|
||||
t.Fatal("unmanaged transaction callback ran")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("outside_transaction_runs_now", func(t *testing.T) {
|
||||
@@ -311,6 +321,21 @@ func TestTransactionEdges(t *testing.T) {
|
||||
if got == nil {
|
||||
t.Fatal("callback of a Transaction with a nil ctx did not run with a context")
|
||||
}
|
||||
var nestedRan bool
|
||||
var nestedEntered bool
|
||||
err = Transaction(t.Context(), gdb, func(ctx context.Context, _ *gorm.DB) error {
|
||||
return Transaction(ctx, gdb, func(ctx context.Context, tx *gorm.DB) error {
|
||||
nestedEntered = true
|
||||
AfterCommit(ctx, tx, func(context.Context, *gorm.DB) { nestedRan = true })
|
||||
return nil
|
||||
})
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "parent transaction handle") {
|
||||
t.Fatalf("nested Transaction with root handle err = %v", err)
|
||||
}
|
||||
if nestedEntered || nestedRan {
|
||||
t.Fatal("nested root handle entered work or ran callbacks")
|
||||
}
|
||||
if err := registerAfterCommit(gdb); err != nil {
|
||||
t.Fatalf("registering the after-commit callback twice: %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user