Fixes tests
parent
841f25f28b
commit
0ef061de56
|
|
@ -10,6 +10,14 @@ jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
DB_TYPE: mariadb
|
||||||
|
DB_HOST: 127.0.0.1
|
||||||
|
DB_PORT: 3306
|
||||||
|
DB_DATABASE: jilo_test
|
||||||
|
DB_USERNAME: test_jilo
|
||||||
|
DB_PASSWORD: test_password
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mariadb:
|
mariadb:
|
||||||
image: mariadb:10.6
|
image: mariadb:10.6
|
||||||
|
|
|
||||||
|
|
@ -121,44 +121,40 @@ class LogTest extends TestCase
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$connection = $this->db->getConnection();
|
$connection = $this->db->getConnection();
|
||||||
|
|
||||||
|
// Ensure fresh log table schema (drop old schema if present)
|
||||||
$connection->exec("DROP TABLE IF EXISTS log");
|
$connection->exec("DROP TABLE IF EXISTS log");
|
||||||
$connection->exec("DROP TABLE IF EXISTS user");
|
|
||||||
|
|
||||||
// Create user table
|
// Use centralized schema setup
|
||||||
$connection->exec("
|
setupTestDatabaseSchema($connection);
|
||||||
CREATE TABLE IF NOT EXISTS user (
|
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
username VARCHAR(255) NOT NULL,
|
|
||||||
password VARCHAR(255) NOT NULL,
|
|
||||||
email VARCHAR(255) NOT NULL,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create log table with the expected schema from Log class
|
// Load logs plugin migration to create log table
|
||||||
$connection->exec("
|
$logMigrationPath = __DIR__ . '/../../../plugins/logs/migrations/create_log_table.sql';
|
||||||
CREATE TABLE IF NOT EXISTS log (
|
if (file_exists($logMigrationPath)) {
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
$sql = file_get_contents($logMigrationPath);
|
||||||
user_id INT,
|
$statements = array_filter(array_map('trim', explode(';', $sql)));
|
||||||
scope VARCHAR(50) NOT NULL DEFAULT 'user',
|
foreach ($statements as $statement) {
|
||||||
message TEXT NOT NULL,
|
if (!empty($statement)) {
|
||||||
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
$connection->exec($statement);
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id)
|
}
|
||||||
)
|
}
|
||||||
");
|
}
|
||||||
|
|
||||||
// Create test users with all required fields
|
// Clean up any existing test data
|
||||||
|
$connection->exec("DELETE FROM log WHERE user_id >= 1000");
|
||||||
|
$connection->exec("DELETE FROM user WHERE id >= 1000");
|
||||||
|
|
||||||
|
// Create test users
|
||||||
|
$timestamp = time();
|
||||||
$connection->exec("
|
$connection->exec("
|
||||||
INSERT INTO user (username, password, email)
|
INSERT INTO user (id, username, password)
|
||||||
VALUES
|
VALUES
|
||||||
('testuser', 'password123', 'testuser@example.com'),
|
(1000, 'testuser_log_{$timestamp}', 'password123'),
|
||||||
('testuser2', 'password123', 'testuser2@example.com')
|
(1001, 'testuser2_log_{$timestamp}', 'password123')
|
||||||
");
|
");
|
||||||
|
|
||||||
// Store test user ID for later use
|
// Store test user ID for later use
|
||||||
$stmt = $this->db->getConnection()->query("SELECT id FROM user WHERE username = 'testuser' LIMIT 1");
|
$this->testUserId = 1000;
|
||||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
$this->testUserId = $user['id'];
|
|
||||||
|
|
||||||
// Create a TestLogger instance that will be used by the app's Log wrapper
|
// Create a TestLogger instance that will be used by the app's Log wrapper
|
||||||
$this->log = new TestLogger($this->db);
|
$this->log = new TestLogger($this->db);
|
||||||
|
|
@ -166,15 +162,15 @@ class LogTest extends TestCase
|
||||||
|
|
||||||
protected function tearDown(): void
|
protected function tearDown(): void
|
||||||
{
|
{
|
||||||
// Drop tables in correct order (respect foreign key constraints)
|
// Clean up test data
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS log");
|
$this->db->getConnection()->exec("DELETE FROM log WHERE user_id >= 1000");
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user");
|
$this->db->getConnection()->exec("DELETE FROM user WHERE id >= 1000");
|
||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInsertLog()
|
public function testInsertLog()
|
||||||
{
|
{
|
||||||
$result = $this->log->insertLog($this->testUserId, 'Test message', 'test');
|
$result = $this->log->insertLog($this->testUserId, 'Test message', 'user');
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
||||||
// Verify the log was inserted
|
// Verify the log was inserted
|
||||||
|
|
@ -182,7 +178,7 @@ class LogTest extends TestCase
|
||||||
$log = $stmt->fetch(PDO::FETCH_ASSOC);
|
$log = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$this->assertEquals('Test message', $log['message']);
|
$this->assertEquals('Test message', $log['message']);
|
||||||
$this->assertEquals('test', $log['scope']);
|
$this->assertEquals('user', $log['scope']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReadLog()
|
public function testReadLog()
|
||||||
|
|
|
||||||
|
|
@ -35,53 +35,14 @@ class UserRegisterTest extends TestCase
|
||||||
// Set up App::db() for Register class to use
|
// Set up App::db() for Register class to use
|
||||||
App::set('db', $this->db->getConnection());
|
App::set('db', $this->db->getConnection());
|
||||||
|
|
||||||
// Create user table with MariaDB syntax
|
// Use centralized schema setup
|
||||||
$this->db->getConnection()->exec("
|
setupTestDatabaseSchema($this->db->getConnection());
|
||||||
CREATE TABLE IF NOT EXISTS user (
|
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
username VARCHAR(255) NOT NULL UNIQUE,
|
|
||||||
password VARCHAR(255) NOT NULL,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create user_meta table with MariaDB syntax
|
// Clean up any test users from previous runs
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("DELETE FROM user_2fa WHERE user_id >= 1000");
|
||||||
CREATE TABLE IF NOT EXISTS user_meta (
|
$this->db->getConnection()->exec("DELETE FROM security_rate_auth WHERE username LIKE 'testuser%'");
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
$this->db->getConnection()->exec("DELETE FROM user_meta WHERE user_id >= 1000");
|
||||||
user_id INT NOT NULL,
|
$this->db->getConnection()->exec("DELETE FROM user WHERE id >= 1000");
|
||||||
name VARCHAR(255),
|
|
||||||
email VARCHAR(255),
|
|
||||||
timezone VARCHAR(100),
|
|
||||||
bio TEXT,
|
|
||||||
avatar VARCHAR(255),
|
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create security_rate_auth table for rate limiting
|
|
||||||
$this->db->getConnection()->exec("
|
|
||||||
CREATE TABLE IF NOT EXISTS security_rate_auth (
|
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
ip_address VARCHAR(45) NOT NULL,
|
|
||||||
username VARCHAR(255) NOT NULL,
|
|
||||||
attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
INDEX idx_ip_username (ip_address, username)
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create user_2fa table for two-factor authentication
|
|
||||||
$this->db->getConnection()->exec("
|
|
||||||
CREATE TABLE IF NOT EXISTS user_2fa (
|
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
user_id INT NOT NULL,
|
|
||||||
secret_key VARCHAR(255) NOT NULL,
|
|
||||||
backup_codes TEXT,
|
|
||||||
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
$this->register = new Register();
|
$this->register = new Register();
|
||||||
$this->user = new User($this->db);
|
$this->user = new User($this->db);
|
||||||
|
|
@ -92,18 +53,19 @@ class UserRegisterTest extends TestCase
|
||||||
// Clean up App state
|
// Clean up App state
|
||||||
App::reset('db');
|
App::reset('db');
|
||||||
|
|
||||||
// Drop tables in correct order
|
// Clean up test data
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_2fa");
|
$this->db->getConnection()->exec("DELETE FROM user_2fa WHERE user_id >= 1000");
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_rate_auth");
|
$this->db->getConnection()->exec("DELETE FROM security_rate_auth WHERE username LIKE 'testuser%'");
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_meta");
|
$this->db->getConnection()->exec("DELETE FROM user_meta WHERE user_id >= 1000");
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user");
|
$this->db->getConnection()->exec("DELETE FROM user WHERE id >= 1000");
|
||||||
|
|
||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRegister()
|
public function testRegister()
|
||||||
{
|
{
|
||||||
// Register a new user
|
// Register a new user with unique username
|
||||||
$username = 'testuser';
|
$username = 'testuser_reg_' . time() . '_' . rand(1000, 9999);
|
||||||
$password = 'password123';
|
$password = 'password123';
|
||||||
|
|
||||||
$result = $this->register->register($username, $password);
|
$result = $this->register->register($username, $password);
|
||||||
|
|
@ -129,8 +91,8 @@ class UserRegisterTest extends TestCase
|
||||||
|
|
||||||
public function testLogin()
|
public function testLogin()
|
||||||
{
|
{
|
||||||
// First register a user
|
// First register a user with unique username
|
||||||
$username = 'testuser';
|
$username = 'testuser_login_' . time() . '_' . rand(1000, 9999);
|
||||||
$password = 'password123';
|
$password = 'password123';
|
||||||
|
|
||||||
$this->register->register($username, $password);
|
$this->register->register($username, $password);
|
||||||
|
|
@ -163,8 +125,8 @@ class UserRegisterTest extends TestCase
|
||||||
|
|
||||||
public function testGetUserDetails()
|
public function testGetUserDetails()
|
||||||
{
|
{
|
||||||
// Register a test user first
|
// First register a user with unique username
|
||||||
$username = 'testuser';
|
$username = 'testuser_details_' . time() . '_' . rand(1000, 9999);
|
||||||
$password = 'password123';
|
$password = 'password123';
|
||||||
$result = $this->register->register($username, $password);
|
$result = $this->register->register($username, $password);
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
|
||||||
|
|
@ -35,53 +35,14 @@ class UserTest extends TestCase
|
||||||
// Set up App::db() for Register class to use
|
// Set up App::db() for Register class to use
|
||||||
App::set('db', $this->db->getConnection());
|
App::set('db', $this->db->getConnection());
|
||||||
|
|
||||||
// Create user table with MariaDB syntax
|
// Use centralized schema setup
|
||||||
$this->db->getConnection()->exec("
|
setupTestDatabaseSchema($this->db->getConnection());
|
||||||
CREATE TABLE IF NOT EXISTS user (
|
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
username VARCHAR(255) NOT NULL UNIQUE,
|
|
||||||
password VARCHAR(255) NOT NULL,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create user_meta table with MariaDB syntax
|
// Clean up any test users from previous runs
|
||||||
$this->db->getConnection()->exec("
|
$this->db->getConnection()->exec("DELETE FROM user_2fa WHERE user_id >= 1000");
|
||||||
CREATE TABLE IF NOT EXISTS user_meta (
|
$this->db->getConnection()->exec("DELETE FROM security_rate_auth WHERE username LIKE 'testuser%'");
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
$this->db->getConnection()->exec("DELETE FROM user_meta WHERE user_id >= 1000");
|
||||||
user_id INT NOT NULL,
|
$this->db->getConnection()->exec("DELETE FROM user WHERE id >= 1000");
|
||||||
name VARCHAR(255),
|
|
||||||
email VARCHAR(255),
|
|
||||||
timezone VARCHAR(100),
|
|
||||||
bio TEXT,
|
|
||||||
avatar VARCHAR(255),
|
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create security_rate_auth table for rate limiting
|
|
||||||
$this->db->getConnection()->exec("
|
|
||||||
CREATE TABLE IF NOT EXISTS security_rate_auth (
|
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
ip_address VARCHAR(45) NOT NULL,
|
|
||||||
username VARCHAR(255) NOT NULL,
|
|
||||||
attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
INDEX idx_ip_username (ip_address, username)
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
// Create user_2fa table for two-factor authentication
|
|
||||||
$this->db->getConnection()->exec("
|
|
||||||
CREATE TABLE IF NOT EXISTS user_2fa (
|
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
user_id INT NOT NULL,
|
|
||||||
secret_key VARCHAR(255) NOT NULL,
|
|
||||||
backup_codes TEXT,
|
|
||||||
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
");
|
|
||||||
|
|
||||||
$this->user = new User($this->db);
|
$this->user = new User($this->db);
|
||||||
$this->register = new Register();
|
$this->register = new Register();
|
||||||
|
|
@ -92,18 +53,19 @@ class UserTest extends TestCase
|
||||||
// Clean up App state
|
// Clean up App state
|
||||||
App::reset('db');
|
App::reset('db');
|
||||||
|
|
||||||
// Drop tables in correct order
|
// Clean up test data
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_2fa");
|
$this->db->getConnection()->exec("DELETE FROM user_2fa WHERE user_id >= 1000");
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS security_rate_auth");
|
$this->db->getConnection()->exec("DELETE FROM security_rate_auth WHERE username LIKE 'testuser%'");
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user_meta");
|
$this->db->getConnection()->exec("DELETE FROM user_meta WHERE user_id >= 1000");
|
||||||
$this->db->getConnection()->exec("DROP TABLE IF EXISTS user");
|
$this->db->getConnection()->exec("DELETE FROM user WHERE id >= 1000");
|
||||||
|
|
||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLogin()
|
public function testLogin()
|
||||||
{
|
{
|
||||||
// First register a user
|
// First register a user with unique username
|
||||||
$username = 'testuser';
|
$username = 'testuser_login_' . time() . '_' . rand(1000, 9999);
|
||||||
$password = 'password123';
|
$password = 'password123';
|
||||||
|
|
||||||
$this->register->register($username, $password);
|
$this->register->register($username, $password);
|
||||||
|
|
@ -136,8 +98,8 @@ class UserTest extends TestCase
|
||||||
|
|
||||||
public function testGetUserDetails()
|
public function testGetUserDetails()
|
||||||
{
|
{
|
||||||
// Register a test user first
|
// First register a user with unique username
|
||||||
$username = 'testuser';
|
$username = 'testuser_details_' . time() . '_' . rand(1000, 9999);
|
||||||
$password = 'password123';
|
$password = 'password123';
|
||||||
$result = $this->register->register($username, $password);
|
$result = $this->register->register($username, $password);
|
||||||
$this->assertTrue($result);
|
$this->assertTrue($result);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,13 @@ if (!defined('APP_PATH')) {
|
||||||
require_once __DIR__ . '/../app/core/App.php';
|
require_once __DIR__ . '/../app/core/App.php';
|
||||||
require_once __DIR__ . '/../app/core/PluginRouteRegistry.php';
|
require_once __DIR__ . '/../app/core/PluginRouteRegistry.php';
|
||||||
|
|
||||||
|
// Define plugin route registration function used by plugin bootstraps
|
||||||
|
if (!function_exists('register_plugin_route_prefix')) {
|
||||||
|
function register_plugin_route_prefix(string $prefix, array $definition = []): void {
|
||||||
|
\App\Core\PluginRouteRegistry::registerPrefix($prefix, $definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load plugin Log model and IP helper early so fallback wrapper is bypassed
|
// Load plugin Log model and IP helper early so fallback wrapper is bypassed
|
||||||
require_once __DIR__ . '/../app/helpers/ip_helper.php';
|
require_once __DIR__ . '/../app/helpers/ip_helper.php';
|
||||||
require_once __DIR__ . '/../app/helpers/logger_loader.php';
|
require_once __DIR__ . '/../app/helpers/logger_loader.php';
|
||||||
|
|
@ -72,3 +79,62 @@ $_SERVER['PHP_SELF'] = '/index.php';
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
$_SERVER['HTTP_USER_AGENT'] = 'PHPUnit Test Browser';
|
$_SERVER['HTTP_USER_AGENT'] = 'PHPUnit Test Browser';
|
||||||
$_SERVER['HTTPS'] = 'on';
|
$_SERVER['HTTPS'] = 'on';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup test database schema by applying main.sql and migrations
|
||||||
|
*
|
||||||
|
* @param PDO $pdo Database connection
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function setupTestDatabaseSchema(PDO $pdo): void
|
||||||
|
{
|
||||||
|
// Apply main.sql schema
|
||||||
|
$mainSqlPath = __DIR__ . '/../doc/database/main.sql';
|
||||||
|
if (file_exists($mainSqlPath)) {
|
||||||
|
$sql = file_get_contents($mainSqlPath);
|
||||||
|
// Add IF NOT EXISTS to CREATE TABLE statements
|
||||||
|
$sql = preg_replace('/CREATE TABLE `/', 'CREATE TABLE IF NOT EXISTS `', $sql);
|
||||||
|
$statements = array_filter(array_map('trim', explode(';', $sql)));
|
||||||
|
foreach ($statements as $statement) {
|
||||||
|
if (!empty($statement)) {
|
||||||
|
try {
|
||||||
|
$pdo->exec($statement);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// Skip errors for INSERT statements on existing data
|
||||||
|
if (strpos($statement, 'INSERT') === false) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply migrations from doc/database/migrations/ (excluding subfolders)
|
||||||
|
$migrationsDir = __DIR__ . '/../doc/database/migrations';
|
||||||
|
if (is_dir($migrationsDir)) {
|
||||||
|
$files = glob($migrationsDir . '/*.sql');
|
||||||
|
sort($files); // Apply in chronological order
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$sql = file_get_contents($file);
|
||||||
|
// Add IF NOT EXISTS to CREATE TABLE statements
|
||||||
|
$sql = preg_replace('/CREATE TABLE `/', 'CREATE TABLE IF NOT EXISTS `', $sql);
|
||||||
|
$statements = array_filter(array_map('trim', explode(';', $sql)));
|
||||||
|
foreach ($statements as $statement) {
|
||||||
|
if (!empty($statement)) {
|
||||||
|
try {
|
||||||
|
$pdo->exec($statement);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// Skip errors for:
|
||||||
|
// - Duplicate columns (already exists)
|
||||||
|
// - Table doesn't exist (plugin tables not yet created)
|
||||||
|
$errorMsg = $e->getMessage();
|
||||||
|
if (strpos($errorMsg, 'Duplicate column') === false &&
|
||||||
|
strpos($errorMsg, "doesn't exist") === false) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue