diff --git a/tests/cli/test_admin.py b/tests/cli/test_admin.py deleted file mode 100644 index a0eba1c1..00000000 --- a/tests/cli/test_admin.py +++ /dev/null @@ -1,392 +0,0 @@ -"""Tests for admin CLI commands""" - -import pytest -import json -from click.testing import CliRunner -from unittest.mock import Mock, patch -from aitbc_cli.commands.admin import admin - - -@pytest.fixture -def runner(): - """Create CLI runner""" - return CliRunner() - - -@pytest.fixture -def mock_config(): - """Mock configuration""" - config = Mock() - config.coordinator_url = "http://test:8000" - config.api_key = "test_admin_key" - return config - - -class TestAdminCommands: - """Test admin command group""" - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_status_success(self, mock_client_class, runner, mock_config): - """Test successful system status check""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "status": "healthy", - "version": "1.0.0", - "uptime": 3600 - } - mock_client.get.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'status' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - data = json.loads(result.output) - assert data['status'] == 'healthy' - assert data['version'] == '1.0.0' - - # Verify API call - mock_client.get.assert_called_once_with( - 'http://test:8000/v1/admin/status', - headers={"X-Api-Key": "test_admin_key"} - ) - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_jobs_with_filter(self, mock_client_class, runner, mock_config): - """Test jobs listing with filters""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "jobs": [ - {"id": "job1", "status": "completed"}, - {"id": "job2", "status": "running"} - ] - } - mock_client.get.return_value = mock_response - - # Run command with filters - result = runner.invoke(admin, [ - 'jobs', - '--status', 'running', - '--limit', '50' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - - # Verify API call with filters - mock_client.get.assert_called_once() - call_args = mock_client.get.call_args - assert '/v1/admin/jobs' in call_args[0][0] - assert call_args[1]['params']['status'] == 'running' - assert call_args[1]['params']['limit'] == 50 - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_job_details_success(self, mock_client_class, runner, mock_config): - """Test successful job details retrieval""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "id": "job123", - "status": "completed", - "result": "Test result", - "created_at": "2024-01-01T00:00:00" - } - mock_client.get.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'job-details', - 'job123' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - data = json.loads(result.output) - assert data['id'] == 'job123' - assert data['status'] == 'completed' - - # Verify API call - mock_client.get.assert_called_once_with( - 'http://test:8000/v1/admin/jobs/job123', - headers={"X-Api-Key": "test_admin_key"} - ) - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_delete_job_confirmed(self, mock_client_class, runner, mock_config): - """Test successful job deletion with confirmation""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_client.delete.return_value = mock_response - - # Run command with confirmation - result = runner.invoke(admin, [ - 'delete-job', - 'job123' - ], obj={'config': mock_config, 'output_format': 'json'}, input='y\n') - - # Assertions - assert result.exit_code == 0 - assert 'deleted' in result.output - - # Verify API call - mock_client.delete.assert_called_once_with( - 'http://test:8000/v1/admin/jobs/job123', - headers={"X-Api-Key": "test_admin_key"} - ) - - def test_delete_job_cancelled(self, runner, mock_config): - """Test job deletion cancelled by user""" - # Run command with cancellation - result = runner.invoke(admin, [ - 'delete-job', - 'job123' - ], obj={'config': mock_config, 'output_format': 'json'}, input='n\n') - - # Assertions - assert result.exit_code == 0 - # No API calls should be made - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_miners_list(self, mock_client_class, runner, mock_config): - """Test miners listing""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "miners": [ - {"id": "miner1", "status": "active", "gpu": "RTX4090"}, - {"id": "miner2", "status": "inactive", "gpu": "RTX3080"} - ] - } - mock_client.get.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'miners' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - data = json.loads(result.output) - assert len(data['miners']) == 2 - - # Verify API call - mock_client.get.assert_called_once_with( - 'http://test:8000/v1/admin/miners', - params={"limit": 50}, - headers={"X-Api-Key": "test_admin_key"} - ) - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_deactivate_miner(self, mock_client_class, runner, mock_config): - """Test miner deactivation""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_client.post.return_value = mock_response - - # Run command with confirmation - result = runner.invoke(admin, [ - 'deactivate-miner', - 'miner123' - ], obj={'config': mock_config, 'output_format': 'json'}, input='y\n') - - # Assertions - assert result.exit_code == 0 - assert 'deactivated' in result.output - - # Verify API call - mock_client.post.assert_called_once_with( - 'http://test:8000/v1/admin/miners/miner123/deactivate', - headers={"X-Api-Key": "test_admin_key"} - ) - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_analytics(self, mock_client_class, runner, mock_config): - """Test system analytics""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "total_jobs": 1000, - "completed_jobs": 950, - "active_miners": 50, - "average_processing_time": 120 - } - mock_client.get.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'analytics', - '--days', '7' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - data = json.loads(result.output) - assert data['total_jobs'] == 1000 - assert data['active_miners'] == 50 - - # Verify API call - mock_client.get.assert_called_once() - call_args = mock_client.get.call_args - assert '/v1/admin/analytics' in call_args[0][0] - assert call_args[1]['params']['days'] == 7 - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_logs_with_level(self, mock_client_class, runner, mock_config): - """Test system logs with level filter""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "logs": [ - {"level": "ERROR", "message": "Test error", "timestamp": "2024-01-01T00:00:00"} - ] - } - mock_client.get.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'logs', - '--level', 'ERROR', - '--limit', '50' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - - # Verify API call - mock_client.get.assert_called_once() - call_args = mock_client.get.call_args - assert '/v1/admin/logs' in call_args[0][0] - assert call_args[1]['params']['level'] == 'ERROR' - assert call_args[1]['params']['limit'] == 50 - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_prioritize_job(self, mock_client_class, runner, mock_config): - """Test job prioritization""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_client.post.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'prioritize-job', - 'job123', - '--reason', 'Urgent request' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - assert 'prioritized' in result.output - - # Verify API call - mock_client.post.assert_called_once() - call_args = mock_client.post.call_args - assert '/v1/admin/jobs/job123/prioritize' in call_args[0][0] - assert call_args[1]['json']['reason'] == 'Urgent request' - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_execute_custom_action(self, mock_client_class, runner, mock_config): - """Test custom action execution""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"status": "success", "result": "Action completed"} - mock_client.post.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'execute', - '--action', 'custom_command', - '--target', 'miner123', - '--data', '{"param": "value"}' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code == 0 - data = json.loads(result.output) - assert data['status'] == 'success' - - # Verify API call - mock_client.post.assert_called_once() - call_args = mock_client.post.call_args - assert '/v1/admin/execute/custom_command' in call_args[0][0] - assert call_args[1]['json']['target'] == 'miner123' - assert call_args[1]['json']['param'] == 'value' - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_maintenance_cleanup(self, mock_client_class, runner, mock_config): - """Test maintenance cleanup""" - # Setup mock - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"cleaned_items": 100} - mock_client.post.return_value = mock_response - - # Run command with confirmation - result = runner.invoke(admin, [ - 'maintenance', - 'cleanup' - ], obj={'config': mock_config, 'output_format': 'json'}, input='y\n') - - # Assertions - assert result.exit_code == 0 - assert 'Cleanup completed' in result.output - - # Verify API call - mock_client.post.assert_called_once_with( - 'http://test:8000/v1/admin/maintenance/cleanup', - headers={"X-Api-Key": "test_admin_key"} - ) - - @patch('aitbc_cli.commands.admin.httpx.Client') - def test_api_error_handling(self, mock_client_class, runner, mock_config): - """Test API error handling""" - # Setup mock for error response - mock_client = Mock() - mock_client_class.return_value.__enter__.return_value = mock_client - mock_response = Mock() - mock_response.status_code = 403 - mock_client.get.return_value = mock_response - - # Run command - result = runner.invoke(admin, [ - 'status' - ], obj={'config': mock_config, 'output_format': 'json'}) - - # Assertions - assert result.exit_code != 0 - assert 'Error' in result.output