338 lines
No EOL
12 KiB
Python
338 lines
No EOL
12 KiB
Python
"""
|
|
Tests for the enhanced exception handling system
|
|
"""
|
|
|
|
import pytest
|
|
import sys
|
|
from io import StringIO
|
|
from deb_mock.exceptions import (
|
|
DebMockError, ConfigurationError, ChrootError, SbuildError,
|
|
BuildError, DependencyError, MetadataError, CacheError,
|
|
PluginError, NetworkError, PermissionError, ValidationError,
|
|
handle_exception, format_error_context
|
|
)
|
|
|
|
|
|
class TestDebMockError:
|
|
"""Test the base DebMockError class"""
|
|
|
|
def test_basic_error(self):
|
|
"""Test basic error creation"""
|
|
error = DebMockError("Test error message")
|
|
assert str(error) == "Error: Test error message"
|
|
assert error.exit_code == 1
|
|
assert error.context == {}
|
|
assert error.suggestions == []
|
|
|
|
def test_error_with_context(self):
|
|
"""Test error with context information"""
|
|
context = {'file': '/path/to/file', 'operation': 'read'}
|
|
error = DebMockError("File operation failed", context=context)
|
|
|
|
expected = """Error: File operation failed
|
|
|
|
Context:
|
|
file: /path/to/file
|
|
operation: read"""
|
|
assert str(error) == expected
|
|
|
|
def test_error_with_suggestions(self):
|
|
"""Test error with suggestions"""
|
|
suggestions = ["Try again", "Check permissions", "Contact admin"]
|
|
error = DebMockError("Operation failed", suggestions=suggestions)
|
|
|
|
expected = """Error: Operation failed
|
|
|
|
Suggestions:
|
|
1. Try again
|
|
2. Check permissions
|
|
3. Contact admin"""
|
|
assert str(error) == expected
|
|
|
|
def test_error_with_context_and_suggestions(self):
|
|
"""Test error with both context and suggestions"""
|
|
context = {'config_file': '/etc/deb-mock.conf'}
|
|
suggestions = ["Check config syntax", "Verify file exists"]
|
|
error = DebMockError("Invalid configuration",
|
|
context=context, suggestions=suggestions)
|
|
|
|
expected = """Error: Invalid configuration
|
|
|
|
Context:
|
|
config_file: /etc/deb-mock.conf
|
|
|
|
Suggestions:
|
|
1. Check config syntax
|
|
2. Verify file exists"""
|
|
assert str(error) == expected
|
|
|
|
def test_print_error(self, capsys):
|
|
"""Test error printing to stderr"""
|
|
error = DebMockError("Test error")
|
|
error.print_error()
|
|
captured = capsys.readouterr()
|
|
assert "Error: Test error" in captured.err
|
|
|
|
def test_get_exit_code(self):
|
|
"""Test exit code retrieval"""
|
|
error = DebMockError("Test error", exit_code=42)
|
|
assert error.get_exit_code() == 42
|
|
|
|
|
|
class TestSpecificExceptions:
|
|
"""Test specific exception types"""
|
|
|
|
def test_configuration_error(self):
|
|
"""Test ConfigurationError with file and section context"""
|
|
error = ConfigurationError(
|
|
"Invalid configuration",
|
|
config_file="/etc/deb-mock.conf",
|
|
config_section="chroot"
|
|
)
|
|
|
|
assert "config_file: /etc/deb-mock.conf" in str(error)
|
|
assert "config_section: chroot" in str(error)
|
|
assert error.exit_code == 2
|
|
assert len(error.suggestions) > 0
|
|
|
|
def test_chroot_error(self):
|
|
"""Test ChrootError with operation context"""
|
|
error = ChrootError(
|
|
"Failed to create chroot",
|
|
chroot_name="bookworm-amd64",
|
|
operation="create",
|
|
chroot_path="/var/lib/deb-mock/chroots/bookworm-amd64"
|
|
)
|
|
|
|
assert "chroot_name: bookworm-amd64" in str(error)
|
|
assert "operation: create" in str(error)
|
|
assert error.exit_code == 3
|
|
assert "clean-chroot" in str(error.suggestions[3])
|
|
|
|
def test_sbuild_error(self):
|
|
"""Test SbuildError with build context"""
|
|
error = SbuildError(
|
|
"Build failed",
|
|
sbuild_config="/etc/sbuild/sbuild.conf",
|
|
build_log="/var/log/sbuild.log",
|
|
return_code=1
|
|
)
|
|
|
|
assert "sbuild_config: /etc/sbuild/sbuild.conf" in str(error)
|
|
assert "build_log: /var/log/sbuild.log" in str(error)
|
|
assert "return_code: 1" in str(error)
|
|
assert error.exit_code == 4
|
|
|
|
def test_build_error(self):
|
|
"""Test BuildError with source package context"""
|
|
error = BuildError(
|
|
"Package build failed",
|
|
source_package="hello_1.0.dsc",
|
|
build_log="/tmp/build.log",
|
|
artifacts=["hello_1.0-1_amd64.deb"]
|
|
)
|
|
|
|
assert "source_package: hello_1.0.dsc" in str(error)
|
|
assert "build_log: /tmp/build.log" in str(error)
|
|
assert "artifacts: ['hello_1.0-1_amd64.deb']" in str(error)
|
|
assert error.exit_code == 5
|
|
|
|
def test_dependency_error(self):
|
|
"""Test DependencyError with missing packages"""
|
|
error = DependencyError(
|
|
"Missing build dependencies",
|
|
missing_packages=["build-essential", "devscripts"],
|
|
conflicting_packages=["old-package"]
|
|
)
|
|
|
|
assert "missing_packages: ['build-essential', 'devscripts']" in str(error)
|
|
assert "conflicting_packages: ['old-package']" in str(error)
|
|
assert error.exit_code == 6
|
|
|
|
def test_cache_error(self):
|
|
"""Test CacheError with cache context"""
|
|
error = CacheError(
|
|
"Cache operation failed",
|
|
cache_type="root_cache",
|
|
cache_path="/var/cache/deb-mock/root-cache",
|
|
operation="restore"
|
|
)
|
|
|
|
assert "cache_type: root_cache" in str(error)
|
|
assert "cache_path: /var/cache/deb-mock/root-cache" in str(error)
|
|
assert "operation: restore" in str(error)
|
|
assert error.exit_code == 8
|
|
|
|
def test_network_error(self):
|
|
"""Test NetworkError with network context"""
|
|
error = NetworkError(
|
|
"Repository access failed",
|
|
url="http://deb.debian.org/debian/",
|
|
proxy="http://proxy.example.com:3128",
|
|
timeout=30
|
|
)
|
|
|
|
assert "url: http://deb.debian.org/debian/" in str(error)
|
|
assert "proxy: http://proxy.example.com:3128" in str(error)
|
|
assert "timeout: 30" in str(error)
|
|
assert error.exit_code == 10
|
|
|
|
def test_permission_error(self):
|
|
"""Test PermissionError with permission context"""
|
|
error = PermissionError(
|
|
"Insufficient privileges",
|
|
operation="create_chroot",
|
|
path="/var/lib/deb-mock",
|
|
required_privileges="root"
|
|
)
|
|
|
|
assert "operation: create_chroot" in str(error)
|
|
assert "path: /var/lib/deb-mock" in str(error)
|
|
assert "required_privileges: root" in str(error)
|
|
assert error.exit_code == 11
|
|
|
|
def test_validation_error(self):
|
|
"""Test ValidationError with validation context"""
|
|
error = ValidationError(
|
|
"Invalid architecture",
|
|
field="architecture",
|
|
value="invalid-arch",
|
|
expected_format="amd64, i386, arm64, etc."
|
|
)
|
|
|
|
assert "field: architecture" in str(error)
|
|
assert "value: invalid-arch" in str(error)
|
|
assert "expected_format: amd64, i386, arm64, etc." in str(error)
|
|
assert error.exit_code == 12
|
|
|
|
|
|
class TestHelperFunctions:
|
|
"""Test helper functions"""
|
|
|
|
def test_format_error_context(self):
|
|
"""Test format_error_context helper"""
|
|
context = format_error_context(
|
|
file="/path/to/file",
|
|
operation="read",
|
|
user="testuser",
|
|
none_value=None
|
|
)
|
|
|
|
expected = {
|
|
'file': '/path/to/file',
|
|
'operation': 'read',
|
|
'user': 'testuser'
|
|
}
|
|
assert context == expected
|
|
assert 'none_value' not in context
|
|
|
|
def test_handle_exception_decorator_success(self):
|
|
"""Test handle_exception decorator with successful function"""
|
|
@handle_exception
|
|
def successful_function():
|
|
return "success"
|
|
|
|
result = successful_function()
|
|
assert result == "success"
|
|
|
|
def test_handle_exception_decorator_debmock_error(self, capsys):
|
|
"""Test handle_exception decorator with DebMockError"""
|
|
@handle_exception
|
|
def failing_function():
|
|
raise ConfigurationError("Config error", config_file="/etc/config")
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
failing_function()
|
|
|
|
assert exc_info.value.code == 2
|
|
captured = capsys.readouterr()
|
|
assert "Error: Config error" in captured.err
|
|
assert "config_file: /etc/config" in captured.err
|
|
|
|
def test_handle_exception_decorator_unexpected_error(self, capsys):
|
|
"""Test handle_exception decorator with unexpected error"""
|
|
@handle_exception
|
|
def unexpected_error_function():
|
|
raise ValueError("Unexpected value error")
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
unexpected_error_function()
|
|
|
|
assert exc_info.value.code == 1
|
|
captured = capsys.readouterr()
|
|
assert "Unexpected error: Unexpected value error" in captured.err
|
|
assert "This may be a bug in deb-mock" in captured.err
|
|
|
|
|
|
class TestExceptionIntegration:
|
|
"""Test exception integration scenarios"""
|
|
|
|
def test_chroot_creation_error_scenario(self):
|
|
"""Test realistic chroot creation error scenario"""
|
|
error = ChrootError(
|
|
"Failed to create chroot environment",
|
|
chroot_name="bookworm-amd64",
|
|
operation="debootstrap",
|
|
chroot_path="/var/lib/deb-mock/chroots/bookworm-amd64"
|
|
)
|
|
|
|
error_str = str(error)
|
|
|
|
# Check that all context information is present
|
|
assert "chroot_name: bookworm-amd64" in error_str
|
|
assert "operation: debootstrap" in error_str
|
|
assert "chroot_path: /var/lib/deb-mock/chroots/bookworm-amd64" in error_str
|
|
|
|
# Check that helpful suggestions are provided
|
|
assert "sufficient disk space" in error_str
|
|
assert "root privileges" in error_str
|
|
assert "clean-chroot" in error_str
|
|
|
|
# Check exit code
|
|
assert error.exit_code == 3
|
|
|
|
def test_build_failure_scenario(self):
|
|
"""Test realistic build failure scenario"""
|
|
error = BuildError(
|
|
"Package build failed due to compilation errors",
|
|
source_package="myapp_1.0.dsc",
|
|
build_log="/tmp/build_myapp.log",
|
|
artifacts=[]
|
|
)
|
|
|
|
error_str = str(error)
|
|
|
|
# Check context information
|
|
assert "source_package: myapp_1.0.dsc" in error_str
|
|
assert "build_log: /tmp/build_myapp.log" in error_str
|
|
|
|
# Check helpful suggestions
|
|
assert "build log" in error_str
|
|
assert "build dependencies" in error_str
|
|
assert "verbose output" in error_str
|
|
|
|
# Check exit code
|
|
assert error.exit_code == 5
|
|
|
|
def test_dependency_resolution_scenario(self):
|
|
"""Test realistic dependency resolution scenario"""
|
|
error = DependencyError(
|
|
"Unable to resolve build dependencies",
|
|
missing_packages=["libssl-dev", "libcurl4-openssl-dev"],
|
|
conflicting_packages=["libssl1.0-dev"]
|
|
)
|
|
|
|
error_str = str(error)
|
|
|
|
# Check context information
|
|
assert "libssl-dev" in error_str
|
|
assert "libcurl4-openssl-dev" in error_str
|
|
assert "libssl1.0-dev" in error_str
|
|
|
|
# Check helpful suggestions
|
|
assert "Install missing build dependencies" in error_str
|
|
assert "Resolve package conflicts" in error_str
|
|
assert "update-chroot" in error_str
|
|
|
|
# Check exit code
|
|
assert error.exit_code == 6 |