Files
dttmr-api/internal/repository/user_test.go
T

190 lines
5.1 KiB
Go

package repository
import (
"context"
"errors"
"fmt"
"regexp"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/robindittmar/dttmr-api/internal/domain"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUserRepo_CreateUser(t *testing.T) {
db, mock, err := sqlmock.New()
assert.NoError(t, err)
defer db.Close()
repo := NewUserRepo(db)
ctx := context.Background()
email := "test@example.com"
name := "Test User"
passwordHash := "hashedpassword123"
now := time.Now()
expectedUser := &domain.User{
ID: "1",
Email: email,
Name: name,
CreatedAt: now,
}
t.Run("success", func(t *testing.T) {
mock.ExpectBegin()
mock.ExpectQuery(`^INSERT INTO users \(email, name, password_hash\) VALUES \(\$1, \$2, \$3\) RETURNING id, created_at$`).
WithArgs(email, name, passwordHash).
WillReturnRows(sqlmock.NewRows([]string{"id", "created_at"}).AddRow(expectedUser.ID, expectedUser.CreatedAt))
mock.ExpectCommit()
user, err := repo.CreateUser(ctx, email, name, passwordHash)
assert.NoError(t, err)
assert.Equal(t, expectedUser, user)
assert.NoError(t, mock.ExpectationsWereMet())
})
t.Run("begin_tx_error", func(t *testing.T) {
mock.ExpectBegin().WillReturnError(fmt.Errorf("tx error"))
user, err := repo.CreateUser(ctx, email, name, passwordHash)
assert.Error(t, err)
assert.Contains(t, err.Error(), "begin transaction")
assert.Nil(t, user)
assert.NoError(t, mock.ExpectationsWereMet())
})
t.Run("insert_error", func(t *testing.T) {
mock.ExpectBegin()
mock.ExpectQuery(`^INSERT INTO users \(email, name, password_hash\) VALUES \(\$1, \$2, \$3\) RETURNING id, created_at$`).
WithArgs(email, name, passwordHash).
WillReturnError(fmt.Errorf("insert error"))
mock.ExpectRollback()
user, err := repo.CreateUser(ctx, email, name, passwordHash)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to insert user")
assert.Nil(t, user)
assert.NoError(t, mock.ExpectationsWereMet())
})
t.Run("commit_error", func(t *testing.T) {
mock.ExpectBegin()
mock.ExpectQuery(`^INSERT INTO users \(email, name, password_hash\) VALUES \(\$1, \$2, \$3\) RETURNING id, created_at$`).
WithArgs(email, name, passwordHash).
WillReturnRows(sqlmock.NewRows([]string{"id", "created_at"}).AddRow(expectedUser.ID, expectedUser.CreatedAt))
mock.ExpectCommit().WillReturnError(fmt.Errorf("commit error"))
user, err := repo.CreateUser(ctx, email, name, passwordHash)
assert.Error(t, err)
assert.Contains(t, err.Error(), "commit transaction")
assert.Nil(t, user)
assert.NoError(t, mock.ExpectationsWereMet())
})
}
func TestUserRepo_CreateUser2(t *testing.T) {
email := "test@example.com"
name := "Test User"
passwordHash := "hashedpassword123"
now := time.Now()
expectedID := "42"
insertQuery := regexp.QuoteMeta(
"INSERT INTO users (email, name, password_hash) VALUES ($1, $2, $3) RETURNING id, created_at",
)
testCases := []struct {
name string
setupMock func(mock sqlmock.Sqlmock)
expectedError string
}{
{
name: "Success: User created perfectly",
setupMock: func(mock sqlmock.Sqlmock) {
mock.ExpectBegin()
rows := sqlmock.NewRows([]string{"id", "created_at"}).
AddRow(expectedID, now)
mock.ExpectQuery(insertQuery).
WithArgs(email, name, passwordHash).
WillReturnRows(rows)
mock.ExpectCommit()
},
expectedError: "",
},
{
name: "Failure: Database connection fails on BeginTx",
setupMock: func(mock sqlmock.Sqlmock) {
mock.ExpectBegin().WillReturnError(errors.New("db connection failed"))
},
expectedError: "begin transaction: db connection failed",
},
{
name: "Failure: Query fails (e.g., duplicate email)",
setupMock: func(mock sqlmock.Sqlmock) {
mock.ExpectBegin()
mock.ExpectQuery(insertQuery).
WithArgs(email, name, passwordHash).
WillReturnError(errors.New("unique constraint violation"))
mock.ExpectRollback()
},
expectedError: "failed to insert user: unique constraint violation",
},
{
name: "Failure: Commit fails (e.g., network timeout)",
setupMock: func(mock sqlmock.Sqlmock) {
mock.ExpectBegin()
rows := sqlmock.NewRows([]string{"id", "created_at"}).
AddRow(expectedID, now)
mock.ExpectQuery(insertQuery).
WithArgs(email, name, passwordHash).
WillReturnRows(rows)
mock.ExpectCommit().WillReturnError(errors.New("commit timeout"))
},
expectedError: "commit transaction: commit timeout",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
db, mock, err := sqlmock.New()
require.NoError(t, err)
defer db.Close()
tc.setupMock(mock)
repo := NewUserRepo(db)
user, err := repo.CreateUser(context.Background(), email, name, passwordHash)
if tc.expectedError != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tc.expectedError)
assert.Nil(t, user)
} else {
require.NoError(t, err)
require.NotNil(t, user)
assert.Equal(t, expectedID, user.ID)
assert.Equal(t, email, user.Email)
assert.Equal(t, name, user.Name)
assert.Equal(t, now, user.CreatedAt)
}
assert.NoError(t, mock.ExpectationsWereMet())
})
}
}