77"""
88
99import importlib
10- import pytest
11- import docker
12- import requests
1310import os
1411import time
1512from pathlib import Path
16- from typing import Generator , Optional , Type
1713
18- from .utils .base_test_cases import BaseServerTestCase
14+ import docker
15+ import pytest
16+
17+ # Docker fixtures using pytest-docker-tools
18+ from pytest_docker_tools import container , image
19+
1920from .controllers .base_controllers import BaseServerController , TestCaseControllerConfig
21+ from .utils .base_test_cases import BaseServerTestCase
22+
23+ unrealircd_image = image (name = "ircatlchat-unrealircd:latest" )
24+
25+
26+ @pytest .fixture (scope = "function" )
27+ def prepared_config_dir (tmp_path ):
28+ """Create and prepare a temporary directory with UnrealIRCd config files."""
29+ import shutil
30+ from pathlib import Path
31+
32+ config_dir = tmp_path / "container_config"
33+ config_dir .mkdir (exist_ok = True )
34+
35+ # Source directory with real configs
36+ source_dir = Path ("src/backend/unrealircd/conf" )
37+
38+ # Copy all config files
39+ for config_file in source_dir .glob ("*.conf" ):
40+ dest_file = config_dir / config_file .name
41+ shutil .copy2 (config_file , dest_file )
42+ dest_file .chmod (0o644 ) # Make readable by anyone
43+
44+ # Copy subdirectories
45+ for subdir in ["help" , "aliases" , "tls" ]:
46+ if (source_dir / subdir ).exists ():
47+ shutil .copytree (source_dir / subdir , config_dir / subdir , dirs_exist_ok = True )
48+ # Set permissions on subdirectory files
49+ for file in (config_dir / subdir ).rglob ("*" ):
50+ if file .is_file ():
51+ file .chmod (0o644 )
52+
53+ # Copy other necessary files
54+ for pattern in ["*.list" , "*.default.conf" , "*.optional.conf" ]:
55+ for file in source_dir .glob (pattern ):
56+ dest_file = config_dir / file .name
57+ shutil .copy2 (file , dest_file )
58+ dest_file .chmod (0o644 )
59+
60+ print (f"DEBUG: Prepared config dir: { config_dir } " )
61+ print (f"DEBUG: Files in config dir: { list (config_dir .glob ('*' ))} " )
62+ print (f"DEBUG: unrealircd.conf exists: { (config_dir / 'unrealircd.conf' ).exists ()} " )
63+
64+ return config_dir
65+
66+
67+ unrealircd_container = container (
68+ image = "{unrealircd_image.id}" ,
69+ ports = {
70+ "6667/tcp" : None , # Main IRC port
71+ "6697/tcp" : None , # TLS port
72+ },
73+ volumes = {
74+ "{prepared_config_dir}" : {"bind" : "/home/unrealircd/unrealircd/conf" , "mode" : "rw" },
75+ },
76+ command = [
77+ "-t" , # Test configuration
78+ "-F" , # Don't fork
79+ ],
80+ scope = "function" ,
81+ )
2082
2183
2284def pytest_addoption (parser ):
@@ -42,22 +104,22 @@ def pytest_configure(config):
42104 try :
43105 module = importlib .import_module (module_name )
44106 except ImportError :
45- pytest .exit ("Cannot import module {}" . format ( module_name ) , 1 )
107+ pytest .exit (f "Cannot import module { module_name } " , 1 )
46108
47109 controller_class = module .get_irctest_controller_class ()
48110 if issubclass (controller_class , BaseServerController ):
49111 from . import server_tests as module
50112 else :
51113 pytest .exit (
52- "{ }.Controller should be a subclass of irctest.basecontroller.BaseServerController". format ( module_name ) ,
114+ f" { module_name } .Controller should be a subclass of irctest.basecontroller.BaseServerController" ,
53115 1 ,
54116 )
55117
56118 if services_module_name is not None :
57119 try :
58120 services_module = importlib .import_module (services_module_name )
59121 except ImportError :
60- pytest .exit ("Cannot import module {}" . format ( services_module_name ) , 1 )
122+ pytest .exit (f "Cannot import module { services_module_name } " , 1 )
61123 controller_class .services_controller_class = services_module .get_irctest_controller_class ()
62124
63125 BaseServerTestCase .controllerClass = controller_class
@@ -177,6 +239,19 @@ def mock_docker_container(mocker):
177239 return mock_container
178240
179241
242+ @pytest .fixture
243+ def controller (unrealircd_container ):
244+ """Controller instance with Docker container support."""
245+ from .controllers .unrealircd_controller import get_unrealircd_controller_class
246+
247+ controller_class = get_unrealircd_controller_class ()
248+ config = TestCaseControllerConfig ()
249+ return controller_class (config , container_fixture = unrealircd_container )
250+
251+
252+ # Removed autouse controller injection - tests should explicitly request controller fixture when needed
253+
254+
180255@pytest .fixture
181256def mock_requests_get (mocker ):
182257 """Mock requests.get for testing HTTP calls."""
@@ -204,6 +279,7 @@ def is_service_running(self, service_name: str) -> bool:
204279
205280 result = subprocess .run (
206281 ["docker" , "compose" , "ps" , service_name ],
282+ check = False ,
207283 cwd = self .project_root ,
208284 capture_output = True ,
209285 text = True ,
@@ -219,6 +295,7 @@ def get_service_logs(self, service_name: str, tail: int = 50) -> str:
219295
220296 result = subprocess .run (
221297 ["docker" , "compose" , "logs" , "--tail" , str (tail ), service_name ],
298+ check = False ,
222299 cwd = self .project_root ,
223300 capture_output = True ,
224301 text = True ,
@@ -264,7 +341,7 @@ def wait_for_irc_server(self, timeout: int = 30) -> bool:
264341
265342 return False
266343
267- def send_irc_command (self , command : str ) -> Optional [ str ] :
344+ def send_irc_command (self , command : str ) -> str | None :
268345 """Send a command to the IRC server and get response."""
269346 import socket
270347
@@ -399,3 +476,23 @@ def setup_test_environment(project_root: Path, tmp_path_factory):
399476 test_env_vars = ["TESTING" , "DOCKER_COMPOSE_FILE" ]
400477 for var in test_env_vars :
401478 os .environ .pop (var , None )
479+
480+
481+ def _inject_controller_if_needed (request ):
482+ """Helper to inject controller only when needed."""
483+ if hasattr (request .instance , "setup_method" ):
484+ # Check if this is an integration test that needs Docker
485+ if any (marker in ["integration" , "irc" , "docker" , "atheme" , "webpanel" ] for marker in request .keywords ):
486+ # Only request controller fixture when actually needed
487+ controller = request .getfixturevalue ("controller" )
488+ request .instance .controller = controller
489+ # Set up connection details
490+ container_ports = controller .get_container_ports ()
491+ request .instance .hostname = "localhost"
492+ request .instance .port = container_ports .get ("6667/tcp" , 6667 )
493+
494+
495+ @pytest .fixture (autouse = True )
496+ def inject_controller (request ):
497+ """Automatically inject controller fixture into test classes that need it."""
498+ _inject_controller_if_needed (request )
0 commit comments