171 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			PHP
		
	
			
		
		
	
	
			171 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			PHP
		
	
| <?php
 | |
| 
 | |
| require_once dirname(__DIR__, 3) . '/app/classes/database.php';
 | |
| require_once dirname(__DIR__, 3) . '/app/classes/user.php';
 | |
| require_once dirname(__DIR__, 3) . '/plugins/register/models/register.php';
 | |
| require_once dirname(__DIR__, 3) . '/app/classes/ratelimiter.php';
 | |
| 
 | |
| use PHPUnit\Framework\TestCase;
 | |
| 
 | |
| class UserTest extends TestCase
 | |
| {
 | |
|     private $db;
 | |
|     private $register;
 | |
|     private $user;
 | |
| 
 | |
|     protected function setUp(): void
 | |
|     {
 | |
|         parent::setUp();
 | |
| 
 | |
|         // Prepare DB for Github CI
 | |
|         $host = defined('CI_DB_HOST') ? CI_DB_HOST : '127.0.0.1';
 | |
|         $password = defined('CI_DB_PASSWORD') ? CI_DB_PASSWORD : '';
 | |
| 
 | |
|         $this->db = new Database([
 | |
|             'type' => 'mariadb',
 | |
|             'host' => $host,
 | |
|             'port' => '3306',
 | |
|             'dbname' => 'jilo_test',
 | |
|             'user' => 'test_jilo',
 | |
|             'password' => $password
 | |
|         ]);
 | |
| 
 | |
|         // Create user table with MariaDB syntax
 | |
|         $this->db->getConnection()->exec("
 | |
|             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
 | |
|         $this->db->getConnection()->exec("
 | |
|             CREATE TABLE IF NOT EXISTS user_meta (
 | |
|                 id INT PRIMARY KEY AUTO_INCREMENT,
 | |
|                 user_id INT NOT NULL,
 | |
|                 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->register = new Register($this->db);
 | |
|     }
 | |
| 
 | |
|     protected function tearDown(): void
 | |
|     {
 | |
|         // Drop tables in correct order
 | |
|         $this->db->getConnection()->exec("DROP TABLE IF EXISTS user_2fa");
 | |
|         $this->db->getConnection()->exec("DROP TABLE IF EXISTS security_rate_auth");
 | |
|         $this->db->getConnection()->exec("DROP TABLE IF EXISTS user_meta");
 | |
|         $this->db->getConnection()->exec("DROP TABLE IF EXISTS user");
 | |
|         parent::tearDown();
 | |
|     }
 | |
| 
 | |
|     public function testLogin()
 | |
|     {
 | |
|         // First register a user
 | |
|         $username = 'testuser';
 | |
|         $password = 'password123';
 | |
| 
 | |
|         $this->register->register($username, $password);
 | |
| 
 | |
|         // Mock $_SERVER['REMOTE_ADDR'] for rate limiter
 | |
|         $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
 | |
| 
 | |
|         // Test successful login
 | |
|         try {
 | |
|             $result = $this->user->login($username, $password);
 | |
|             $this->assertIsArray($result);
 | |
|             $this->assertEquals('success', $result['status']);
 | |
|             $this->assertArrayHasKey('user_id', $result);
 | |
|             $this->assertArrayHasKey('username', $result);
 | |
|             $this->assertArrayHasKey('user_id', $_SESSION);
 | |
|             $this->assertArrayHasKey('username', $_SESSION);
 | |
|             $this->assertArrayHasKey('CREATED', $_SESSION);
 | |
|             $this->assertArrayHasKey('LAST_ACTIVITY', $_SESSION);
 | |
|         } catch (Exception $e) {
 | |
|             $this->fail('Login should not throw for valid credentials: ' . $e->getMessage());
 | |
|         }
 | |
| 
 | |
|         // Test failed login
 | |
|         $result = $this->user->login($username, 'wrongpassword');
 | |
|         $this->assertIsArray($result);
 | |
|         $this->assertEquals('failed', $result['status']);
 | |
|         $this->assertArrayHasKey('message', $result);
 | |
|         $this->assertStringContainsString('Invalid credentials', $result['message']);
 | |
|     }
 | |
| 
 | |
|     public function testGetUserDetails()
 | |
|     {
 | |
|         // Register a test user first
 | |
|         $username = 'testuser';
 | |
|         $password = 'password123';
 | |
|         $result = $this->register->register($username, $password);
 | |
|         $this->assertTrue($result);
 | |
| 
 | |
|         // Get user ID from database
 | |
|         $stmt = $this->db->getConnection()->prepare("SELECT id FROM user WHERE username = ?");
 | |
|         $stmt->execute([$username]);
 | |
|         $userId = $stmt->fetchColumn();
 | |
|         $this->assertNotFalse($userId);
 | |
| 
 | |
|         // Insert user metadata
 | |
|         $stmt = $this->db->getConnection()->prepare("
 | |
|             UPDATE user_meta
 | |
|             SET name = ?, email = ?
 | |
|             WHERE user_id = ?
 | |
|         ");
 | |
|         $stmt->execute(['Test User', 'test@example.com', $userId]);
 | |
| 
 | |
|         // Get user details
 | |
|         $userDetails = $this->user->getUserDetails($userId);
 | |
| 
 | |
|         $this->assertIsArray($userDetails);
 | |
|         $this->assertNotEmpty($userDetails);
 | |
|         $this->assertArrayHasKey(0, $userDetails, 'User details should be returned as an array');
 | |
| 
 | |
|         // Get first row since we're querying by primary key
 | |
|         $userDetails = $userDetails[0];
 | |
| 
 | |
|         $this->assertArrayHasKey('username', $userDetails, 'User details should include username');
 | |
|         $this->assertArrayHasKey('name', $userDetails, 'User details should include name');
 | |
|         $this->assertArrayHasKey('email', $userDetails, 'User details should include email');
 | |
| 
 | |
|         // Verify values
 | |
|         $this->assertEquals($username, $userDetails['username'], 'Username should match');
 | |
|         $this->assertEquals('Test User', $userDetails['name'], 'Name should match');
 | |
|         $this->assertEquals('test@example.com', $userDetails['email'], 'Email should match');
 | |
|     }
 | |
| }
 |