Refactor database interface to use *sql.DB directly
Simplified the database layer by removing custom interface wrappers and using standard library *sql.DB and *sql.Tx types directly. Changes: - Removed DBConnection and DBTransaction interfaces from database.go - Removed NewDBConnection() wrapper function - Updated TokenGenerator to use *sql.DB instead of DBConnection - Updated all validation and revocation methods to accept *sql.Tx - Updated TableManager to work with *sql.DB directly - Updated all tests to use db.Begin() instead of custom wrappers - Fixed GeneratorConfig.DB field (was DBConn) - Updated documentation in doc.go with correct API usage Benefits: - Simpler API with fewer abstractions - Works directly with database/sql standard library - Compatible with GORM (via gormDB.DB()) and Bun (share same *sql.DB) - Easier to understand and maintain - No unnecessary wrapper layers Breaking changes: - GeneratorConfig.DBConn renamed to GeneratorConfig.DB - Removed NewDBConnection() function - pass *sql.DB directly - ValidateAccess/ValidateRefresh now accept *sql.Tx instead of DBTransaction - Token.Revoke/CheckNotRevoked now accept *sql.Tx instead of DBTransaction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
221
jwt/tablemanager_test.go
Normal file
221
jwt/tablemanager_test.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewTableManager(t *testing.T) {
|
||||
db, _, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabasePostgreSQL, Version: "15"}
|
||||
config := DefaultTableConfig()
|
||||
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
require.NotNil(t, tm)
|
||||
}
|
||||
|
||||
func TestGetCreateTableSQL_PostgreSQL(t *testing.T) {
|
||||
db, _, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabasePostgreSQL, Version: "15"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
sql, err := tm.getCreateTableSQL()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, sql, "CREATE TABLE IF NOT EXISTS jwtblacklist")
|
||||
require.Contains(t, sql, "jti UUID PRIMARY KEY")
|
||||
require.Contains(t, sql, "exp BIGINT NOT NULL")
|
||||
require.Contains(t, sql, "sub INTEGER NOT NULL")
|
||||
require.Contains(t, sql, "CREATE INDEX IF NOT EXISTS idx_jwtblacklist_exp")
|
||||
require.Contains(t, sql, "CREATE INDEX IF NOT EXISTS idx_jwtblacklist_sub")
|
||||
}
|
||||
|
||||
func TestGetCreateTableSQL_MySQL(t *testing.T) {
|
||||
db, _, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabaseMySQL, Version: "8.0"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
sql, err := tm.getCreateTableSQL()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, sql, "CREATE TABLE IF NOT EXISTS jwtblacklist")
|
||||
require.Contains(t, sql, "jti CHAR(36) PRIMARY KEY")
|
||||
require.Contains(t, sql, "exp BIGINT NOT NULL")
|
||||
require.Contains(t, sql, "sub INT NOT NULL")
|
||||
require.Contains(t, sql, "INDEX idx_exp")
|
||||
require.Contains(t, sql, "ENGINE=InnoDB")
|
||||
}
|
||||
|
||||
func TestGetCreateTableSQL_SQLite(t *testing.T) {
|
||||
db, _, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabaseSQLite, Version: "3.42"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
sql, err := tm.getCreateTableSQL()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, sql, "CREATE TABLE IF NOT EXISTS jwtblacklist")
|
||||
require.Contains(t, sql, "jti TEXT PRIMARY KEY")
|
||||
require.Contains(t, sql, "exp INTEGER NOT NULL")
|
||||
require.Contains(t, sql, "sub INTEGER NOT NULL")
|
||||
}
|
||||
|
||||
func TestGetCreateTableSQL_CustomTableName(t *testing.T) {
|
||||
db, _, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabasePostgreSQL, Version: "15"}
|
||||
config := TableConfig{
|
||||
TableName: "custom_blacklist",
|
||||
AutoCreate: true,
|
||||
EnableAutoCleanup: false,
|
||||
CleanupInterval: 24,
|
||||
}
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
sql, err := tm.getCreateTableSQL()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, sql, "CREATE TABLE IF NOT EXISTS custom_blacklist")
|
||||
require.Contains(t, sql, "CREATE INDEX IF NOT EXISTS idx_custom_blacklist_exp")
|
||||
}
|
||||
|
||||
func TestGetCreateTableSQL_UnsupportedDB(t *testing.T) {
|
||||
db, _, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: "unsupported", Version: "1.0"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
sql, err := tm.getCreateTableSQL()
|
||||
require.Error(t, err)
|
||||
require.Empty(t, sql)
|
||||
require.Contains(t, err.Error(), "unsupported database type")
|
||||
}
|
||||
|
||||
func TestTableExists_PostgreSQL(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabasePostgreSQL, Version: "15"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
// Test table exists
|
||||
mock.ExpectQuery("SELECT 1 FROM information_schema.tables").
|
||||
WithArgs("jwtblacklist").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"1"}).AddRow(1))
|
||||
|
||||
exists, err := tm.tableExists(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.True(t, exists)
|
||||
|
||||
// Test table doesn't exist
|
||||
mock.ExpectQuery("SELECT 1 FROM information_schema.tables").
|
||||
WithArgs("jwtblacklist").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"1"}))
|
||||
|
||||
exists, err = tm.tableExists(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.False(t, exists)
|
||||
|
||||
require.NoError(t, mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func TestCreateTable_AlreadyExists(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabasePostgreSQL, Version: "15"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
// Mock table exists check
|
||||
mock.ExpectQuery("SELECT 1 FROM information_schema.tables").
|
||||
WithArgs("jwtblacklist").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"1"}).AddRow(1))
|
||||
|
||||
err = tm.CreateTable(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func TestCreateTable_Success(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabasePostgreSQL, Version: "15"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
// Mock table doesn't exist
|
||||
mock.ExpectQuery("SELECT 1 FROM information_schema.tables").
|
||||
WithArgs("jwtblacklist").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"1"}))
|
||||
|
||||
// Mock CREATE TABLE
|
||||
mock.ExpectExec("CREATE TABLE IF NOT EXISTS jwtblacklist").
|
||||
WillReturnResult(sqlmock.NewResult(0, 0))
|
||||
|
||||
err = tm.CreateTable(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func TestSetupAutoCleanup_Disabled(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabasePostgreSQL, Version: "15"}
|
||||
config := TableConfig{
|
||||
TableName: "jwtblacklist",
|
||||
AutoCreate: true,
|
||||
EnableAutoCleanup: false,
|
||||
CleanupInterval: 24,
|
||||
}
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
err = tm.SetupAutoCleanup(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func TestSetupAutoCleanup_SQLite(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
dbType := DatabaseType{Type: DatabaseSQLite, Version: "3.42"}
|
||||
config := DefaultTableConfig()
|
||||
tm := NewTableManager(db, dbType, config)
|
||||
|
||||
// SQLite doesn't support auto-cleanup, should return nil
|
||||
err = tm.SetupAutoCleanup(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, mock.ExpectationsWereMet())
|
||||
}
|
||||
Reference in New Issue
Block a user