Skip to content

Commit 70357a4

Browse files
committed
test: implementation
1 parent 5649a5f commit 70357a4

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

tests/test_api_key_from_env.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
"""
2+
Tests for api_key from_env configuration feature
3+
"""
4+
5+
import os
6+
import tempfile
7+
import unittest
8+
9+
from openevolve.config import Config, LLMModelConfig
10+
11+
12+
class TestApiKeyFromEnv(unittest.TestCase):
13+
"""Tests for api_key from_env parameter handling in configuration"""
14+
15+
def setUp(self):
16+
"""Set up test environment variables"""
17+
self.test_env_var = "TEST_OPENEVOLVE_API_KEY"
18+
self.test_api_key = "test-secret-key-12345"
19+
os.environ[self.test_env_var] = self.test_api_key
20+
21+
def tearDown(self):
22+
"""Clean up test environment variables"""
23+
if self.test_env_var in os.environ:
24+
del os.environ[self.test_env_var]
25+
26+
def test_api_key_from_env_in_model_config(self):
27+
"""Test that api_key can be loaded from environment variable via from_env"""
28+
model_config = LLMModelConfig(name="test-model", api_key={"from_env": self.test_env_var})
29+
30+
self.assertEqual(model_config.api_key, self.test_api_key)
31+
32+
def test_api_key_direct_value(self):
33+
"""Test that direct api_key value still works"""
34+
direct_key = "direct-api-key-value"
35+
model_config = LLMModelConfig(name="test-model", api_key=direct_key)
36+
37+
self.assertEqual(model_config.api_key, direct_key)
38+
39+
def test_api_key_none(self):
40+
"""Test that api_key can be None"""
41+
model_config = LLMModelConfig(name="test-model", api_key=None)
42+
43+
self.assertIsNone(model_config.api_key)
44+
45+
def test_api_key_from_env_missing_env_var(self):
46+
"""Test that missing environment variable raises ValueError"""
47+
with self.assertRaises(ValueError) as context:
48+
LLMModelConfig(name="test-model", api_key={"from_env": "NONEXISTENT_ENV_VAR_12345"})
49+
50+
self.assertIn("NONEXISTENT_ENV_VAR_12345", str(context.exception))
51+
self.assertIn("is not set", str(context.exception))
52+
53+
def test_api_key_dict_without_from_env_key(self):
54+
"""Test that dict without from_env key raises ValueError"""
55+
with self.assertRaises(ValueError) as context:
56+
LLMModelConfig(name="test-model", api_key={"wrong_key": "value"})
57+
58+
self.assertIn("from_env", str(context.exception))
59+
60+
def test_api_key_from_env_in_llm_config(self):
61+
"""Test that api_key from_env works at LLM config level"""
62+
yaml_config = {
63+
"log_level": "INFO",
64+
"llm": {
65+
"api_base": "https://api.openai.com/v1",
66+
"api_key": {"from_env": self.test_env_var},
67+
"models": [{"name": "test-model", "weight": 1.0}],
68+
},
69+
}
70+
71+
config = Config.from_dict(yaml_config)
72+
73+
self.assertEqual(config.llm.api_key, self.test_api_key)
74+
# Models should inherit the resolved api_key
75+
self.assertEqual(config.llm.models[0].api_key, self.test_api_key)
76+
77+
def test_api_key_from_env_per_model(self):
78+
"""Test that api_key from_env can be specified per model"""
79+
# Set up a second env var for testing
80+
second_env_var = "TEST_OPENEVOLVE_API_KEY_2"
81+
second_api_key = "second-secret-key-67890"
82+
os.environ[second_env_var] = second_api_key
83+
84+
try:
85+
yaml_config = {
86+
"log_level": "INFO",
87+
"llm": {
88+
"api_base": "https://api.openai.com/v1",
89+
"models": [
90+
{
91+
"name": "model-1",
92+
"weight": 1.0,
93+
"api_key": {"from_env": self.test_env_var},
94+
},
95+
{"name": "model-2", "weight": 0.5, "api_key": {"from_env": second_env_var}},
96+
],
97+
},
98+
}
99+
100+
config = Config.from_dict(yaml_config)
101+
102+
self.assertEqual(config.llm.models[0].api_key, self.test_api_key)
103+
self.assertEqual(config.llm.models[1].api_key, second_api_key)
104+
finally:
105+
if second_env_var in os.environ:
106+
del os.environ[second_env_var]
107+
108+
def test_api_key_from_env_in_evaluator_models(self):
109+
"""Test that api_key from_env works in evaluator_models"""
110+
yaml_config = {
111+
"log_level": "INFO",
112+
"llm": {
113+
"api_base": "https://api.openai.com/v1",
114+
"models": [{"name": "evolution-model", "weight": 1.0, "api_key": "direct-key"}],
115+
"evaluator_models": [
116+
{
117+
"name": "evaluator-model",
118+
"weight": 1.0,
119+
"api_key": {"from_env": self.test_env_var},
120+
}
121+
],
122+
},
123+
}
124+
125+
config = Config.from_dict(yaml_config)
126+
127+
self.assertEqual(config.llm.evaluator_models[0].api_key, self.test_api_key)
128+
129+
def test_yaml_file_loading_with_from_env(self):
130+
"""Test loading api_key from_env from actual YAML file"""
131+
yaml_content = f"""
132+
log_level: INFO
133+
llm:
134+
api_base: https://api.openai.com/v1
135+
api_key:
136+
from_env: {self.test_env_var}
137+
models:
138+
- name: test-model
139+
weight: 1.0
140+
"""
141+
142+
with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
143+
f.write(yaml_content)
144+
f.flush()
145+
146+
try:
147+
config = Config.from_yaml(f.name)
148+
self.assertEqual(config.llm.api_key, self.test_api_key)
149+
finally:
150+
os.unlink(f.name)
151+
152+
def test_mixed_api_key_sources(self):
153+
"""Test mixing direct api_key and from_env in same config"""
154+
yaml_config = {
155+
"log_level": "INFO",
156+
"llm": {
157+
"api_base": "https://api.openai.com/v1",
158+
"api_key": "llm-level-direct-key",
159+
"models": [
160+
{
161+
"name": "model-with-env",
162+
"weight": 1.0,
163+
"api_key": {"from_env": self.test_env_var},
164+
},
165+
{"name": "model-with-direct", "weight": 0.5, "api_key": "model-direct-key"},
166+
],
167+
},
168+
}
169+
170+
config = Config.from_dict(yaml_config)
171+
172+
self.assertEqual(config.llm.api_key, "llm-level-direct-key")
173+
self.assertEqual(config.llm.models[0].api_key, self.test_api_key)
174+
self.assertEqual(config.llm.models[1].api_key, "model-direct-key")
175+
176+
177+
if __name__ == "__main__":
178+
unittest.main()

0 commit comments

Comments
 (0)