import socket import struct from unittest.mock import Mock, mock_open, patch import pytest from fenrirscreenreader.remoteDriver import unixDriver def test_watchdog_keeps_serving_when_instance_registration_fails( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment driver.fenrirSocks = [Mock()] active = Mock(value=True) event_queue = Mock() def stop_after_select(*_args): active.value = False return ([], [], []) with patch.object(driver, "_get_socket_candidates", return_value=[]), patch.object( driver, "_register_instance", side_effect=PermissionError("denied") ), patch( "fenrirscreenreader.remoteDriver.unixDriver.select.select", side_effect=stop_after_select, ) as select_call: driver.watch_dog(active, event_queue) select_call.assert_called_once() def test_watchdog_closes_listeners_when_unexpected_error_escapes( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment listener = Mock() active = Mock(value=True) with patch.object( driver, "_get_socket_candidates", return_value=[("/tmp/fenrir-test.sock", False)], ), patch.object( driver, "_bind_socket", return_value=listener ), patch.object( driver, "_try_register_instance" ), patch( "fenrirscreenreader.remoteDriver.unixDriver.select.select", side_effect=RuntimeError("unexpected failure"), ), patch( "fenrirscreenreader.remoteDriver.unixDriver.os.path.exists", return_value=False, ), patch( "fenrirscreenreader.remoteDriver.unixDriver.remoteInstanceRegistry.remove_instance" ) as remove_instance: with pytest.raises(RuntimeError, match="unexpected failure"): driver.watch_dog(active, Mock()) listener.close.assert_called_once_with() assert driver.fenrirSocks == [] assert driver.bound_sockets == [] remove_instance.assert_called_once_with() class FakeClientSocket: def __init__(self, data): self.data = data self.sent = b"" def recv(self, _size): return self.data def sendall(self, data): self.sent += data def test_get_peer_uid_from_unix_socket(): driver = unixDriver.driver() client_sock = Mock() client_sock.getsockopt.return_value = struct.pack("3i", 4321, 1000, 100) assert driver._get_peer_uid(client_sock) == 1000 client_sock.getsockopt.assert_called_once_with( socket.SOL_SOCKET, socket.SO_PEERCRED, struct.calcsize("3i"), ) def test_main_socket_routes_to_ancestor_private_socket(mock_environment): driver = unixDriver.driver() driver.env = mock_environment driver.bound_sockets = [ (Mock(), "/tmp/fenrirscreenreader-999.sock"), (Mock(), unixDriver.MAIN_SOCKET_FILE), ] client_sock = FakeClientSocket(b"command say routed") event_queue = Mock() with patch.object(driver, "_get_peer_pid", return_value=1234), patch.object( driver, "_find_ancestor_private_socket", return_value="/tmp/fenrirscreenreader-222.sock", ), patch.object( driver, "_find_available_private_socket", return_value="/tmp/fenrirscreenreader-222.sock", ), patch.object( driver, "_forward_remote_to_socket", return_value=True ) as forward: driver._handle_client( client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE ) forward.assert_called_once_with( "command say routed", "/tmp/fenrirscreenreader-222.sock" ) event_queue.put.assert_not_called() def test_main_socket_routes_to_first_available_private_socket( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment driver.bound_sockets = [ (Mock(), "/tmp/fenrirscreenreader-999.sock"), (Mock(), unixDriver.MAIN_SOCKET_FILE), ] client_sock = FakeClientSocket(b"command say fallback") event_queue = Mock() with patch.object(driver, "_get_peer_pid", return_value=1234), patch.object( driver, "_find_ancestor_private_socket", return_value="", ), patch.object( driver, "_find_available_private_socket", return_value="/tmp/fenrirscreenreader-333.sock", ), patch.object( driver, "_forward_remote_to_socket", return_value=True ) as forward: driver._handle_client( client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE ) forward.assert_called_once_with( "command say fallback", "/tmp/fenrirscreenreader-333.sock" ) event_queue.put.assert_not_called() def test_main_socket_handles_command_locally_without_available_target( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment client_sock = FakeClientSocket(b"command say local") event_queue = Mock() with patch.object(driver, "_get_peer_pid", return_value=1234), patch.object( driver, "_get_peer_uid", return_value=1000 ), patch.object( driver, "_get_socket_owner_uid", return_value=65534 ), patch.object( driver, "_find_available_private_socket", return_value="", ): driver._handle_client( client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE ) event_queue.put.assert_called_once_with( { "Type": unixDriver.FenrirEventType.remote_incomming, "data": "command say local", } ) def test_vcsa_main_socket_owner_handles_command_locally(mock_environment): driver = unixDriver.driver() driver.env = mock_environment driver.bound_sockets = [(Mock(), unixDriver.MAIN_SOCKET_FILE)] client_sock = FakeClientSocket(b"command say root") event_queue = Mock() with patch.object(driver, "_get_peer_uid", return_value=1000), patch.object( driver, "_get_socket_owner_uid", return_value=1000 ), patch.object( driver, "_find_available_private_socket" ) as find_available: driver._handle_client( client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE ) find_available.assert_not_called() event_queue.put.assert_called_once_with( { "Type": unixDriver.FenrirEventType.remote_incomming, "data": "command say root", } ) def test_vcsa_main_socket_routes_to_same_user_private_socket( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment driver.bound_sockets = [(Mock(), unixDriver.MAIN_SOCKET_FILE)] client_sock = FakeClientSocket(b"command say x session") event_queue = Mock() with patch.object(driver, "_get_peer_pid", return_value=1234), patch.object( driver, "_get_peer_uid", return_value=1000 ), patch.object( driver, "_get_socket_owner_uid", return_value=65534 ), patch.object( driver, "_find_ancestor_private_socket", return_value="" ), patch.object( driver, "_find_available_private_socket", return_value="/tmp/fenrirscreenreader-222.sock", ) as find_available, patch.object( driver, "_forward_remote_to_socket", return_value=True ) as forward: driver._handle_client( client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE ) find_available.assert_called_once_with("", owner_uid=1000) forward.assert_called_once_with( "command say x session", "/tmp/fenrirscreenreader-222.sock" ) event_queue.put.assert_not_called() def test_vcsa_main_socket_stays_local_without_peer_credentials( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment driver.bound_sockets = [(Mock(), unixDriver.MAIN_SOCKET_FILE)] client_sock = FakeClientSocket(b"command say unknown") event_queue = Mock() with patch.object(driver, "_get_peer_uid", return_value=-1), patch.object( driver, "_find_available_private_socket" ) as find_available: driver._handle_client( client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE ) find_available.assert_not_called() event_queue.put.assert_called_once_with( { "Type": unixDriver.FenrirEventType.remote_incomming, "data": "command say unknown", } ) def test_private_socket_handles_command_locally(mock_environment): driver = unixDriver.driver() driver.env = mock_environment client_sock = FakeClientSocket(b"command say private") event_queue = Mock() driver._handle_client( client_sock, event_queue, "/tmp/fenrirscreenreader-222.sock" ) event_queue.put.assert_called_once_with( { "Type": unixDriver.FenrirEventType.remote_incomming, "data": "command say private", } ) def test_list_command_still_returns_response_from_main_socket(mock_environment): driver = unixDriver.driver() driver.env = mock_environment mock_environment["runtime"]["RemoteManager"] = Mock() client_sock = FakeClientSocket(b"command list") event_queue = Mock() mock_environment["runtime"][ "RemoteManager" ].handle_remote_incomming_with_response.return_value = { "success": True, "message": "pid=1", } driver._handle_client(client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE) assert client_sock.sent == b"pid=1\n" event_queue.put.assert_not_called() def test_get_parent_pid_parses_process_names_with_spaces(): driver = unixDriver.driver() stat_file = mock_open( read_data="1234 (name with spaces) S 567 1 1 0 -1 0\n" ) with patch("builtins.open", stat_file): assert driver._get_parent_pid(1234) == 567 def test_find_available_private_socket_prefers_ancestor_socket( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment with patch( "fenrirscreenreader.remoteDriver.unixDriver.remoteInstanceRegistry.list_instances", return_value=[ { "pid": 111, "socket_files": ["/tmp/fenrirscreenreader-111.sock"], }, { "pid": 222, "socket_files": ["/tmp/fenrirscreenreader-222.sock"], }, ], ), patch.object(driver, "_is_socket_active", return_value=True): assert ( driver._find_available_private_socket( "/tmp/fenrirscreenreader-222.sock" ) == "/tmp/fenrirscreenreader-222.sock" ) def test_find_available_private_socket_skips_main_socket( mock_environment, ): driver = unixDriver.driver() driver.env = mock_environment with patch( "fenrirscreenreader.remoteDriver.unixDriver.remoteInstanceRegistry.list_instances", return_value=[ { "pid": 111, "socket_files": [ unixDriver.MAIN_SOCKET_FILE, "/tmp/fenrirscreenreader-111.sock", ], } ], ), patch.object(driver, "_is_socket_active", return_value=True): assert ( driver._find_available_private_socket() == "/tmp/fenrirscreenreader-111.sock" ) def test_find_available_private_socket_filters_by_owner(mock_environment): driver = unixDriver.driver() driver.env = mock_environment with patch( "fenrirscreenreader.remoteDriver.unixDriver.remoteInstanceRegistry.list_instances", return_value=[ { "pid": 111, "socket_files": ["/tmp/fenrirscreenreader-111.sock"], }, { "pid": 222, "socket_files": ["/tmp/fenrirscreenreader-222.sock"], }, ], ), patch.object( driver, "_get_socket_owner_uid", side_effect=lambda socket_file: { "/tmp/fenrirscreenreader-111.sock": 1001, "/tmp/fenrirscreenreader-222.sock": 1000, }[socket_file], ), patch.object(driver, "_is_socket_active", return_value=True): assert ( driver._find_available_private_socket(owner_uid=1000) == "/tmp/fenrirscreenreader-222.sock" )