1. Restructured configuration: Moved config_other and console to top level 2. Added common _match_pattern function for regex pattern matching 3. Implemented Unifi Hostname bug fix in is_hostname_unknown 4. Created common get_device_hostname function to eliminate code duplication 5. Added comprehensive test scripts for all new functionality 6. Added detailed documentation for all changes
253 lines
8.2 KiB
Python
253 lines
8.2 KiB
Python
#!/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() |