| |
| """ |
| Testes para o HardwareManager (hardware.py). |
| |
| Estes testes usam mocks para simular a biblioteca pynvml, permitindo |
| testar a lógica do HardwareManager sem a necessidade de uma GPU física. |
| """ |
|
|
| import pytest |
| from unittest.mock import patch, MagicMock, PropertyMock |
| from superezio_enterprise.hardware import HardwareManager, GpuState, get_hardware_manager |
|
|
| |
| |
| nvml_mock = MagicMock() |
|
|
| |
| nvml_mock.NVML_TEMPERATURE_GPU = 0 |
| def nvml_error(*args, **kwargs): |
| raise nvml_mock.NVMLError(1) |
|
|
| |
| @pytest.fixture |
| def mock_nvml_structs(): |
| class MockMemInfo: |
| def __init__(self, total, free, used): |
| self.total = total |
| self.free = free |
| self.used = used |
|
|
| class MockUtilRates: |
| def __init__(self, gpu): |
| self.gpu = gpu |
|
|
| return MockMemInfo, MockUtilRates |
|
|
| @pytest.fixture |
| def mock_pynvml(mock_nvml_structs): |
| """Configura o mock completo da pynvml para simular 2 GPUs.""" |
| MockMemInfo, MockUtilRates = mock_nvml_structs |
|
|
| nvml_mock.reset_mock() |
| nvml_mock.nvmlInit.side_effect = None |
| nvml_mock.nvmlDeviceGetCount.return_value = 2 |
|
|
| |
| handle0 = "handle0" |
| |
| handle1 = "handle1" |
|
|
| nvml_mock.nvmlDeviceGetHandleByIndex.side_effect = [handle0, handle1] |
| nvml_mock.nvmlDeviceGetName.side_effect = [ |
| b"Mock GPU 0", |
| b"Mock GPU 1", |
| ] |
| nvml_mock.nvmlDeviceGetMemoryInfo.side_effect = [ |
| MockMemInfo(total=8000 * 1024**2, free=6000 * 1024**2, used=2000 * 1024**2), |
| MockMemInfo(total=16000 * 1024**2, free=12000 * 1024**2, used=4000 * 1024**2), |
| ] |
| nvml_mock.nvmlDeviceGetUtilizationRates.side_effect = [ |
| MockUtilRates(gpu=10), |
| MockUtilRates(gpu=50), |
| ] |
| nvml_mock.nvmlDeviceGetTemperature.return_value = 60 |
| nvml_mock.nvmlDeviceGetPowerUsage.return_value = 150 * 1000 |
|
|
| with patch.dict("sys.modules", {"pynvml": nvml_mock}): |
| |
| from superezio_enterprise.hardware import HardwareManager, GpuState, get_hardware_manager |
| nvml_mock.reset_mock() |
| yield nvml_mock, HardwareManager, GpuState, get_hardware_manager |
|
|
| def test_hardware_manager_initialization(mock_pynvml): |
| """Testa se o manager inicializa corretamente com as GPUs mockadas.""" |
| nvml, HardwareManager, _, get_hardware_manager_func = mock_pynvml |
| HardwareManager._instance = None |
| manager = get_hardware_manager_func() |
| manager.shutdown() |
|
|
| nvml.nvmlInit.assert_called_once() |
| assert manager.is_initialized is True |
| assert manager.gpu_count == 2 |
| assert len(manager.gpu_states) == 2 |
| assert manager.gpu_states[0].name == "Mock GPU 0" |
| assert manager.gpu_states[1].total_memory_mb == pytest.approx(16000) |
|
|
| def test_assign_model_to_best_gpu(mock_pynvml): |
| """Testa a lógica de alocação de modelo para a melhor GPU disponível.""" |
| _, HardwareManager, _, get_hardware_manager_func = mock_pynvml |
| manager = get_hardware_manager_func() |
|
|
| |
| |
| assigned_gpu = manager.assign_model_to_gpu("model-a", 5000) |
| assert assigned_gpu == 0 |
| assert manager.assignments["model-a"] == 0 |
|
|
| |
| assigned_gpu_2 = manager.assign_model_to_gpu("model-b", 10000) |
| assert assigned_gpu_2 == 1 |
| assert manager.assignments["model-b"] == 1 |
|
|
| manager.shutdown() |
|
|
| def test_assign_model_insufficient_vram(mock_pynvml): |
| """Testa a falha na alocação quando nenhuma GPU tem VRAM suficiente.""" |
| _, HardwareManager, _, get_hardware_manager_func = mock_pynvml |
| manager = get_hardware_manager_func() |
| assigned_gpu = manager.assign_model_to_gpu("huge-model", 20000) |
| assert assigned_gpu is None |
| manager.shutdown() |
|
|
| def test_release_model(mock_pynvml): |
| """Testa a liberação de um modelo previamente alocado.""" |
| _, HardwareManager, _, get_hardware_manager_func = mock_pynvml |
| manager = get_hardware_manager_func() |
| manager.assign_model_to_gpu("model-c", 4000) |
| assert "model-c" in manager.assignments |
|
|
| manager.release_model("model-c") |
| assert "model-c" not in manager.assignments |
| manager.shutdown() |
|
|
| def test_initialization_fails_with_nvml_error(mock_pynvml): |
| """Testa se o manager lida com erros de inicialização da NVML.""" |
| nvml, HardwareManager, _ = mock_pynvml |
| nvml.nvmlInit.side_effect = nvml_mock.NVMLError(1) |
|
|
| |
| HardwareManager._instance = None |
| manager = HardwareManager() |
|
|
| assert manager.is_initialized is False |
| assert manager.gpu_count == 0 |
| manager.shutdown() |
|
|