237 lines
9.6 KiB
Python
237 lines
9.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test script to verify the Unifi Hostname bug fix in the is_hostname_unknown function.
|
|
|
|
This script tests:
|
|
1. A device affected by the Unifi Hostname bug (UniFi-reported hostname matches unknown patterns,
|
|
but self-reported hostname doesn't)
|
|
2. A device not affected by the bug (both hostnames match or don't match unknown patterns)
|
|
3. Various combinations of parameters (with/without from_unifi_os, with/without IP)
|
|
"""
|
|
|
|
import logging
|
|
import unittest
|
|
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 TestUnifiHostnameBugFix(unittest.TestCase):
|
|
"""Test cases for the Unifi Hostname bug fix."""
|
|
|
|
def setUp(self):
|
|
"""Set up test environment."""
|
|
self.discovery = TasmotaDiscovery(debug=True)
|
|
|
|
# Create a mock config
|
|
self.discovery.config = {
|
|
'unifi': {
|
|
'network_filter': {
|
|
'test_network': {
|
|
'unknown_device_patterns': [
|
|
"^tasmota_*",
|
|
"^tasmota-*",
|
|
"^esp-*",
|
|
"^ESP-*"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Define test patterns
|
|
self.test_patterns = [
|
|
"^tasmota_*",
|
|
"^tasmota-*",
|
|
"^esp-*",
|
|
"^ESP-*"
|
|
]
|
|
|
|
@patch('requests.get')
|
|
def test_bug_affected_device(self, mock_get):
|
|
"""Test a device affected by the Unifi Hostname bug."""
|
|
# Mock response for Status 5 command
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
'StatusNET': {
|
|
'Hostname': 'my_proper_device' # Self-reported hostname doesn't match unknown patterns
|
|
}
|
|
}
|
|
mock_get.return_value = mock_response
|
|
|
|
# Test with a hostname that matches unknown patterns (as reported by UniFi)
|
|
# but with a self-reported hostname that doesn't match unknown patterns
|
|
result = self.discovery.is_hostname_unknown(
|
|
hostname="tasmota_123", # UniFi-reported hostname (matches unknown patterns)
|
|
patterns=self.test_patterns,
|
|
from_unifi_os=True, # Enable Unifi Hostname bug handling
|
|
ip="192.168.1.100" # Provide IP to query the device
|
|
)
|
|
|
|
# The function should return False because the self-reported hostname doesn't match unknown patterns
|
|
self.assertFalse(result)
|
|
|
|
# Verify that requests.get was called with the correct URL
|
|
mock_get.assert_called_once_with("http://192.168.1.100/cm?cmnd=Status%205", timeout=5)
|
|
|
|
logger.info("Test for bug-affected device passed")
|
|
|
|
@patch('requests.get')
|
|
def test_non_bug_affected_device_both_match(self, mock_get):
|
|
"""Test a device not affected by the bug (both hostnames match unknown patterns)."""
|
|
# Mock response for Status 5 command
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
'StatusNET': {
|
|
'Hostname': 'tasmota_456' # Self-reported hostname matches unknown patterns
|
|
}
|
|
}
|
|
mock_get.return_value = mock_response
|
|
|
|
# Test with a hostname that matches unknown patterns (as reported by UniFi)
|
|
# and with a self-reported hostname that also matches unknown patterns
|
|
result = self.discovery.is_hostname_unknown(
|
|
hostname="tasmota_123", # UniFi-reported hostname (matches unknown patterns)
|
|
patterns=self.test_patterns,
|
|
from_unifi_os=True, # Enable Unifi Hostname bug handling
|
|
ip="192.168.1.100" # Provide IP to query the device
|
|
)
|
|
|
|
# The function should return True because both hostnames match unknown patterns
|
|
self.assertTrue(result)
|
|
|
|
# Verify that requests.get was called with the correct URL
|
|
mock_get.assert_called_once_with("http://192.168.1.100/cm?cmnd=Status%205", timeout=5)
|
|
|
|
logger.info("Test for non-bug-affected device (both match) passed")
|
|
|
|
@patch('requests.get')
|
|
def test_non_bug_affected_device_both_dont_match(self, mock_get):
|
|
"""Test a device not affected by the bug (both hostnames don't match unknown patterns)."""
|
|
# Mock response for Status 5 command
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
'StatusNET': {
|
|
'Hostname': 'my_proper_device' # Self-reported hostname doesn't match unknown patterns
|
|
}
|
|
}
|
|
mock_get.return_value = mock_response
|
|
|
|
# Test with a hostname that doesn't match unknown patterns (as reported by UniFi)
|
|
# and with a self-reported hostname that also doesn't match unknown patterns
|
|
result = self.discovery.is_hostname_unknown(
|
|
hostname="my_device", # UniFi-reported hostname (doesn't match unknown patterns)
|
|
patterns=self.test_patterns,
|
|
from_unifi_os=True, # Enable Unifi Hostname bug handling
|
|
ip="192.168.1.100" # Provide IP to query the device
|
|
)
|
|
|
|
# The function should return False because neither hostname matches unknown patterns
|
|
self.assertFalse(result)
|
|
|
|
# Verify that requests.get was called with the correct URL
|
|
mock_get.assert_called_once_with("http://192.168.1.100/cm?cmnd=Status%205", timeout=5)
|
|
|
|
logger.info("Test for non-bug-affected device (both don't match) passed")
|
|
|
|
def test_without_from_unifi_os(self):
|
|
"""Test without the from_unifi_os parameter."""
|
|
# Test with a hostname that matches unknown patterns
|
|
result = self.discovery.is_hostname_unknown(
|
|
hostname="tasmota_123", # Matches unknown patterns
|
|
patterns=self.test_patterns,
|
|
from_unifi_os=False, # Disable Unifi Hostname bug handling
|
|
ip="192.168.1.100" # Provide IP (should be ignored since from_unifi_os is False)
|
|
)
|
|
|
|
# The function should return True because the hostname matches unknown patterns
|
|
# and from_unifi_os is False, so no bug handling is performed
|
|
self.assertTrue(result)
|
|
|
|
logger.info("Test without from_unifi_os passed")
|
|
|
|
def test_without_ip(self):
|
|
"""Test without the IP parameter."""
|
|
# Test with a hostname that matches unknown patterns
|
|
result = self.discovery.is_hostname_unknown(
|
|
hostname="tasmota_123", # Matches unknown patterns
|
|
patterns=self.test_patterns,
|
|
from_unifi_os=True, # Enable Unifi Hostname bug handling
|
|
ip=None # No IP provided, so can't query the device
|
|
)
|
|
|
|
# The function should return True because the hostname matches unknown patterns
|
|
# and no IP is provided, so no bug handling is performed
|
|
self.assertTrue(result)
|
|
|
|
logger.info("Test without IP passed")
|
|
|
|
@patch('requests.get')
|
|
def test_request_exception(self, mock_get):
|
|
"""Test handling of request exceptions."""
|
|
# Mock requests.get to raise an exception
|
|
mock_get.side_effect = Exception("Test exception")
|
|
|
|
# Test with a hostname that matches unknown patterns
|
|
result = self.discovery.is_hostname_unknown(
|
|
hostname="tasmota_123", # Matches unknown patterns
|
|
patterns=self.test_patterns,
|
|
from_unifi_os=True, # Enable Unifi Hostname bug handling
|
|
ip="192.168.1.100" # Provide IP to query the device
|
|
)
|
|
|
|
# The function should return True because the hostname matches unknown patterns
|
|
# and the request failed, so no bug handling is performed
|
|
self.assertTrue(result)
|
|
|
|
# Verify that requests.get was called with the correct URL
|
|
mock_get.assert_called_once_with("http://192.168.1.100/cm?cmnd=Status%205", timeout=5)
|
|
|
|
logger.info("Test for request exception passed")
|
|
|
|
@patch('requests.get')
|
|
def test_invalid_json_response(self, mock_get):
|
|
"""Test handling of invalid JSON responses."""
|
|
# 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
|
|
|
|
# Test with a hostname that matches unknown patterns
|
|
result = self.discovery.is_hostname_unknown(
|
|
hostname="tasmota_123", # Matches unknown patterns
|
|
patterns=self.test_patterns,
|
|
from_unifi_os=True, # Enable Unifi Hostname bug handling
|
|
ip="192.168.1.100" # Provide IP to query the device
|
|
)
|
|
|
|
# The function should return True because the hostname matches unknown patterns
|
|
# and the JSON parsing failed, so no bug handling is performed
|
|
self.assertTrue(result)
|
|
|
|
# Verify that requests.get was called with the correct URL
|
|
mock_get.assert_called_once_with("http://192.168.1.100/cm?cmnd=Status%205", timeout=5)
|
|
|
|
logger.info("Test for invalid JSON response passed")
|
|
|
|
def main():
|
|
"""Run the tests."""
|
|
unittest.main()
|
|
|
|
if __name__ == "__main__":
|
|
main() |