#!/usr/bin/env python3 """ Test script to verify the get_device_hostname function in TasmotaManager.py. This script tests: 1. Successful hostname retrieval 2. Empty hostname in response 3. Invalid JSON response 4. Non-200 status code 5. Network error (connection failure) 6. Timeout error """ import logging import unittest import requests from unittest.mock import patch, MagicMock # Configure logging logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) logger = logging.getLogger(__name__) # Import TasmotaManager class import sys import os sys.path.append(os.path.dirname(os.path.abspath(__file__))) from TasmotaManager import TasmotaDiscovery class TestGetDeviceHostname(unittest.TestCase): """Test cases for the get_device_hostname function.""" def setUp(self): """Set up test environment.""" self.discovery = TasmotaDiscovery(debug=True) # Create a minimal config to initialize the TasmotaDiscovery instance self.discovery.config = { 'unifi': { 'network_filter': {} } } @patch('requests.get') def test_successful_hostname_retrieval(self, mock_get): """Test successful hostname retrieval.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { 'StatusNET': { 'Hostname': 'test-device' } } mock_get.return_value = mock_response # Call the function hostname, success = self.discovery.get_device_hostname("192.168.1.100") # Verify results self.assertEqual(hostname, 'test-device') self.assertTrue(success) # Verify that requests.get was called with the correct URL and timeout mock_get.assert_called_once_with("http://192.168.1.100/cm?cmnd=Status%205", timeout=5) logger.info("Test for successful hostname retrieval passed") @patch('requests.get') def test_empty_hostname_in_response(self, mock_get): """Test empty hostname in response.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { 'StatusNET': { 'Hostname': '' } } mock_get.return_value = mock_response # Call the function hostname, success = self.discovery.get_device_hostname("192.168.1.100") # Verify results self.assertEqual(hostname, '') self.assertFalse(success) logger.info("Test for empty hostname in response passed") @patch('requests.get') def test_missing_hostname_in_response(self, mock_get): """Test missing hostname in response.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { 'StatusNET': {} # No Hostname key } mock_get.return_value = mock_response # Call the function hostname, success = self.discovery.get_device_hostname("192.168.1.100") # Verify results self.assertEqual(hostname, '') self.assertFalse(success) logger.info("Test for missing hostname in response passed") @patch('requests.get') def test_invalid_json_response(self, mock_get): """Test invalid JSON response.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.side_effect = ValueError("Invalid JSON") mock_get.return_value = mock_response # Call the function hostname, success = self.discovery.get_device_hostname("192.168.1.100") # Verify results self.assertEqual(hostname, '') self.assertFalse(success) logger.info("Test for invalid JSON response passed") @patch('requests.get') def test_non_200_status_code(self, mock_get): """Test non-200 status code.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 404 mock_get.return_value = mock_response # Call the function hostname, success = self.discovery.get_device_hostname("192.168.1.100") # Verify results self.assertEqual(hostname, '') self.assertFalse(success) logger.info("Test for non-200 status code passed") @patch('requests.get') def test_connection_error(self, mock_get): """Test connection error.""" # Mock requests.get to raise a connection error mock_get.side_effect = requests.exceptions.ConnectionError("Connection refused") # Call the function hostname, success = self.discovery.get_device_hostname("192.168.1.100") # Verify results self.assertEqual(hostname, '') self.assertFalse(success) logger.info("Test for connection error passed") @patch('requests.get') def test_timeout_error(self, mock_get): """Test timeout error.""" # Mock requests.get to raise a timeout error mock_get.side_effect = requests.exceptions.Timeout("Request timed out") # Call the function hostname, success = self.discovery.get_device_hostname("192.168.1.100") # Verify results self.assertEqual(hostname, '') self.assertFalse(success) logger.info("Test for timeout error passed") @patch('requests.get') def test_custom_timeout(self, mock_get): """Test custom timeout parameter.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { 'StatusNET': { 'Hostname': 'test-device' } } mock_get.return_value = mock_response # Call the function with custom timeout hostname, success = self.discovery.get_device_hostname("192.168.1.100", timeout=10) # Verify results self.assertEqual(hostname, 'test-device') self.assertTrue(success) # Verify that requests.get was called with the custom timeout mock_get.assert_called_once_with("http://192.168.1.100/cm?cmnd=Status%205", timeout=10) logger.info("Test for custom timeout passed") @patch('requests.get') def test_with_device_name(self, mock_get): """Test with device_name parameter.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { 'StatusNET': { 'Hostname': 'test-device' } } mock_get.return_value = mock_response # Call the function with device_name hostname, success = self.discovery.get_device_hostname("192.168.1.100", device_name="Living Room Light") # Verify results self.assertEqual(hostname, 'test-device') self.assertTrue(success) logger.info("Test with device_name parameter passed") @patch('requests.get') def test_with_log_level(self, mock_get): """Test with log_level parameter.""" # Mock response for Status 5 command mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = { 'StatusNET': { 'Hostname': 'test-device' } } mock_get.return_value = mock_response # Call the function with log_level hostname, success = self.discovery.get_device_hostname("192.168.1.100", log_level="info") # Verify results self.assertEqual(hostname, 'test-device') self.assertTrue(success) logger.info("Test with log_level parameter passed") def main(): """Run the tests.""" unittest.main() if __name__ == "__main__": main()