StartTx starts a transaction and returns a DBTx object. This allows running 2 transactions concurrently in a test more easily. Example: a := StartTx(t, db, opts) b := StartTx(t, db, opts) a.GetUsers(...) b.GetUsers(...) require.NoError(t, a.Done()
(t *testing.T, db database.Store, opts *database.TxOptions)
| 29 | // |
| 30 | // require.NoError(t, a.Done() |
| 31 | func StartTx(t *testing.T, db database.Store, opts *database.TxOptions) *DBTx { |
| 32 | done := make(chan error) |
| 33 | finalErr := make(chan error) |
| 34 | txC := make(chan database.Store) |
| 35 | |
| 36 | go func() { |
| 37 | t.Helper() |
| 38 | once := sync.Once{} |
| 39 | count := 0 |
| 40 | |
| 41 | err := db.InTx(func(store database.Store) error { |
| 42 | // InTx can be retried |
| 43 | once.Do(func() { |
| 44 | txC <- store |
| 45 | }) |
| 46 | count++ |
| 47 | if count > 1 { |
| 48 | // If you recursively call InTx, then don't use this. |
| 49 | t.Logf("InTx called more than once: %d", count) |
| 50 | assert.NoError(t, xerrors.New("InTx called more than once, this is not allowed with the StartTx helper")) |
| 51 | } |
| 52 | |
| 53 | <-done |
| 54 | // Just return nil. The caller should be checking their own errors. |
| 55 | return nil |
| 56 | }, opts) |
| 57 | finalErr <- err |
| 58 | }() |
| 59 | |
| 60 | txStore := <-txC |
| 61 | close(txC) |
| 62 | |
| 63 | return &DBTx{Store: txStore, done: done, finalErr: finalErr} |
| 64 | } |
| 65 | |
| 66 | // Done can only be called once. If you call it twice, it will panic. |
| 67 | func (tx *DBTx) Done() error { |