#!/usr/bin/env python3 """ Unit tests for CLI tool """ import unittest import tempfile import os import json import shutil from unittest.mock import patch, MagicMock from io import StringIO import sys from pathlib import Path # Add api directory to path api_dir = Path(__file__).parent.parent / 'api' sys.path.insert(0, str(api_dir)) # Import from api package instead of tests package try: from cell_cli import api_request, show_status, list_peers, add_peer, remove_peer, show_config, update_config except ImportError: # Fallback for when running from tests directory import sys sys.path.append('..') from api.cell_cli import api_request, show_status, list_peers, add_peer, remove_peer, show_config, update_config class TestCLITool(unittest.TestCase): """Test cases for CLI tool functions""" def setUp(self): """Set up test environment""" self.test_dir = tempfile.mkdtemp() self.data_dir = os.path.join(self.test_dir, 'data') os.makedirs(self.data_dir, exist_ok=True) def tearDown(self): """Clean up test environment""" shutil.rmtree(self.test_dir) @patch('requests.get') def test_api_request_get_success(self, mock_get): """Test successful GET request""" mock_response = MagicMock() mock_response.json.return_value = {'status': 'success'} mock_response.raise_for_status.return_value = None mock_get.return_value = mock_response result = api_request('GET', '/test') self.assertEqual(result, {'status': 'success'}) @patch('requests.get') def test_api_request_get_failure(self, mock_get): """Test failed GET request""" import requests mock_get.side_effect = requests.exceptions.RequestException("Connection error") result = api_request('GET', '/test') self.assertIsNone(result) @patch('requests.post') def test_api_request_post_success(self, mock_post): """Test successful POST request""" mock_response = MagicMock() mock_response.json.return_value = {'message': 'success'} mock_response.raise_for_status.return_value = None mock_post.return_value = mock_response result = api_request('POST', '/test', {'data': 'test'}) self.assertEqual(result, {'message': 'success'}) @patch('requests.put') def test_api_request_put_success(self, mock_put): """Test successful PUT request""" mock_response = MagicMock() mock_response.json.return_value = {'message': 'updated'} mock_response.raise_for_status.return_value = None mock_put.return_value = mock_response result = api_request('PUT', '/test', {'data': 'test'}) self.assertEqual(result, {'message': 'updated'}) @patch('requests.delete') def test_api_request_delete_success(self, mock_delete): """Test successful DELETE request""" mock_response = MagicMock() mock_response.json.return_value = {'message': 'deleted'} mock_response.raise_for_status.return_value = None mock_delete.return_value = mock_response result = api_request('DELETE', '/test') self.assertEqual(result, {'message': 'deleted'}) @patch("api.cell_cli.api_request") def test_show_status(self, mock_api_request): """Test show_status function""" mock_api_request.return_value = { 'cell_name': 'testcell', 'domain': 'testcell.cell', 'peers_count': 2, 'uptime': 3600, 'services': { 'dns': True, 'dhcp': True, 'ntp': False } } # Capture stdout captured_output = StringIO() sys.stdout = captured_output show_status() # Restore stdout sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('testcell', output) self.assertIn('2', output) self.assertIn('3600', output) @patch("api.cell_cli.api_request") def test_list_peers_empty(self, mock_api_request): """Test list_peers with empty list""" mock_api_request.return_value = [] captured_output = StringIO() sys.stdout = captured_output list_peers() sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('No peers configured', output) @patch("api.cell_cli.api_request") def test_list_peers_with_data(self, mock_api_request): """Test list_peers with peer data""" mock_api_request.return_value = [ { 'name': 'testpeer', 'ip': '192.168.1.100', 'public_key': 'testkey123456789', 'added_at': '2024-01-01T00:00:00' } ] captured_output = StringIO() sys.stdout = captured_output list_peers() sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('testpeer', output) self.assertIn('192.168.1.100', output) self.assertIn('testkey123456789', output) @patch("api.cell_cli.api_request") def test_add_peer_success(self, mock_api_request): """Test add_peer success""" mock_api_request.return_value = {'message': 'Peer added successfully'} captured_output = StringIO() sys.stdout = captured_output add_peer('testpeer', '192.168.1.100', 'testkey123') sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('✅', output) self.assertIn('successfully', output) @patch("api.cell_cli.api_request") def test_add_peer_failure(self, mock_api_request): """Test add_peer failure""" mock_api_request.return_value = None captured_output = StringIO() sys.stdout = captured_output add_peer('testpeer', '192.168.1.100', 'testkey123') sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('❌', output) self.assertIn('Failed', output) @patch("api.cell_cli.api_request") def test_remove_peer_success(self, mock_api_request): """Test remove_peer success""" mock_api_request.return_value = {'message': 'Peer removed successfully'} captured_output = StringIO() sys.stdout = captured_output remove_peer('testpeer') sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('✅', output) self.assertIn('successfully', output) @patch("api.cell_cli.api_request") def test_show_config(self, mock_api_request): """Test show_config function""" mock_api_request.return_value = { 'network': { 'dns_port': 53, 'dhcp_range': '192.168.1.100-200' }, 'wireguard': { 'port': 51820, 'address': '10.0.0.1/24' } } captured_output = StringIO() sys.stdout = captured_output show_config() sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('53', output) self.assertIn('51820', output) @patch("api.cell_cli.api_request") def test_update_config_success(self, mock_api_request): """Test update_config success""" mock_api_request.return_value = {'message': 'Configuration updated successfully'} captured_output = StringIO() sys.stdout = captured_output update_config('network', {'dns_port': 5353}) sys.stdout = sys.__stdout__ output = captured_output.getvalue() self.assertIn('✅', output) self.assertIn('successfully', output) class TestEnhancedCLI(unittest.TestCase): """Test the enhanced CLI functionality""" def setUp(self): self.temp_dir = tempfile.mkdtemp() self.config_file = os.path.join(self.temp_dir, 'cli_config.json') # Mock API client self.mock_api_client = MagicMock() self.mock_api_client.get.return_value = {'status': 'ok'} self.mock_api_client.post.return_value = {'success': True} def tearDown(self): shutil.rmtree(self.temp_dir) def test_api_client(self): """Test API client functionality""" with patch('enhanced_cli.requests.get') as mock_get, \ patch('enhanced_cli.requests.post') as mock_post: mock_get.return_value.json.return_value = {'status': 'ok'} mock_get.return_value.status_code = 200 mock_post.return_value.json.return_value = {'success': True} mock_post.return_value.status_code = 200 client = EnhancedCLI('http://localhost:5000') # Test GET request response = client.get('/api/status') self.assertEqual(response['status'], 'ok') # Test POST request response = client.post('/api/config', {'test': 'data'}) self.assertEqual(response['success'], True) def test_cli_config_manager(self): """Test CLI config manager""" config_manager = CLIConfigManager(self.config_file) # Test setting and getting config config_manager.set('api_url', 'http://localhost:5000') config_manager.set('timeout', 30) self.assertEqual(config_manager.get('api_url'), 'http://localhost:5000') self.assertEqual(config_manager.get('timeout'), 30) # Test default values self.assertEqual(config_manager.get('nonexistent', 'default'), 'default') # Test saving and loading config_manager.save() new_config_manager = CLIConfigManager(self.config_file) self.assertEqual(new_config_manager.get('api_url'), 'http://localhost:5000') def test_cli_commands(self): """Test CLI commands""" with patch('enhanced_cli.APIClient') as mock_client_class: mock_client = MagicMock() mock_client_class.return_value = mock_client # Mock API responses mock_client.get.return_value = { 'status': 'online', 'services': ['network', 'wireguard'] } mock_client.post.return_value = {'success': True} cli = EnhancedCLI('http://localhost:5000') # Test status command with patch('builtins.print') as mock_print: cli.show_status() mock_print.assert_called() # Test service commands with patch('builtins.print') as mock_print: cli.list_services() mock_print.assert_called() # Test configuration commands with patch('builtins.print') as mock_print: cli.show_config() mock_print.assert_called() def test_interactive_mode(self): """Test interactive mode""" with patch('enhanced_cli.APIClient') as mock_client_class: mock_client = MagicMock() mock_client_class.return_value = mock_client mock_client.get.return_value = {'status': 'ok'} cli = EnhancedCLI('http://localhost:5000') # Test interactive mode setup with patch('builtins.input', return_value='quit'), \ patch('builtins.print') as mock_print: cli.interactive_mode() mock_print.assert_called() def test_batch_operations(self): """Test batch operations""" with patch('enhanced_cli.APIClient') as mock_client_class: mock_client = MagicMock() mock_client_class.return_value = mock_client mock_client.post.return_value = {'success': True} cli = EnhancedCLI('http://localhost:5000') # Test batch service start services = ['network', 'wireguard'] with patch('builtins.print') as mock_print: cli.batch_start_services(services) mock_print.assert_called() # Test batch service stop with patch('builtins.print') as mock_print: cli.batch_stop_services(services) mock_print.assert_called() def test_service_wizards(self): """Test service wizards""" with patch('enhanced_cli.APIClient') as mock_client_class: mock_client = MagicMock() mock_client_class.return_value = mock_client mock_client.post.return_value = {'success': True} cli = EnhancedCLI('http://localhost:5000') # Test network setup wizard with patch('builtins.input', side_effect=['192.168.1.1', '255.255.255.0', '53']), \ patch('builtins.print') as mock_print: cli.network_setup_wizard() mock_print.assert_called() # Test WireGuard setup wizard with patch('builtins.input', side_effect=['51820', '10.0.0.1/24']), \ patch('builtins.print') as mock_print: cli.wireguard_setup_wizard() mock_print.assert_called() def test_error_handling(self): """Test error handling""" with patch('enhanced_cli.APIClient') as mock_client_class: mock_client = MagicMock() mock_client_class.return_value = mock_client mock_client.get.side_effect = Exception("Connection failed") cli = EnhancedCLI('http://localhost:5000') # Test error handling in status command with patch('builtins.print') as mock_print: cli.show_status() # Should handle the exception gracefully mock_print.assert_called() if __name__ == '__main__': unittest.main()