package services import ( "database/sql" "regexp" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "veza-backend-api/internal/database" ) // Helper to setup mock DB func setupMockDB(t *testing.T) (*database.Database, sqlmock.Sqlmock) { db, mock, err := sqlmock.New() require.NoError(t, err) dbWrapper := &database.Database{ DB: db, Logger: zap.NewNop(), } return dbWrapper, mock } func TestOAuthService_GenerateStateToken_Success(t *testing.T) { // Setup db, mock := setupMockDB(t) defer db.DB.Close() logger := zap.NewNop() service := &OAuthService{ db: db, logger: logger, } provider := "google" redirectURL := "http://example.com" // Expectation mock.ExpectExec(regexp.QuoteMeta(`INSERT INTO oauth_states`)). WithArgs(sqlmock.AnyArg(), provider, redirectURL, sqlmock.AnyArg()). WillReturnResult(sqlmock.NewResult(1, 1)) // Execute token, err := service.GenerateStateToken(provider, redirectURL) // Assert assert.NoError(t, err) assert.NotEmpty(t, token) assert.NoError(t, mock.ExpectationsWereMet()) } func TestOAuthService_ValidateStateToken_Success(t *testing.T) { // Setup db, mock := setupMockDB(t) defer db.DB.Close() logger := zap.NewNop() service := &OAuthService{ db: db, logger: logger, } token := "valid_token" now := time.Now() // Expectation rows := sqlmock.NewRows([]string{"id", "state_token", "provider", "redirect_url", "expires_at", "created_at"}). AddRow(1, token, "google", "http://example.com", now.Add(time.Hour), now) mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, state_token, provider, redirect_url, expires_at, created_at FROM oauth_states WHERE state_token = $1`)). WithArgs(token). WillReturnRows(rows) mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM oauth_states WHERE id = $1`)). WithArgs(1). WillReturnResult(sqlmock.NewResult(1, 1)) // Execute state, err := service.ValidateStateToken(token) // Assert assert.NoError(t, err) assert.NotNil(t, state) assert.Equal(t, token, state.StateToken) assert.NoError(t, mock.ExpectationsWereMet()) } func TestOAuthService_ValidateStateToken_NotFound(t *testing.T) { // Setup db, mock := setupMockDB(t) defer db.DB.Close() logger := zap.NewNop() service := &OAuthService{ db: db, logger: logger, } token := "invalid_token" // Expectation mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, state_token, provider, redirect_url, expires_at, created_at FROM oauth_states WHERE state_token = $1`)). WithArgs(token). WillReturnError(sql.ErrNoRows) // Execute state, err := service.ValidateStateToken(token) // Assert assert.Error(t, err) assert.Equal(t, "invalid state token", err.Error()) assert.Nil(t, state) assert.NoError(t, mock.ExpectationsWereMet()) } func TestOAuthService_ValidateStateToken_Expired(t *testing.T) { // Setup db, mock := setupMockDB(t) defer db.DB.Close() logger := zap.NewNop() service := &OAuthService{ db: db, logger: logger, } token := "expired_token" now := time.Now() // Expectation rows := sqlmock.NewRows([]string{"id", "state_token", "provider", "redirect_url", "expires_at", "created_at"}). AddRow(1, token, "google", "http://example.com", now.Add(-time.Hour), now.Add(-2*time.Hour)) mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, state_token, provider, redirect_url, expires_at, created_at FROM oauth_states WHERE state_token = $1`)). WithArgs(token). WillReturnRows(rows) // Execute state, err := service.ValidateStateToken(token) // Assert assert.Error(t, err) assert.Equal(t, "state token expired", err.Error()) assert.Nil(t, state) assert.NoError(t, mock.ExpectationsWereMet()) }