-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_evolution_api.py
More file actions
194 lines (150 loc) · 7.43 KB
/
Copy pathtest_evolution_api.py
File metadata and controls
194 lines (150 loc) · 7.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
"""Tests for evolution integration in API server."""
import pytest
from unittest.mock import Mock, patch
from memevolve.api.evolution_manager import EvolutionManager, EvolutionMetrics
from memevolve.utils.config import MemEvolveConfig, ConfigManager
class TestEvolutionManager:
"""Test EvolutionManager functionality."""
@pytest.fixture
def mock_memory_system(self):
"""Create a mock memory system."""
return Mock()
@pytest.fixture
def config(self):
"""Create a test config with evolution enabled."""
config = MemEvolveConfig()
config.evolution.enable = True
config.evolution.population_size = 5
config.evolution.generations = 2
return config
@pytest.fixture
def config_manager(self, config):
"""Create a test config manager."""
cm = ConfigManager()
cm.config = config
return cm
def test_evolution_manager_creation(self, config, config_manager, mock_memory_system, tmp_path):
"""Test EvolutionManager can be created."""
# Use temporary directory to avoid loading existing state
config.cache_dir = str(tmp_path)
config.data_dir = str(tmp_path)
manager = EvolutionManager(config, mock_memory_system, config_manager)
assert manager.config == config
assert manager.memory_system == mock_memory_system
assert manager.is_running == False
assert len(manager.population) == 0
def test_start_stop_evolution(self, config, config_manager, mock_memory_system, tmp_path):
"""Test starting and stopping evolution."""
# Use temporary directory to avoid loading existing state
config.cache_dir = str(tmp_path)
config.data_dir = str(tmp_path)
manager = EvolutionManager(config, mock_memory_system, config_manager)
# Start evolution with auto_trigger to bypass trigger checks
assert manager.start_evolution(auto_trigger=True) == True
assert manager.is_running == True
# Try to start again (should fail)
assert manager.start_evolution(auto_trigger=True) == False
# Stop evolution
assert manager.stop_evolution() == True
assert manager.is_running == False
# Try to stop again (should fail)
assert manager.stop_evolution() == False
def test_record_api_request(self, config, config_manager, mock_memory_system, tmp_path):
"""Test recording API requests."""
# Use temporary directory to avoid loading existing state
config.cache_dir = str(tmp_path)
config.data_dir = str(tmp_path)
manager = EvolutionManager(config, mock_memory_system, config_manager)
# Record some requests
manager.record_api_request(0.5, True)
manager.record_api_request(1.0, False)
manager.record_api_request(0.8, True)
metrics = manager.metrics
assert metrics.api_requests_total == 3
assert metrics.api_requests_successful == 2
assert abs(metrics.average_response_time -
0.766) < 0.01 # (0.5 + 1.0 + 0.8) / 3
def test_record_memory_retrieval(self, config, config_manager, mock_memory_system, tmp_path):
"""Test recording memory retrievals."""
# Use temporary directory to avoid loading existing state
config.cache_dir = str(tmp_path)
config.data_dir = str(tmp_path)
manager = EvolutionManager(config, mock_memory_system, config_manager)
# Record some retrievals
manager.record_memory_retrieval(0.1, True)
manager.record_memory_retrieval(0.2, False)
manager.record_memory_retrieval(0.15, True)
metrics = manager.metrics
assert metrics.memory_retrievals_total == 3
assert metrics.memory_retrievals_successful == 2
assert abs(metrics.average_retrieval_time - 0.15) < 0.01
def test_get_status(self, config, config_manager, mock_memory_system, tmp_path):
"""Test getting evolution status."""
# Use temporary directory to avoid loading existing state
config.cache_dir = str(tmp_path)
config.data_dir = str(tmp_path)
manager = EvolutionManager(config, mock_memory_system, config_manager)
status = manager.get_status()
assert status["is_running"] == False
assert status["population_size"] == 0
assert status["evolution_cycles_completed"] == 0
assert status["api_requests_total"] == 0
@patch('time.sleep') # Prevent actual sleeping in tests
def test_evolution_loop_basic(self, mock_sleep, config, config_manager, mock_memory_system):
"""Test basic evolution loop functionality."""
# Reduce population size and generations for faster testing
config.evolution.population_size = 3
config.evolution.generations = 1
manager = EvolutionManager(config, mock_memory_system, config_manager)
# Initialize population
manager._initialize_population()
assert len(manager.population) == 3
# Test evaluation (mock fitness scores using actual genome IDs)
fitness_scores = {}
for genotype in manager.population:
genome_id = genotype.get_genome_id()
fitness_scores[genome_id] = 0.8 if len(
fitness_scores) == 0 else 0.6 # Simple scoring
selected = manager._select_best_genotypes(fitness_scores)
assert len(selected) <= len(manager.population)
# Test crossover
parent1 = manager.population[0]
parent2 = manager.population[1]
child = manager._crossover(parent1, parent2)
assert isinstance(child, type(parent1))
def test_persistence_save_load(self, config, config_manager, mock_memory_system, tmp_path):
"""Test saving and loading evolution state."""
# Set up temporary cache directory
config.cache_dir = str(tmp_path)
manager = EvolutionManager(config, mock_memory_system, config_manager)
# Set up some state
manager.best_genotype = manager.genotype_factory.create_baseline_genotype()
manager.metrics.api_requests_total = 100
manager.metrics.evolution_cycles_completed = 5
# Save state
manager._save_persistent_state()
# Create new manager and verify it loads the state
manager2 = EvolutionManager(config, mock_memory_system, config_manager)
assert manager2.best_genotype is not None
assert manager2.best_genotype.get_genome_id(
) == manager.best_genotype.get_genome_id()
assert manager2.metrics.api_requests_total == 100
assert manager2.metrics.evolution_cycles_completed == 5
class TestEvolutionAPIIntegration:
"""Test evolution integration with API server."""
def test_evolution_disabled_by_default(self):
"""Test that evolution can be disabled."""
config = MemEvolveConfig()
config.evolution.enable = False # Explicitly disable for test
assert config.evolution.enable == False
def test_evolution_can_be_enabled(self):
"""Test that evolution can be enabled via config."""
config = MemEvolveConfig()
config.evolution.enable = True
assert config.evolution.enable == True
@patch.dict('os.environ', {'MEMEVOLVE_ENABLE_EVOLUTION': 'true'})
def test_evolution_enabled_via_env(self):
"""Test evolution can be enabled via environment variable."""
from memevolve.utils.config import load_config
config = load_config()
assert config.evolution.enable == True