Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
182 lines
6.1 KiB
Python
182 lines
6.1 KiB
Python
"""
|
|
Tests for terminal SSH web feature.
|
|
"""
|
|
import hashlib
|
|
import pytest
|
|
from datetime import datetime, timedelta, timezone
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
from app.services.terminal_service import (
|
|
TerminalService,
|
|
terminal_service,
|
|
TERMINAL_SESSION_TTL_MINUTES,
|
|
TERMINAL_MAX_SESSIONS_PER_USER,
|
|
)
|
|
|
|
|
|
class TestTerminalService:
|
|
"""Tests for TerminalService class."""
|
|
|
|
def test_generate_session_id(self):
|
|
"""Test session ID generation produces unique IDs."""
|
|
service = TerminalService()
|
|
id1 = service.generate_session_id()
|
|
id2 = service.generate_session_id()
|
|
|
|
assert len(id1) == 64 # 32 bytes hex = 64 chars
|
|
assert len(id2) == 64
|
|
assert id1 != id2
|
|
|
|
def test_generate_session_token(self):
|
|
"""Test token generation produces unique tokens and valid hashes."""
|
|
service = TerminalService()
|
|
token1, hash1 = service.generate_session_token()
|
|
token2, hash2 = service.generate_session_token()
|
|
|
|
# Tokens should be unique
|
|
assert token1 != token2
|
|
|
|
# Hashes should be valid SHA256
|
|
assert len(hash1) == 64
|
|
assert len(hash2) == 64
|
|
|
|
# Hash should match token
|
|
computed_hash = hashlib.sha256(token1.encode()).hexdigest()
|
|
assert computed_hash == hash1
|
|
|
|
def test_verify_token_valid(self):
|
|
"""Test token verification with valid token."""
|
|
service = TerminalService()
|
|
token, token_hash = service.generate_session_token()
|
|
|
|
assert service.verify_token(token, token_hash) is True
|
|
|
|
def test_verify_token_invalid(self):
|
|
"""Test token verification with invalid token."""
|
|
service = TerminalService()
|
|
token, token_hash = service.generate_session_token()
|
|
|
|
# Wrong token
|
|
assert service.verify_token("wrong_token", token_hash) is False
|
|
|
|
# Wrong hash
|
|
assert service.verify_token(token, "wrong_hash") is False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_allocate_port(self):
|
|
"""Test port allocation."""
|
|
service = TerminalService()
|
|
session_id = service.generate_session_id()
|
|
|
|
port = await service.allocate_port(session_id)
|
|
|
|
assert port >= 7680
|
|
assert port <= 7700
|
|
assert port in service._allocated_ports
|
|
assert service._allocated_ports[port] == session_id
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_allocate_port_unique(self):
|
|
"""Test that allocated ports are unique."""
|
|
service = TerminalService()
|
|
|
|
ports = []
|
|
for i in range(5):
|
|
session_id = service.generate_session_id()
|
|
port = await service.allocate_port(session_id)
|
|
ports.append(port)
|
|
|
|
# All ports should be unique
|
|
assert len(ports) == len(set(ports))
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_release_port(self):
|
|
"""Test port release."""
|
|
service = TerminalService()
|
|
session_id = service.generate_session_id()
|
|
|
|
port = await service.allocate_port(session_id)
|
|
assert port in service._allocated_ports
|
|
|
|
await service.release_port(port)
|
|
assert port not in service._allocated_ports
|
|
|
|
def test_check_ttyd_available_not_found(self):
|
|
"""Test ttyd availability check when not installed."""
|
|
service = TerminalService()
|
|
service._ttyd_available = None # Reset cache
|
|
|
|
with patch('shutil.which', return_value=None):
|
|
result = service.check_ttyd_available()
|
|
|
|
assert result is False
|
|
assert service._ttyd_available is False
|
|
|
|
def test_check_ttyd_available_found(self):
|
|
"""Test ttyd availability check when installed."""
|
|
service = TerminalService()
|
|
service._ttyd_available = None # Reset cache
|
|
|
|
with patch('shutil.which', return_value='/usr/bin/ttyd'):
|
|
result = service.check_ttyd_available()
|
|
|
|
assert result is True
|
|
assert service._ttyd_available is True
|
|
|
|
def test_get_session_url_direct(self):
|
|
"""Test session URL generation for direct access."""
|
|
service = TerminalService()
|
|
url = service.get_session_url(7680, "test_token")
|
|
|
|
assert url == "http://localhost:7680/"
|
|
|
|
def test_get_session_url_with_base(self):
|
|
"""Test session URL generation with base URL."""
|
|
service = TerminalService()
|
|
url = service.get_session_url(7680, "test_token", base_url="https://example.com")
|
|
|
|
assert url == "https://example.com/terminal/proxy/7680?token=test_token"
|
|
|
|
def test_get_websocket_url(self):
|
|
"""Test WebSocket URL generation."""
|
|
service = TerminalService()
|
|
url = service.get_websocket_url(7680)
|
|
|
|
assert url == "ws://localhost:7680/ws"
|
|
|
|
def test_get_active_session_count_empty(self):
|
|
"""Test active session count when no sessions."""
|
|
service = TerminalService()
|
|
assert service.get_active_session_count() == 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_terminate_session_not_found(self):
|
|
"""Test terminating non-existent session."""
|
|
service = TerminalService()
|
|
result = await service.terminate_session("nonexistent_id")
|
|
assert result is False
|
|
|
|
|
|
class TestTerminalSessionTTL:
|
|
"""Tests for session TTL configuration."""
|
|
|
|
def test_session_ttl_default(self):
|
|
"""Test default TTL value."""
|
|
assert TERMINAL_SESSION_TTL_MINUTES == 30
|
|
|
|
def test_max_sessions_default(self):
|
|
"""Test default max sessions per user."""
|
|
assert TERMINAL_MAX_SESSIONS_PER_USER == 3
|
|
|
|
|
|
class TestTerminalServiceSingleton:
|
|
"""Tests for terminal service singleton."""
|
|
|
|
def test_global_instance(self):
|
|
"""Test global terminal service instance exists."""
|
|
from app.services.terminal_service import get_terminal_service
|
|
|
|
service = get_terminal_service()
|
|
assert service is terminal_service
|
|
assert isinstance(service, TerminalService)
|