Team Ai
Apppublic

diegobeyl/backtesting

sourceHugging Faceupdated 9mo agoView on Hugging Face
2likes
test_config_manager.py110 linesDownload Raw Back to tests
1"""Tests for Configuration Manager"""
2import pytest
3import sys
4import json
5import tempfile
6import os
7from pathlib import Path
8from unittest.mock import MagicMock
9import threading
10
11sys.path.insert(0, str(Path(__file__).parent.parent))
12
13from api.config_manager import ConfigManager, ConfigFileHandler, get_config_manager
14from api.schemas import BacktestConfig, Timeframe
15
16
17class TestConfigManager:
18    """Tests for ConfigManager class"""
19    
20    @pytest.fixture
21    def temp_config_file(self):
22        """Create a temporary config file"""
23        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
24            json.dump({"symbol": "BTCUSD", "timeframe": "D1", "donchian_period": 1}, f)
25            temp_path = f.name
26        yield temp_path
27        if os.path.exists(temp_path):
28            os.remove(temp_path)
29    
30    def test_init_with_existing_file(self, temp_config_file):
31        """Test initialization with existing config file"""
32        manager = ConfigManager(config_path=temp_config_file)
33        config = manager.get_config()
34        assert config.symbol == "BTCUSD"
35    
36    def test_update_config(self, temp_config_file):
37        """Test updating configuration"""
38        manager = ConfigManager(config_path=temp_config_file)
39        new_config = BacktestConfig(symbol="ETHUSD", timeframe="W1")
40        manager.update_config(new_config)
41        assert manager.get_config().symbol == "ETHUSD"
42    
43    def test_update_partial(self, temp_config_file):
44        """Test partial configuration update"""
45        manager = ConfigManager(config_path=temp_config_file)
46        manager.update_partial({"risk_percent": 2.5, "leverage": 50})
47        config = manager.get_config()
48        assert config.risk_percent == 2.5
49        assert config.leverage == 50
50    
51    def test_reset_to_defaults(self, temp_config_file):
52        """Test resetting to defaults"""
53        manager = ConfigManager(config_path=temp_config_file)
54        manager.update_partial({"symbol": "ETHUSD", "donchian_period": 10})
55        manager.reset_to_defaults()
56        config = manager.get_config()
57        assert config.symbol == "BTCUSD"
58        assert config.donchian_period == 1
59    
60    def test_listener_notification(self, temp_config_file):
61        """Test listener notifications"""
62        manager = ConfigManager(config_path=temp_config_file)
63        callback_called = []
64        manager.add_listener(lambda c: callback_called.append(c))
65        manager.update_partial({"risk_percent": 3.0})
66        assert len(callback_called) == 1
67    
68    def test_thread_safety(self, temp_config_file):
69        """Test thread safety"""
70        manager = ConfigManager(config_path=temp_config_file)
71        errors = []
72        def worker(val):
73            try:
74                for _ in range(10):
75                    manager.update_partial({"risk_percent": val})
76                    manager.get_config()
77            except Exception as e:
78                errors.append(e)
79        # Use valid risk_percent values (min 0.1)
80        threads = [threading.Thread(target=worker, args=(i+0.5,)) for i in range(3)]
81        for t in threads: t.start()
82        for t in threads: t.join()
83        assert len(errors) == 0
84
85
86class TestConfigFileHandler:
87    """Tests for ConfigFileHandler"""
88    
89    def test_on_modified_debounce(self):
90        """Test debounce of rapid changes"""
91        mock_manager = MagicMock()
92        handler = ConfigFileHandler(mock_manager)
93        from watchdog.events import FileModifiedEvent
94        event = FileModifiedEvent(src_path="/path/config.json")
95        handler.on_modified(event)
96        handler.on_modified(event)  # Should be debounced
97        assert mock_manager.reload_config.call_count == 1
98    
99    def test_ignores_non_json(self):
100        """Test non-JSON files are ignored"""
101        mock_manager = MagicMock()
102        handler = ConfigFileHandler(mock_manager)
103        from watchdog.events import FileModifiedEvent
104        handler.on_modified(FileModifiedEvent(src_path="/path/file.txt"))
105        mock_manager.reload_config.assert_not_called()
106
107
108if __name__ == "__main__":
109    pytest.main([__file__, "-v"])
110