2023-08-17 18:25:16 +00:00
|
|
|
package database_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/lib/pq"
|
|
|
|
"github.com/stretchr/testify/require"
|
2024-01-05 00:35:56 +00:00
|
|
|
"go.uber.org/mock/gomock"
|
2023-08-17 18:25:16 +00:00
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
2023-08-18 18:55:43 +00:00
|
|
|
"github.com/coder/coder/v2/coderd/database"
|
|
|
|
"github.com/coder/coder/v2/coderd/database/dbmock"
|
2023-08-17 18:25:16 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestReadModifyUpdate_OK(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
mDB := dbmock.NewMockStore(gomock.NewController(t))
|
|
|
|
|
|
|
|
mDB.EXPECT().
|
|
|
|
InTx(gomock.Any(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead}).
|
|
|
|
Times(1).
|
|
|
|
Return(nil)
|
|
|
|
err := database.ReadModifyUpdate(mDB, func(tx database.Store) error {
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReadModifyUpdate_RetryOK(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
mDB := dbmock.NewMockStore(gomock.NewController(t))
|
|
|
|
|
|
|
|
firstUpdate := mDB.EXPECT().
|
|
|
|
InTx(gomock.Any(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead}).
|
|
|
|
Times(1).
|
|
|
|
Return(&pq.Error{Code: pq.ErrorCode("40001")})
|
|
|
|
mDB.EXPECT().
|
|
|
|
InTx(gomock.Any(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead}).
|
|
|
|
After(firstUpdate).
|
|
|
|
Times(1).
|
|
|
|
Return(nil)
|
|
|
|
|
|
|
|
err := database.ReadModifyUpdate(mDB, func(tx database.Store) error {
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReadModifyUpdate_HardError(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
mDB := dbmock.NewMockStore(gomock.NewController(t))
|
|
|
|
|
|
|
|
mDB.EXPECT().
|
|
|
|
InTx(gomock.Any(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead}).
|
|
|
|
Times(1).
|
|
|
|
Return(xerrors.New("a bad thing happened"))
|
|
|
|
|
|
|
|
err := database.ReadModifyUpdate(mDB, func(tx database.Store) error {
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
require.ErrorContains(t, err, "a bad thing happened")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReadModifyUpdate_TooManyRetries(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
mDB := dbmock.NewMockStore(gomock.NewController(t))
|
|
|
|
|
|
|
|
mDB.EXPECT().
|
|
|
|
InTx(gomock.Any(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead}).
|
|
|
|
Times(5).
|
|
|
|
Return(&pq.Error{Code: pq.ErrorCode("40001")})
|
|
|
|
err := database.ReadModifyUpdate(mDB, func(tx database.Store) error {
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
require.ErrorContains(t, err, "too many errors")
|
|
|
|
}
|