@@ -18,6 +18,36 @@ import (
1818
1919const testPostgresImage = "postgres:18-alpine"
2020
21+ func TestSerializableRetryDelay (t * testing.T ) {
22+ t .Parallel ()
23+
24+ for _ , tc := range []struct {
25+ attempt int
26+ minimum time.Duration
27+ maximum time.Duration
28+ }{
29+ {1 , 10 * time .Millisecond , 20 * time .Millisecond },
30+ {2 , 20 * time .Millisecond , 40 * time .Millisecond },
31+ {3 , 40 * time .Millisecond , 80 * time .Millisecond },
32+ {5 , 160 * time .Millisecond , 320 * time .Millisecond },
33+ {6 , 250 * time .Millisecond , 500 * time .Millisecond },
34+ {9 , 250 * time .Millisecond , 500 * time .Millisecond },
35+ } {
36+ t .Run (fmt .Sprintf ("attempt-%d" , tc .attempt ), func (t * testing.T ) {
37+ t .Parallel ()
38+
39+ delays := make (map [time.Duration ]struct {})
40+ for range 32 {
41+ delay := serializableRetryDelay (tc .attempt )
42+ require .GreaterOrEqual (t , delay , tc .minimum )
43+ require .Less (t , delay , tc .maximum )
44+ delays [delay ] = struct {}{}
45+ }
46+ assert .Greater (t , len (delays ), 1 , "retries must not use a deterministic delay" )
47+ })
48+ }
49+ }
50+
2151func TestConnectChecksAndConfiguresPool (t * testing.T ) {
2252 t .Parallel ()
2353
@@ -96,6 +126,9 @@ func TestAdvisoryLockRetriesSerializableTransactionOnItsSession(t *testing.T) {
96126 attempts := 0
97127 result , err := InSerializableTxReturn1 (t .Context (), lock , func (ctx context.Context , tx pgx.Tx ) (transactionResult , error ) {
98128 attempts ++
129+ deadline , ok := ctx .Deadline ()
130+ require .True (t , ok , "transaction attempts must have a deadline" )
131+ assert .LessOrEqual (t , time .Until (deadline ), 5 * time .Second )
99132
100133 var value int
101134 var backend int
@@ -194,6 +227,17 @@ func TestSerializableTransactionCleansUpAndBoundsReplays(t *testing.T) {
194227 ).Scan (& value ))
195228 assert .Equal (t , 3 , value )
196229
230+ deadline := time .Now ().Add (time .Second )
231+ shorter , cancelShorter := context .WithDeadline (t .Context (), deadline )
232+ defer cancelShorter ()
233+ require .NoError (t , lock .InSerializableTx (shorter , func (ctx context.Context , _ pgx.Tx ) error {
234+ actual , ok := ctx .Deadline ()
235+ require .True (t , ok )
236+ assert .Equal (t , deadline , actual , "transaction budget must not extend the caller's deadline" )
237+
238+ return nil
239+ }))
240+
197241 attempts := 0
198242 err = lock .InSerializableTx (t .Context (), func (context.Context , pgx.Tx ) error {
199243 attempts ++
0 commit comments