"""Tests for TunnelControllerGroup lifecycle.""" import asyncio from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch import pytest from i2p_apps.i2ptunnel.group import TunnelControllerGroup class TestGroupLifecycle: @pytest.mark.asyncio async def test_load_empty_config(self, tmp_path): config = tmp_path / "empty.config" config.write_text("") group = TunnelControllerGroup(config) await group.load_and_start() assert len(group.controllers) == 0 @pytest.mark.asyncio async def test_load_tunnels_from_config(self, tmp_path): config = tmp_path / "test.config" config.write_text( "tunnel.0.name=proxy\n" "tunnel.0.type=httpclient\n" "tunnel.0.listenPort=4444\n" "tunnel.0.interface=127.0.0.1\n" "tunnel.0.startOnLoad=false\n" ) group = TunnelControllerGroup(config) await group.load_and_start() assert len(group.controllers) == 1 assert group.controllers[0].config.name == "proxy" def test_get_controller_by_name(self, tmp_path): config = tmp_path / "test.config" config.write_text( "tunnel.0.name=myproxy\n" "tunnel.0.type=httpclient\n" "tunnel.0.listenPort=4444\n" "tunnel.0.interface=127.0.0.1\n" ) group = TunnelControllerGroup(config) # Manually load without async start from i2p_apps.i2ptunnel.config import TunnelConfigParser from i2p_apps.i2ptunnel.controller import TunnelController from i2p_apps.i2ptunnel.sam_session import SessionFactory tunnels = TunnelConfigParser.load(config) for td in tunnels: group._controllers.append( TunnelController(td, SessionFactory("127.0.0.1", 7656)) ) assert group.get_controller("myproxy") is not None assert group.get_controller("nonexistent") is None def test_list_controllers(self, tmp_path): config = tmp_path / "test.config" config.write_text("") group = TunnelControllerGroup(config) assert group.list_controllers() == [] @pytest.mark.asyncio async def test_stop_all_empty(self, tmp_path): config = tmp_path / "test.config" config.write_text("") group = TunnelControllerGroup(config) await group.load_and_start() await group.stop_all() # no crash @pytest.mark.asyncio async def test_start_all_skips_running(self, tmp_path): config = tmp_path / "test.config" config.write_text("") group = TunnelControllerGroup(config) await group.load_and_start() await group.start_all() # no crash on empty @pytest.mark.asyncio async def test_config_d_loading(self, tmp_path): """Loads tunnel configs from config.d/ directory.""" config = tmp_path / "i2ptunnel.config" config.write_text( "tunnel.0.name=main\n" "tunnel.0.type=httpclient\n" "tunnel.0.listenPort=4444\n" "tunnel.0.interface=127.0.0.1\n" ) config_d = tmp_path / "i2ptunnel.config.d" config_d.mkdir() (config_d / "extra.config").write_text( "tunnel.0.name=extra\n" "tunnel.0.type=server\n" "tunnel.0.targetHost=127.0.0.1\n" "tunnel.0.targetPort=8080\n" "tunnel.0.interface=127.0.0.1\n" ) group = TunnelControllerGroup(config) await group.load_and_start() names = [c.config.name for c in group.controllers] assert "main" in names assert "extra" in names