deb-mock/tests/test_api.py
robojerk 8c585e2e33
Some checks failed
Build Deb-Mock Package / build (push) Failing after 59s
Lint Code / Lint All Code (push) Failing after 2s
Test Deb-Mock Build / test (push) Failing after 41s
Add stable Python API and comprehensive environment management
- Add MockAPIClient and MockEnvironment for external integration
- Implement EnvironmentManager with full lifecycle support
- Enhance plugin system with registry and BasePlugin class
- Add comprehensive test suite and documentation
- Include practical usage examples and plugin development guide
2025-09-04 10:04:16 -07:00

479 lines
18 KiB
Python

"""
Tests for deb-mock API
This module contains comprehensive tests for the deb-mock API to ensure
stability and reliability for external integrations.
"""
import os
import sys
import tempfile
import unittest
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
# Add deb-mock to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from deb_mock.api import MockAPIClient, MockEnvironment, MockConfigBuilder, create_client
from deb_mock.environment_manager import EnvironmentManager, EnvironmentInfo, BuildResult
from deb_mock.config import Config
from deb_mock.exceptions import ChrootError, ConfigurationError
class TestMockConfigBuilder(unittest.TestCase):
"""Test the MockConfigBuilder class"""
def setUp(self):
self.builder = MockConfigBuilder()
def test_basic_configuration(self):
"""Test basic configuration building"""
config = (self.builder
.environment("test-env")
.architecture("amd64")
.suite("trixie")
.mirror("http://test.debian.org/debian/")
.build())
self.assertEqual(config.chroot_name, "test-env")
self.assertEqual(config.architecture, "amd64")
self.assertEqual(config.suite, "trixie")
self.assertEqual(config.mirror, "http://test.debian.org/debian/")
def test_packages_configuration(self):
"""Test packages configuration"""
packages = ["build-essential", "devscripts", "cmake"]
config = self.builder.packages(packages).build()
self.assertEqual(config.chroot_additional_packages, packages)
def test_output_directory(self):
"""Test output directory configuration"""
output_dir = "/tmp/test-output"
config = self.builder.output_dir(output_dir).build()
self.assertEqual(config.output_dir, output_dir)
def test_cache_settings(self):
"""Test cache configuration"""
config = self.builder.cache_enabled(True).build()
self.assertTrue(config.use_root_cache)
config = self.builder.cache_enabled(False).build()
self.assertFalse(config.use_root_cache)
def test_parallel_jobs(self):
"""Test parallel jobs configuration"""
config = self.builder.parallel_jobs(8).build()
self.assertEqual(config.parallel_jobs, 8)
def test_verbose_debug(self):
"""Test verbose and debug configuration"""
config = (self.builder
.verbose(True)
.debug(True)
.build())
self.assertTrue(config.verbose)
self.assertTrue(config.debug)
class TestMockAPIClient(unittest.TestCase):
"""Test the MockAPIClient class"""
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
self.config = Config(
chroot_dir=self.temp_dir,
output_dir=os.path.join(self.temp_dir, "output"),
chroot_config_dir=os.path.join(self.temp_dir, "config")
)
# Create necessary directories
os.makedirs(self.config.chroot_config_dir, exist_ok=True)
# Mock the DebMock class to avoid actual chroot operations
with patch('deb_mock.api.DebMock') as mock_deb_mock:
self.mock_deb_mock_instance = Mock()
mock_deb_mock.return_value = self.mock_deb_mock_instance
# Mock chroot manager
self.mock_chroot_manager = Mock()
self.mock_deb_mock_instance.chroot_manager = self.mock_chroot_manager
self.mock_chroot_manager.chroot_exists.return_value = False
self.mock_chroot_manager.get_chroot_info.return_value = {
'name': 'test-env',
'status': 'active',
'size': 1024,
'created': None,
'modified': None
}
# Mock other methods
self.mock_deb_mock_instance.init_chroot = Mock()
self.mock_deb_mock_instance.install_packages = Mock(return_value={'success': True})
self.mock_deb_mock_instance.clean_chroot = Mock()
self.mock_deb_mock_instance.list_chroots = Mock(return_value=[])
self.mock_deb_mock_instance.build = Mock(return_value={'success': True, 'artifacts': []})
self.mock_deb_mock_instance.build_parallel = Mock(return_value=[{'success': True}])
self.mock_deb_mock_instance.build_chain = Mock(return_value=[{'success': True}])
self.mock_deb_mock_instance.get_cache_stats = Mock(return_value={})
self.mock_deb_mock_instance.cleanup_caches = Mock(return_value={})
self.client = MockAPIClient(self.config)
def tearDown(self):
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
def test_client_initialization(self):
"""Test client initialization"""
self.assertIsInstance(self.client, MockAPIClient)
self.assertEqual(self.client.config, self.config)
def test_create_environment(self):
"""Test environment creation"""
env = self.client.create_environment("test-env", "amd64", "trixie", ["build-essential"])
self.assertIsInstance(env, MockEnvironment)
self.assertEqual(env.name, "test-env")
self.mock_deb_mock_instance.init_chroot.assert_called_once_with("test-env", "amd64", "trixie")
self.mock_deb_mock_instance.install_packages.assert_called_once_with(["build-essential"])
def test_get_environment(self):
"""Test getting existing environment"""
# Mock existing environment
self.mock_chroot_manager.chroot_exists.return_value = True
env = self.client.get_environment("test-env")
self.assertIsInstance(env, MockEnvironment)
self.assertEqual(env.name, "test-env")
def test_get_nonexistent_environment(self):
"""Test getting non-existent environment"""
self.mock_chroot_manager.chroot_exists.return_value = False
with self.assertRaises(ValueError):
self.client.get_environment("nonexistent-env")
def test_list_environments(self):
"""Test listing environments"""
self.mock_deb_mock_instance.list_chroots.return_value = ["env1", "env2"]
environments = self.client.list_environments()
self.assertEqual(environments, ["env1", "env2"])
def test_remove_environment(self):
"""Test removing environment"""
self.client.remove_environment("test-env")
self.mock_deb_mock_instance.clean_chroot.assert_called_once_with("test-env")
def test_build_package(self):
"""Test building a package"""
result = self.client.build_package("/path/to/package.dsc", "test-env")
self.mock_deb_mock_instance.build.assert_called_once()
self.assertEqual(result['success'], True)
def test_build_parallel(self):
"""Test parallel building"""
packages = ["/path/to/pkg1.dsc", "/path/to/pkg2.dsc"]
results = self.client.build_parallel(packages, max_workers=2)
self.mock_deb_mock_instance.build_parallel.assert_called_once_with(packages, 2)
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['success'], True)
def test_build_chain(self):
"""Test chain building"""
packages = ["/path/to/pkg1.dsc", "/path/to/pkg2.dsc"]
results = self.client.build_chain(packages)
self.mock_deb_mock_instance.build_chain.assert_called_once_with(packages)
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['success'], True)
def test_environment_context_manager(self):
"""Test environment context manager"""
# Mock existing environment
self.mock_chroot_manager.chroot_exists.return_value = True
with self.client.environment("test-env") as env:
self.assertIsInstance(env, MockEnvironment)
self.assertEqual(env.name, "test-env")
self.assertTrue(env.is_active())
# Environment should be deactivated after context
self.assertFalse(env.is_active())
class TestMockEnvironment(unittest.TestCase):
"""Test the MockEnvironment class"""
def setUp(self):
self.mock_deb_mock = Mock()
self.mock_chroot_manager = Mock()
self.mock_deb_mock.chroot_manager = self.mock_chroot_manager
self.mock_chroot_manager.chroot_exists.return_value = True
self.mock_chroot_manager.execute_in_chroot.return_value = Mock(returncode=0, stdout="test output")
self.mock_chroot_manager.get_chroot_info.return_value = {'status': 'active'}
self.env = MockEnvironment("test-env", self.mock_deb_mock)
def test_environment_initialization(self):
"""Test environment initialization"""
self.assertEqual(self.env.name, "test-env")
self.assertFalse(self.env.is_active())
def test_activate_deactivate(self):
"""Test environment activation and deactivation"""
self.env.activate()
self.assertTrue(self.env.is_active())
self.env.deactivate()
self.assertFalse(self.env.is_active())
def test_activate_nonexistent_environment(self):
"""Test activating non-existent environment"""
self.mock_chroot_manager.chroot_exists.return_value = False
with self.assertRaises(ChrootError):
self.env.activate()
def test_execute_command(self):
"""Test command execution"""
self.env.activate()
result = self.env.execute(["ls", "-la"])
self.mock_chroot_manager.execute_in_chroot.assert_called_once_with(
"test-env", ["ls", "-la"], capture_output=True
)
self.assertEqual(result.returncode, 0)
def test_execute_command_string(self):
"""Test command execution with string command"""
self.env.activate()
result = self.env.execute("ls -la")
self.mock_chroot_manager.execute_in_chroot.assert_called_once_with(
"test-env", ["ls", "-la"], capture_output=True
)
def test_execute_command_inactive(self):
"""Test executing command on inactive environment"""
with self.assertRaises(RuntimeError):
self.env.execute(["ls"])
def test_install_packages(self):
"""Test package installation"""
self.env.activate()
result = self.env.install_packages(["build-essential"])
self.mock_deb_mock.install_packages.assert_called_once_with(["build-essential"])
self.assertEqual(result['success'], True)
def test_copy_in(self):
"""Test copying files into environment"""
self.env.activate()
self.env.copy_in("/local/file", "/chroot/file")
self.mock_chroot_manager.copy_to_chroot.assert_called_once_with(
"/local/file", "/chroot/file", "test-env"
)
def test_copy_out(self):
"""Test copying files out of environment"""
self.env.activate()
self.env.copy_out("/chroot/file", "/local/file")
self.mock_chroot_manager.copy_from_chroot.assert_called_once_with(
"/chroot/file", "/local/file", "test-env"
)
def test_get_info(self):
"""Test getting environment info"""
info = self.env.get_info()
self.mock_chroot_manager.get_chroot_info.assert_called_once_with("test-env")
self.assertEqual(info['status'], 'active')
class TestEnvironmentManager(unittest.TestCase):
"""Test the EnvironmentManager class"""
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
self.config = Config(
chroot_dir=self.temp_dir,
output_dir=os.path.join(self.temp_dir, "output"),
chroot_config_dir=os.path.join(self.temp_dir, "config")
)
# Create necessary directories
os.makedirs(self.config.chroot_config_dir, exist_ok=True)
# Mock the DebMock class
with patch('deb_mock.environment_manager.DebMock') as mock_deb_mock:
self.mock_deb_mock_instance = Mock()
mock_deb_mock.return_value = self.mock_deb_mock_instance
# Mock chroot manager
self.mock_chroot_manager = Mock()
self.mock_deb_mock_instance.chroot_manager = self.mock_chroot_manager
self.mock_chroot_manager.chroot_exists.return_value = False
self.mock_chroot_manager.get_chroot_info.return_value = {
'name': 'test-env',
'status': 'active',
'size': 1024,
'created': None,
'modified': None
}
self.mock_chroot_manager.list_mounts.return_value = []
# Mock other methods
self.mock_deb_mock_instance.init_chroot = Mock()
self.mock_deb_mock_instance.install_packages = Mock(return_value={'success': True})
self.mock_deb_mock_instance.clean_chroot = Mock()
self.mock_deb_mock_instance.list_chroots = Mock(return_value=[])
self.mock_deb_mock_instance.build = Mock(return_value={'success': True, 'artifacts': []})
self.mock_deb_mock_instance.update_chroot = Mock()
self.manager = EnvironmentManager(self.config)
def tearDown(self):
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
def test_manager_initialization(self):
"""Test manager initialization"""
self.assertIsInstance(self.manager, EnvironmentManager)
self.assertEqual(self.manager.config, self.config)
def test_create_environment(self):
"""Test environment creation"""
info = self.manager.create_environment("test-env", "amd64", "trixie", ["build-essential"])
self.assertIsInstance(info, EnvironmentInfo)
self.assertEqual(info.name, "test-env")
self.assertEqual(info.architecture, "amd64")
self.assertEqual(info.suite, "trixie")
self.mock_deb_mock_instance.init_chroot.assert_called_once_with("test-env", "amd64", "trixie")
def test_environment_exists(self):
"""Test checking if environment exists"""
self.mock_chroot_manager.chroot_exists.return_value = True
self.assertTrue(self.manager.environment_exists("test-env"))
self.mock_chroot_manager.chroot_exists.return_value = False
self.assertFalse(self.manager.environment_exists("test-env"))
def test_get_environment_info(self):
"""Test getting environment info"""
self.mock_chroot_manager.chroot_exists.return_value = True
info = self.manager.get_environment_info("test-env")
self.assertIsInstance(info, EnvironmentInfo)
self.assertEqual(info.name, "test-env")
def test_get_nonexistent_environment_info(self):
"""Test getting info for non-existent environment"""
self.mock_chroot_manager.chroot_exists.return_value = False
with self.assertRaises(ValueError):
self.manager.get_environment_info("nonexistent-env")
def test_list_environments(self):
"""Test listing environments"""
self.mock_deb_mock_instance.list_chroots.return_value = ["env1", "env2"]
self.mock_chroot_manager.chroot_exists.return_value = True
environments = self.manager.list_environments()
self.assertEqual(len(environments), 2)
self.assertIsInstance(environments[0], EnvironmentInfo)
def test_remove_environment(self):
"""Test removing environment"""
self.mock_chroot_manager.chroot_exists.return_value = True
self.manager.remove_environment("test-env")
self.mock_deb_mock_instance.clean_chroot.assert_called_once_with("test-env")
def test_execute_command(self):
"""Test command execution"""
self.mock_chroot_manager.chroot_exists.return_value = True
self.mock_chroot_manager.execute_in_chroot.return_value = Mock(returncode=0, stdout="test output")
result = self.manager.execute_command("test-env", ["ls", "-la"])
self.mock_chroot_manager.execute_in_chroot.assert_called_once_with(
"test-env", ["ls", "-la"], capture_output=True
)
self.assertEqual(result.returncode, 0)
def test_install_packages(self):
"""Test package installation"""
self.mock_chroot_manager.chroot_exists.return_value = True
result = self.manager.install_packages("test-env", ["build-essential"])
self.mock_deb_mock_instance.install_packages.assert_called_once_with(["build-essential"])
self.assertEqual(result['success'], True)
def test_build_package(self):
"""Test package building"""
self.mock_chroot_manager.chroot_exists.return_value = True
result = self.manager.build_package("test-env", "/path/to/package.dsc")
self.mock_deb_mock_instance.build.assert_called_once()
self.assertIsInstance(result, BuildResult)
self.assertTrue(result.success)
class TestIntegration(unittest.TestCase):
"""Integration tests for the API"""
def test_create_client_with_config_builder(self):
"""Test creating client with config builder"""
config = (MockConfigBuilder()
.environment("test-env")
.architecture("amd64")
.suite("trixie")
.build())
client = MockAPIClient(config)
self.assertIsInstance(client, MockAPIClient)
self.assertEqual(client.config.chroot_name, "test-env")
def test_quick_build_function(self):
"""Test the quick_build convenience function"""
from deb_mock.api import quick_build
with patch('deb_mock.api.MockAPIClient') as mock_client_class:
mock_client = Mock()
mock_client.build_package.return_value = {'success': True}
mock_client_class.return_value = mock_client
result = quick_build("/path/to/package.dsc")
self.assertEqual(result['success'], True)
mock_client.build_package.assert_called_once()
if __name__ == '__main__':
unittest.main()