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
238 lines
8.7 KiB
Python
238 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test script to verify the template matching algorithm in TasmotaManager.py.
|
|
|
|
This script simulates different scenarios to ensure the algorithm works correctly:
|
|
1. Key matches Device Name, Template matches value
|
|
2. Key matches Device Name, Template doesn't match value
|
|
3. No key matches Device Name, but a value matches Template
|
|
4. No matches at all
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
import requests
|
|
import unittest
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
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 TestTemplateMatching(unittest.TestCase):
|
|
"""Test cases for template matching algorithm."""
|
|
|
|
def setUp(self):
|
|
"""Set up test environment."""
|
|
self.discovery = TasmotaDiscovery(debug=True)
|
|
|
|
# Create a mock config with config_other at top level
|
|
self.discovery.config = {
|
|
'mqtt': {},
|
|
'config_other': {
|
|
'TreatLife_SW_SS01S': '{"NAME":"TL SS01S Swtch","GPIO":[0,0,0,0,52,158,0,0,21,17,0,0,0],"FLAG":0,"BASE":18}',
|
|
'TreatLife_SW_SS02S': '{"NAME":"Treatlife SS02","GPIO":[0,0,0,0,288,576,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}'
|
|
}
|
|
}
|
|
|
|
@patch('requests.get')
|
|
def test_key_matches_template_matches(self, mock_get):
|
|
"""Test when key matches Device Name and template matches value."""
|
|
# Mock responses for Status 0 and Template commands
|
|
mock_responses = [
|
|
# Status 0 response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Status": {"DeviceName": "TreatLife_SW_SS01S"}}
|
|
),
|
|
# Template response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Template": '{"NAME":"TL SS01S Swtch","GPIO":[0,0,0,0,52,158,0,0,21,17,0,0,0],"FLAG":0,"BASE":18}'}
|
|
)
|
|
]
|
|
mock_get.side_effect = mock_responses
|
|
|
|
# Call the method
|
|
result = self.discovery.check_and_update_template("192.168.8.100", "test_device")
|
|
|
|
# Verify results
|
|
self.assertFalse(result) # No update needed
|
|
self.assertEqual(mock_get.call_count, 2) # Only Status 0 and Template calls
|
|
|
|
# Log the result
|
|
logger.info("Test 1: Key matches Device Name, Template matches value - PASSED")
|
|
|
|
@patch('requests.get')
|
|
def test_key_matches_template_doesnt_match(self, mock_get):
|
|
"""Test when key matches Device Name but template doesn't match value."""
|
|
# Mock responses for Status 0, Template, and Template update commands
|
|
mock_responses = [
|
|
# Status 0 response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Status": {"DeviceName": "TreatLife_SW_SS01S"}}
|
|
),
|
|
# Template response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Template": '{"NAME":"Different Template","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}'}
|
|
),
|
|
# Template update response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Template": "Done"}
|
|
)
|
|
]
|
|
mock_get.side_effect = mock_responses
|
|
|
|
# Call the method
|
|
result = self.discovery.check_and_update_template("192.168.8.100", "test_device")
|
|
|
|
# Verify results
|
|
self.assertTrue(result) # Template was updated
|
|
self.assertEqual(mock_get.call_count, 3) # Status 0, Template, and Template update calls
|
|
|
|
# Log the result
|
|
logger.info("Test 2: Key matches Device Name, Template doesn't match value - PASSED")
|
|
|
|
@patch('requests.get')
|
|
def test_no_key_matches_value_matches(self, mock_get):
|
|
"""Test when no key matches Device Name but a value matches Template."""
|
|
# Mock responses for Status 0, Template, and DeviceName update commands
|
|
mock_responses = [
|
|
# Status 0 response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Status": {"DeviceName": "Unknown_Device"}}
|
|
),
|
|
# Template response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Template": '{"NAME":"Treatlife SS02","GPIO":[0,0,0,0,288,576,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}'}
|
|
),
|
|
# DeviceName update response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"DeviceName": "Done"}
|
|
)
|
|
]
|
|
mock_get.side_effect = mock_responses
|
|
|
|
# Call the method
|
|
result = self.discovery.check_and_update_template("192.168.8.100", "test_device")
|
|
|
|
# Verify results
|
|
self.assertTrue(result) # Device name was updated
|
|
self.assertEqual(mock_get.call_count, 3) # Status 0, Template, and DeviceName update calls
|
|
|
|
# Log the result
|
|
logger.info("Test 3: No key matches Device Name, but a value matches Template - PASSED")
|
|
|
|
@patch('requests.get')
|
|
def test_no_matches_at_all(self, mock_get):
|
|
"""Test when there are no matches at all."""
|
|
# Mock responses for Status 0 and Template commands
|
|
mock_responses = [
|
|
# Status 0 response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Status": {"DeviceName": "Unknown_Device"}}
|
|
),
|
|
# Template response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Template": '{"NAME":"Unknown Template","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}'}
|
|
)
|
|
]
|
|
mock_get.side_effect = mock_responses
|
|
|
|
# Call the method
|
|
result = self.discovery.check_and_update_template("192.168.8.100", "test_device")
|
|
|
|
# Verify results
|
|
self.assertFalse(result) # No updates made
|
|
self.assertEqual(mock_get.call_count, 2) # Only Status 0 and Template calls
|
|
|
|
# Log the result
|
|
logger.info("Test 4: No matches at all - PASSED")
|
|
|
|
@patch('requests.get')
|
|
def test_no_config_other(self, mock_get):
|
|
"""Test when there's no config_other in the configuration."""
|
|
# Set empty config without config_other
|
|
self.discovery.config = {'mqtt': {}}
|
|
|
|
# Call the method
|
|
result = self.discovery.check_and_update_template("192.168.8.100", "test_device")
|
|
|
|
# Verify results
|
|
self.assertFalse(result) # No updates made
|
|
self.assertEqual(mock_get.call_count, 0) # No HTTP calls made
|
|
|
|
# Log the result
|
|
logger.info("Test 5: No config_other in configuration - PASSED")
|
|
|
|
@patch('requests.get')
|
|
def test_status0_failure(self, mock_get):
|
|
"""Test when Status 0 command fails."""
|
|
# Mock response for Status 0 command
|
|
mock_get.return_value = MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Status": {}} # Missing DeviceName
|
|
)
|
|
|
|
# Call the method
|
|
result = self.discovery.check_and_update_template("192.168.8.100", "test_device")
|
|
|
|
# Verify results
|
|
self.assertFalse(result) # No updates made
|
|
self.assertEqual(mock_get.call_count, 1) # Only Status 0 call
|
|
|
|
# Log the result
|
|
logger.info("Test 6: Status 0 command failure - PASSED")
|
|
|
|
@patch('requests.get')
|
|
def test_template_failure(self, mock_get):
|
|
"""Test when Template command fails."""
|
|
# Mock responses for Status 0 and Template commands
|
|
mock_responses = [
|
|
# Status 0 response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {"Status": {"DeviceName": "TreatLife_SW_SS01S"}}
|
|
),
|
|
# Template response
|
|
MagicMock(
|
|
status_code=200,
|
|
json=lambda: {} # Missing Template
|
|
)
|
|
]
|
|
mock_get.side_effect = mock_responses
|
|
|
|
# Call the method
|
|
result = self.discovery.check_and_update_template("192.168.8.100", "test_device")
|
|
|
|
# Verify results
|
|
self.assertFalse(result) # No updates made
|
|
self.assertEqual(mock_get.call_count, 2) # Status 0 and Template calls
|
|
|
|
# Log the result
|
|
logger.info("Test 7: Template command failure - PASSED")
|
|
|
|
def main():
|
|
"""Run the tests."""
|
|
unittest.main()
|
|
|
|
if __name__ == "__main__":
|
|
main() |