mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 06:21:11 +00:00 
			
		
		
		
	- Older code (154 places to be exact) that want to do transactions uses `TxContext`. If the context is not already in a transaction then it uses `DefaultContext` for the new transaction. - Not reusing the context it was given leads to two problems: for tracing (forgejo/forgejo#6470) any SQL code that is executed inside this transaction is not shown in the trace. If the context is cancelled then the transaction is not cancelled and will always complete (given there's no SQL error). - When this function was introduced it didn't take a parent context, hence the usage of `DefaultContext`. When `parentCtx` was introduced it was only used to avoid nested transactions and use the parent's transaction. I do not see any reasons why the parent context cannot be reused, it is reused in the newer transaction function `WithTx` without any known problems. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8464 Reviewed-by: Otto <otto@codeberg.org> Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Co-authored-by: Gusted <postmaster@gusted.xyz> Co-committed-by: Gusted <postmaster@gusted.xyz>
		
			
				
	
	
		
			99 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2022 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package db_test
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"testing"
 | |
| 
 | |
| 	"forgejo.org/models/db"
 | |
| 	"forgejo.org/models/unittest"
 | |
| 
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| )
 | |
| 
 | |
| func TestInTransaction(t *testing.T) {
 | |
| 	require.NoError(t, unittest.PrepareTestDatabase())
 | |
| 	assert.False(t, db.InTransaction(db.DefaultContext))
 | |
| 	require.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error {
 | |
| 		assert.True(t, db.InTransaction(ctx))
 | |
| 		return nil
 | |
| 	}))
 | |
| 
 | |
| 	ctx, committer, err := db.TxContext(db.DefaultContext)
 | |
| 	require.NoError(t, err)
 | |
| 	defer committer.Close()
 | |
| 	assert.True(t, db.InTransaction(ctx))
 | |
| 	require.NoError(t, db.WithTx(ctx, func(ctx context.Context) error {
 | |
| 		assert.True(t, db.InTransaction(ctx))
 | |
| 		return nil
 | |
| 	}))
 | |
| }
 | |
| 
 | |
| func TestTxContext(t *testing.T) {
 | |
| 	require.NoError(t, unittest.PrepareTestDatabase())
 | |
| 
 | |
| 	{ // create new transaction
 | |
| 		ctx, committer, err := db.TxContext(db.DefaultContext)
 | |
| 		require.NoError(t, err)
 | |
| 		assert.True(t, db.InTransaction(ctx))
 | |
| 		require.NoError(t, committer.Commit())
 | |
| 	}
 | |
| 
 | |
| 	{ // reuse the transaction created by TxContext and commit it
 | |
| 		ctx, committer, err := db.TxContext(db.DefaultContext)
 | |
| 		engine := db.GetEngine(ctx)
 | |
| 		require.NoError(t, err)
 | |
| 		assert.True(t, db.InTransaction(ctx))
 | |
| 		{
 | |
| 			ctx, committer, err := db.TxContext(ctx)
 | |
| 			require.NoError(t, err)
 | |
| 			assert.True(t, db.InTransaction(ctx))
 | |
| 			assert.Equal(t, engine, db.GetEngine(ctx))
 | |
| 			require.NoError(t, committer.Commit())
 | |
| 		}
 | |
| 		require.NoError(t, committer.Commit())
 | |
| 	}
 | |
| 
 | |
| 	{ // reuse the transaction created by TxContext and close it
 | |
| 		ctx, committer, err := db.TxContext(db.DefaultContext)
 | |
| 		engine := db.GetEngine(ctx)
 | |
| 		require.NoError(t, err)
 | |
| 		assert.True(t, db.InTransaction(ctx))
 | |
| 		{
 | |
| 			ctx, committer, err := db.TxContext(ctx)
 | |
| 			require.NoError(t, err)
 | |
| 			assert.True(t, db.InTransaction(ctx))
 | |
| 			assert.Equal(t, engine, db.GetEngine(ctx))
 | |
| 			require.NoError(t, committer.Close())
 | |
| 		}
 | |
| 		require.NoError(t, committer.Close())
 | |
| 	}
 | |
| 
 | |
| 	{ // reuse the transaction created by WithTx
 | |
| 		require.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error {
 | |
| 			assert.True(t, db.InTransaction(ctx))
 | |
| 			{
 | |
| 				ctx, committer, err := db.TxContext(ctx)
 | |
| 				require.NoError(t, err)
 | |
| 				assert.True(t, db.InTransaction(ctx))
 | |
| 				require.NoError(t, committer.Commit())
 | |
| 			}
 | |
| 			return nil
 | |
| 		}))
 | |
| 	}
 | |
| 
 | |
| 	t.Run("Reuses parent context", func(t *testing.T) {
 | |
| 		type unique struct{}
 | |
| 
 | |
| 		ctx := context.WithValue(db.DefaultContext, unique{}, "yes!")
 | |
| 		assert.False(t, db.InTransaction(ctx))
 | |
| 
 | |
| 		require.NoError(t, db.WithTx(ctx, func(ctx context.Context) error {
 | |
| 			assert.Equal(t, "yes!", ctx.Value(unique{}))
 | |
| 			return nil
 | |
| 		}))
 | |
| 	})
 | |
| }
 |