Skip to content

Commit f3a889f

Browse files
committed
Add comprehensive test suite for core modules, including config, db, evaluator, firestore_client, manage_exclusions, and test_evaluation_function.
1 parent 3d18268 commit f3a889f

6 files changed

Lines changed: 899 additions & 0 deletions

File tree

tests/test_config.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import importlib
2+
import logging
3+
4+
import config
5+
6+
7+
def _reload_config():
8+
return importlib.reload(config)
9+
10+
11+
def test_log_level_env_var_sets_logger_level(monkeypatch):
12+
with monkeypatch.context() as mp:
13+
mp.setenv("LOG_LEVEL", "DEBUG")
14+
reloaded = _reload_config()
15+
assert reloaded.logger.level == logging.DEBUG
16+
_reload_config()
17+
18+
19+
def test_invalid_log_level_falls_back_to_info(monkeypatch):
20+
with monkeypatch.context() as mp:
21+
mp.setenv("LOG_LEVEL", "NOT_A_LEVEL")
22+
reloaded = _reload_config()
23+
assert reloaded.logger.level == logging.INFO
24+
_reload_config()
25+
26+
27+
def test_request_delay_and_max_concurrency_parsed_from_env(monkeypatch):
28+
with monkeypatch.context() as mp:
29+
mp.setenv("REQUEST_DELAY", "1.5")
30+
mp.setenv("MAX_CONCURRENCY", "7")
31+
reloaded = _reload_config()
32+
assert reloaded.DEFAULT_REQUEST_DELAY == 1.5
33+
assert isinstance(reloaded.DEFAULT_REQUEST_DELAY, float)
34+
assert reloaded.DEFAULT_MAX_CONCURRENCY == 7
35+
assert isinstance(reloaded.DEFAULT_MAX_CONCURRENCY, int)
36+
_reload_config()

tests/test_db.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
from unittest.mock import MagicMock
2+
3+
import pytest
4+
5+
import db
6+
7+
8+
# ---------------------------------------------------------------------------
9+
# get_db_connection
10+
# ---------------------------------------------------------------------------
11+
12+
def test_get_db_connection_builds_url_and_returns_connection(monkeypatch):
13+
monkeypatch.setenv("DB_USER", "alice")
14+
monkeypatch.setenv("DB_PASSWORD", "secret")
15+
monkeypatch.setenv("DB_HOST", "dbhost")
16+
monkeypatch.setenv("DB_PORT", "5433")
17+
monkeypatch.setenv("DB_NAME", "mydb")
18+
19+
sentinel_conn = object()
20+
engine = MagicMock()
21+
engine.connect.return_value = sentinel_conn
22+
create_engine_mock = MagicMock(return_value=engine)
23+
monkeypatch.setattr(db, "create_engine", create_engine_mock)
24+
25+
result = db.get_db_connection()
26+
27+
assert result is sentinel_conn
28+
called_url = create_engine_mock.call_args[0][0]
29+
assert "alice:secret@dbhost:5433/mydb" in called_url
30+
assert called_url.startswith("postgresql+psycopg2://")
31+
32+
33+
def test_get_db_connection_propagates_connect_errors(monkeypatch):
34+
engine = MagicMock()
35+
engine.connect.side_effect = RuntimeError("connection refused")
36+
monkeypatch.setattr(db, "create_engine", MagicMock(return_value=engine))
37+
38+
with pytest.raises(RuntimeError, match="connection refused"):
39+
db.get_db_connection()
40+
41+
42+
# ---------------------------------------------------------------------------
43+
# fetch_data
44+
# ---------------------------------------------------------------------------
45+
46+
def _mock_conn(rows=None):
47+
conn = MagicMock()
48+
conn.execute.return_value.mappings.return_value = rows if rows is not None else [{"submission_id": "s1"}]
49+
return conn
50+
51+
52+
def _main_query_params(conn):
53+
"""The query params dict passed to the second (main-query) conn.execute call."""
54+
return conn.execute.call_args_list[1][0][1]
55+
56+
57+
def test_fetch_data_returns_rows_as_dicts():
58+
conn = _mock_conn(rows=[{"submission_id": "s1"}, {"submission_id": "s2"}])
59+
60+
result = db.fetch_data(conn, sql_limit=10, eval_function_name="my_func", grade_params_json=None, seed=0.5)
61+
62+
assert result == [{"submission_id": "s1"}, {"submission_id": "s2"}]
63+
64+
65+
def test_fetch_data_clamps_non_positive_sql_limit_to_one():
66+
conn = _mock_conn()
67+
68+
db.fetch_data(conn, sql_limit=0, eval_function_name="my_func", grade_params_json=None, seed=0.5)
69+
70+
assert _main_query_params(conn)["limit_param"] == 1
71+
72+
73+
def test_fetch_data_includes_grade_params_json_when_provided():
74+
conn = _mock_conn()
75+
76+
db.fetch_data(conn, sql_limit=10, eval_function_name="my_func", grade_params_json='{"comparison": "exact"}', seed=0.5)
77+
78+
params = _main_query_params(conn)
79+
assert params["params_param"] == '{"comparison": "exact"}'
80+
81+
82+
def test_fetch_data_adds_placeholders_for_excluded_ids():
83+
conn = _mock_conn()
84+
85+
db.fetch_data(
86+
conn, sql_limit=10, eval_function_name="my_func", grade_params_json=None, seed=0.5,
87+
excluded_ids=["id1", "id2"],
88+
)
89+
90+
params = _main_query_params(conn)
91+
assert params["excl_0"] == "id1"
92+
assert params["excl_1"] == "id2"
93+
94+
95+
def test_fetch_data_adds_placeholders_for_excluded_grade_param_values():
96+
conn = _mock_conn()
97+
98+
db.fetch_data(
99+
conn, sql_limit=10, eval_function_name="my_func", grade_params_json=None, seed=0.5,
100+
excluded_grade_param_values={"comparison": ["exact", "approx"]},
101+
)
102+
103+
params = _main_query_params(conn)
104+
assert params["gpv_key_0"] == "comparison"
105+
assert params["gpv_val_0_0"] == "exact"
106+
assert params["gpv_val_0_1"] == "approx"
107+
108+
109+
def test_fetch_data_propagates_execute_errors():
110+
conn = MagicMock()
111+
conn.execute.side_effect = RuntimeError("query failed")
112+
113+
with pytest.raises(RuntimeError, match="query failed"):
114+
db.fetch_data(conn, sql_limit=10, eval_function_name="my_func", grade_params_json=None, seed=0.5)

0 commit comments

Comments
 (0)