From e9ebb338b48d4b641828c0daba02a0df8725a502 Mon Sep 17 00:00:00 2001 From: sh4un <97253929+sh4un-dot-com@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:20:30 -0500 Subject: [PATCH] Update CHANGELOG, enhance configuration loading with default values, and add tests for missing defaults --- CHANGELOG.md | 16 ++++++++-------- ammb/config_handler.py | 18 ++++++++---------- tests/test_config_handler_missing_default.py | 14 ++++++++++++++ tmp_no_default.ini | 2 ++ tmp_run_load.py | 6 ++++++ tmp_test_config.py | 7 +++++++ 6 files changed, 45 insertions(+), 18 deletions(-) create mode 100644 tests/test_config_handler_missing_default.py create mode 100644 tmp_no_default.ini create mode 100644 tmp_run_load.py create mode 100644 tmp_test_config.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 2083dae..a263096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,11 @@ ## Version 2.0.0 - Comprehensive Code Review and Enhancements (December 31, 2025) -### ๐Ÿ› Bug Fixes +### Bug Fixes - **Fixed test file errors**: Corrected incomplete string in `test_config_handler.py` and wrong function name in `test_protocol.py` - **Fixed missing method**: Added `_on_log` method to `MQTTHandler` that was referenced but not defined -### โœจ New Features +### New Features #### 1. Metrics and Statistics Collection - **New Module**: `ammb/metrics.py` @@ -70,7 +70,7 @@ - Configurable insecure mode (for testing) - Automatic TLS context creation -### ๐Ÿ”ง Enhancements +### Enhancements #### Configuration System - Added API configuration options: @@ -111,32 +111,32 @@ - Enhanced shutdown sequence - Better error handling and logging -### ๐Ÿ“Š Performance Optimizations +### Performance Optimizations - Thread-safe metrics collection - Non-blocking message logging - Efficient rate limiting algorithm - Optimized health check intervals - Reduced lock contention -### ๐Ÿ›ก๏ธ Security Enhancements +### Security Enhancements - Message validation prevents malformed data - Rate limiting prevents message flooding - TLS/SSL support for secure MQTT - Input sanitization prevents injection attacks - Node ID validation prevents spoofing -### ๐Ÿ“ Documentation +### Documentation - Updated README.md with new features - Enhanced configuration examples - Added API endpoint documentation - Improved code comments and docstrings -### ๐Ÿงช Testing +### Testing - Fixed broken test files - All modules compile successfully - No linter errors -### ๐Ÿ”„ Backward Compatibility +### Backward Compatibility - All new features are optional and configurable - Default behavior maintains backward compatibility - Existing configurations continue to work diff --git a/ammb/config_handler.py b/ammb/config_handler.py index fa2bdcd..eb6fc9f 100644 --- a/ammb/config_handler.py +++ b/ammb/config_handler.py @@ -100,14 +100,12 @@ def load_config(config_path: str = CONFIG_FILE) -> Optional[BridgeConfig]: if 'DEFAULT' not in config.sections(): logger.warning(f"Configuration file '{config_path}' lacks the [DEFAULT] section. Using only defaults.") - cfg_section = config.defaults() - else: - cfg_section = config['DEFAULT'] + cfg_section = config['DEFAULT'] - meshtastic_port = cfg_section.get('MESHTASTIC_SERIAL_PORT') - external_network_id = cfg_section.get('EXTERNAL_NETWORK_ID') - bridge_node_id = cfg_section.get('BRIDGE_NODE_ID') - log_level = cfg_section.get('LOG_LEVEL').upper() + meshtastic_port = cfg_section.get('MESHTASTIC_SERIAL_PORT', fallback=DEFAULT_CONFIG['MESHTASTIC_SERIAL_PORT']) + external_network_id = cfg_section.get('EXTERNAL_NETWORK_ID', fallback=DEFAULT_CONFIG['EXTERNAL_NETWORK_ID']) + bridge_node_id = cfg_section.get('BRIDGE_NODE_ID', fallback=DEFAULT_CONFIG['BRIDGE_NODE_ID']) + log_level = cfg_section.get('LOG_LEVEL', fallback=DEFAULT_CONFIG['LOG_LEVEL']).upper() if log_level not in VALID_LOG_LEVELS: logger.error(f"Invalid LOG_LEVEL '{log_level}'. Must be one of: {VALID_LOG_LEVELS}") @@ -121,7 +119,7 @@ def load_config(config_path: str = CONFIG_FILE) -> Optional[BridgeConfig]: logger.error(f"Invalid integer value for MESSAGE_QUEUE_SIZE: {e}") return None - external_transport = cfg_section.get('EXTERNAL_TRANSPORT').lower() + external_transport = cfg_section.get('EXTERNAL_TRANSPORT', fallback=DEFAULT_CONFIG['EXTERNAL_TRANSPORT']).lower() if external_transport not in VALID_TRANSPORTS: logger.error(f"Invalid EXTERNAL_TRANSPORT '{external_transport}'. Must be one of: {VALID_TRANSPORTS}") return None @@ -140,8 +138,8 @@ def load_config(config_path: str = CONFIG_FILE) -> Optional[BridgeConfig]: mqtt_retain_out = None if external_transport == 'serial': - serial_port = cfg_section.get('SERIAL_PORT') - serial_protocol = cfg_section.get('SERIAL_PROTOCOL').lower() + serial_port = cfg_section.get('SERIAL_PORT', fallback=DEFAULT_CONFIG['SERIAL_PORT']) + serial_protocol = cfg_section.get('SERIAL_PROTOCOL', fallback=DEFAULT_CONFIG['SERIAL_PROTOCOL']).lower() if not serial_port: logger.error("SERIAL_PORT must be set when EXTERNAL_TRANSPORT is 'serial'.") return None diff --git a/tests/test_config_handler_missing_default.py b/tests/test_config_handler_missing_default.py new file mode 100644 index 0000000..e2e733a --- /dev/null +++ b/tests/test_config_handler_missing_default.py @@ -0,0 +1,14 @@ +import importlib.util + + +def test_load_config_missing_default(tmp_path): + cfgfile = tmp_path / "no_default.ini" + cfgfile.write_text("[serial]\nSERIAL_PORT=/dev/ttyS1\n") + + spec = importlib.util.spec_from_file_location('config_handler', 'ammb/config_handler.py') + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + + cfg = mod.load_config(str(cfgfile)) + assert cfg is not None + assert cfg.log_level == 'INFO' diff --git a/tmp_no_default.ini b/tmp_no_default.ini new file mode 100644 index 0000000..57cbcb9 --- /dev/null +++ b/tmp_no_default.ini @@ -0,0 +1,2 @@ +[serial] +SERIAL_PORT = /dev/ttyS1 diff --git a/tmp_run_load.py b/tmp_run_load.py new file mode 100644 index 0000000..9f10bc4 --- /dev/null +++ b/tmp_run_load.py @@ -0,0 +1,6 @@ +import importlib.util +spec = importlib.util.spec_from_file_location('config_handler', 'ammb/config_handler.py') +mod = importlib.util.module_from_spec(spec) +spec.loader.exec_module(mod) +print('Using file: tmp_no_default.ini') +print(mod.load_config('tmp_no_default.ini')) diff --git a/tmp_test_config.py b/tmp_test_config.py new file mode 100644 index 0000000..d3c23e9 --- /dev/null +++ b/tmp_test_config.py @@ -0,0 +1,7 @@ +from ammb import config_handler +path='tmp_no_default.ini' +with open(path,'w') as f: + f.write('[serial]\nSERIAL_PORT=/dev/ttyS1\n') +print('Using file:', path) +cfg = config_handler.load_config(path) +print('Result:', cfg)