- Add pytest test suite across all modules (config, database, file_processor, ai_processor, api, scheduler, monitoring, ftp_server) - 145 tests covering normal paths, error handling, edge cases - Mock external dependencies (AI endpoint, requests, pyftpdlib) - 95% code coverage with fail-under=90 threshold in CI - Update CI workflow to run pytest with coverage enforcement - Add pyproject.toml with pytest/coverage configuration
100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
"""Tests for ftp_server module."""
|
|
|
|
import pytest
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_pyftpdlib():
|
|
"""Mock pyftpdlib modules which are not available on Python 3.12+."""
|
|
with patch.dict("sys.modules", {
|
|
"pyftpdlib": MagicMock(),
|
|
"pyftpdlib.authorizers": MagicMock(),
|
|
"pyftpdlib.handlers": MagicMock(),
|
|
"pyftpdlib.servers": MagicMock(),
|
|
}):
|
|
from factsdb.ftp_server import FTPServerManager, get_ftp_server_manager
|
|
yield
|
|
|
|
|
|
class MockConfig:
|
|
"""Lightweight mock Config for FTP tests."""
|
|
|
|
def __init__(self):
|
|
self.ftp_server = MagicMock()
|
|
self.ftp_server.host = "0.0.0.0"
|
|
self.ftp_server.port = 2121
|
|
self.ftp_server.username = "testuser"
|
|
self.ftp_server.password = "testpass"
|
|
self.database = MagicMock()
|
|
|
|
|
|
class TestFTPServerManager:
|
|
def test_init(self, mock_pyftpdlib):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
assert mgr.is_running is False
|
|
assert mgr.onboarded_directories == set()
|
|
assert mgr.server is None
|
|
|
|
def test_add_onboarded_directory(self, mock_pyftpdlib, tmp_path):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
mgr.add_onboarded_directory(str(tmp_path))
|
|
assert str(tmp_path) in mgr.onboarded_directories
|
|
|
|
def test_add_nonexistent_directory(self, mock_pyftpdlib, tmp_path):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
mgr.add_onboarded_directory("/nonexistent/path")
|
|
assert len(mgr.onboarded_directories) == 0
|
|
|
|
def test_is_directory_allowed(self, mock_pyftpdlib, tmp_path):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
mgr.add_onboarded_directory(str(tmp_path))
|
|
assert mgr.is_directory_allowed(str(tmp_path)) is True
|
|
assert mgr.is_directory_allowed("/other/path") is False
|
|
|
|
def test_is_directory_subpath(self, mock_pyftpdlib, tmp_path):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
mgr.add_onboarded_directory(str(tmp_path))
|
|
sub = tmp_path / "sub"
|
|
assert mgr.is_directory_allowed(str(sub)) is True
|
|
|
|
def test_get_onboarded_directories(self, mock_pyftpdlib, tmp_path):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
mgr.add_onboarded_directory(str(tmp_path))
|
|
dirs = mgr.get_onboarded_directories()
|
|
assert len(dirs) == 1
|
|
assert str(tmp_path) in dirs
|
|
|
|
def test_is_running_attr(self, mock_pyftpdlib):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
assert mgr.is_running is False
|
|
|
|
|
|
class TestFTPServerStartStop:
|
|
def test_start_already_running(self, mock_pyftpdlib):
|
|
from factsdb.ftp_server import FTPServerManager
|
|
mgr = FTPServerManager(MockConfig())
|
|
mgr.is_running = True
|
|
mgr.server = MagicMock()
|
|
mgr.start()
|
|
assert mgr.is_running is True
|
|
|
|
|
|
class TestGetFtpServerManager:
|
|
def test_singleton(self, mock_pyftpdlib):
|
|
from factsdb import ftp_server as ftp_mod
|
|
ftp_mod._ftp_server_manager = None
|
|
from factsdb.ftp_server import FTPServerManager, get_ftp_server_manager
|
|
cfg = MockConfig()
|
|
m1 = get_ftp_server_manager(cfg)
|
|
m2 = get_ftp_server_manager(cfg)
|
|
assert m1 is m2
|
|
ftp_mod._ftp_server_manager = None
|