Skip to main content
Glama
test_utils.py•10.8 kB
# SPDX-License-Identifier: GPL-3.0-only OR MIT """ Tests for arch_ops_server.utils module. """ import asyncio from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch import pytest from arch_ops_server.utils import ( IS_ARCH, add_aur_warning, check_command_exists, create_error_response, get_aur_helper, is_arch_linux, run_command, ) class TestPlatformDetection: """Test platform detection functionality.""" def test_is_arch_linux_with_arch_release(self, mock_arch_release): """Test detection via /etc/arch-release file.""" with patch("arch_ops_server.utils.Path") as mock_path: mock_path.return_value.exists.return_value = True result = is_arch_linux() assert result is True def test_is_arch_linux_with_os_release(self, mock_os_release_arch): """Test detection via /etc/os-release file.""" with ( patch("arch_ops_server.utils.Path") as mock_path, patch("builtins.open", create=True) as mock_open, ): # Simulate arch-release not existing mock_path.return_value.exists.return_value = False # Mock os-release reading mock_open.return_value.__enter__.return_value.read.return_value = ( mock_os_release_arch.read_text() ) result = is_arch_linux() assert result is True def test_is_arch_linux_not_arch(self, mock_os_release_ubuntu): """Test detection on non-Arch system.""" with ( patch("arch_ops_server.utils.Path") as mock_path, patch("builtins.open", create=True) as mock_open, ): # Simulate arch-release not existing mock_path.return_value.exists.return_value = False # Mock os-release reading for Ubuntu mock_open.return_value.__enter__.return_value.read.return_value = ( mock_os_release_ubuntu.read_text() ) result = is_arch_linux() assert result is False def test_is_arch_linux_no_files(self): """Test detection when neither file exists.""" with ( patch("arch_ops_server.utils.Path") as mock_path, patch("builtins.open", side_effect=FileNotFoundError), ): mock_path.return_value.exists.return_value = False result = is_arch_linux() assert result is False class TestCommandExecution: """Test async command execution.""" @pytest.mark.asyncio async def test_run_command_success(self, mock_subprocess_success): """Test successful command execution.""" with patch( "asyncio.create_subprocess_exec", new=mock_subprocess_success ): exit_code, stdout, stderr = await run_command( ["echo", "hello"], skip_sudo_check=True ) assert exit_code == 0 assert stdout == "success output" assert stderr == "" @pytest.mark.asyncio async def test_run_command_failure_with_check(self, mock_subprocess_failure): """Test command failure with check=True raises exception.""" with patch( "asyncio.create_subprocess_exec", new=mock_subprocess_failure ): with pytest.raises(RuntimeError, match="Command failed with exit code 1"): await run_command(["false"], check=True, skip_sudo_check=True) @pytest.mark.asyncio async def test_run_command_failure_without_check(self, mock_subprocess_failure): """Test command failure with check=False returns error.""" with patch( "asyncio.create_subprocess_exec", new=mock_subprocess_failure ): exit_code, stdout, stderr = await run_command( ["false"], check=False, skip_sudo_check=True ) assert exit_code == 1 assert stdout == "" assert stderr == "error output" @pytest.mark.asyncio async def test_run_command_timeout(self): """Test command timeout handling.""" async def _slow_communicate(): await asyncio.sleep(10) return (b"", b"") mock_process = MagicMock() mock_process.communicate = _slow_communicate async def _create_slow_subprocess(*args, **kwargs): return mock_process with patch("asyncio.create_subprocess_exec", new=_create_slow_subprocess): with pytest.raises(asyncio.TimeoutError): await run_command( ["sleep", "10"], timeout=0.1, skip_sudo_check=True ) @pytest.mark.asyncio async def test_run_command_sudo_password_not_cached(self): """Test sudo command when password is not cached.""" # Mock sudo -n true to fail (password not cached) async def _mock_communicate(): return (b"", b"sudo: a password is required") mock_test_process = MagicMock() mock_test_process.returncode = 1 mock_test_process.communicate = _mock_communicate call_count = 0 async def _create_subprocess(*args, **kwargs): nonlocal call_count call_count += 1 return mock_test_process with patch("asyncio.create_subprocess_exec", new=_create_subprocess): exit_code, stdout, stderr = await run_command(["sudo", "pacman", "-S", "test"]) assert exit_code == 1 assert "Sudo password required" in stderr assert call_count == 1 # Only the test command, not the actual command class TestErrorHandling: """Test error response creation and formatting.""" def test_create_error_response_basic(self): """Test basic error response creation.""" response = create_error_response( "TestError", "Something went wrong", suggest_wiki_search=False ) assert response["error"] is True assert response["type"] == "TestError" assert response["message"] == "Something went wrong" assert "wiki_suggestions" not in response def test_create_error_response_with_details(self): """Test error response with additional details.""" response = create_error_response( "TestError", "Something went wrong", details="More information here", suggest_wiki_search=False, ) assert response["details"] == "More information here" def test_create_error_response_with_wiki_suggestions(self): """Test error response includes Wiki suggestions.""" response = create_error_response( "NotFound", "Package not found", suggest_wiki_search=True ) assert "wiki_suggestions" in response assert isinstance(response["wiki_suggestions"], list) assert len(response["wiki_suggestions"]) > 0 assert "help_text" in response def test_wiki_suggestions_for_network_error(self): """Test Wiki suggestions for network-related errors.""" response = create_error_response( "NetworkError", "Failed to connect to mirror server", suggest_wiki_search=True, ) suggestions = response.get("wiki_suggestions", []) # Should suggest network and mirror-related topics assert any("network" in s.lower() or "mirror" in s.lower() for s in suggestions) def test_wiki_suggestions_for_pacman_error(self): """Test Wiki suggestions for pacman-related errors.""" response = create_error_response( "CommandError", "pacman failed to update database", suggest_wiki_search=True, ) suggestions = response.get("wiki_suggestions", []) # Should suggest pacman-related topics assert any("pacman" in s.lower() for s in suggestions) class TestAURWarning: """Test AUR warning wrapper.""" def test_add_aur_warning(self): """Test AUR warning is properly added to data.""" test_data = {"package": "test-pkg", "version": "1.0"} result = add_aur_warning(test_data) assert "warning" in result assert "AUR PACKAGE WARNING" in result["warning"] assert "USER-PRODUCED" in result["warning"] assert result["data"] == test_data def test_aur_warning_preserves_data(self): """Test that original data is preserved unchanged.""" original_data = {"key1": "value1", "key2": {"nested": "value"}} result = add_aur_warning(original_data) assert result["data"] == original_data assert result["data"] is original_data # Same object reference class TestCommandExistence: """Test command existence checking.""" def test_check_command_exists_found(self): """Test detecting an existing command.""" with patch("os.system", return_value=0): result = check_command_exists("ls") assert result is True def test_check_command_exists_not_found(self): """Test detecting a missing command.""" with patch("os.system", return_value=1): result = check_command_exists("nonexistent_command_xyz") assert result is False def test_check_command_exists_exception(self): """Test handling exceptions during command check.""" with patch("os.system", side_effect=Exception("Test error")): result = check_command_exists("test") assert result is False class TestAURHelper: """Test AUR helper detection.""" def test_get_aur_helper_paru(self): """Test detection when paru is available.""" with patch("arch_ops_server.utils.check_command_exists") as mock_check: mock_check.side_effect = lambda cmd: cmd == "paru" result = get_aur_helper() assert result == "paru" def test_get_aur_helper_yay(self): """Test detection when only yay is available.""" with patch("arch_ops_server.utils.check_command_exists") as mock_check: mock_check.side_effect = lambda cmd: cmd == "yay" result = get_aur_helper() assert result == "yay" def test_get_aur_helper_both_available(self): """Test priority when both helpers are available (paru wins).""" with patch("arch_ops_server.utils.check_command_exists", return_value=True): result = get_aur_helper() assert result == "paru" def test_get_aur_helper_none_available(self): """Test when no AUR helper is available.""" with patch("arch_ops_server.utils.check_command_exists", return_value=False): result = get_aur_helper() assert result is None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nihalxkumar/arch-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server