Skip to content

Commit a83c9c2

Browse files
committed
fixes
1 parent c1c0a65 commit a83c9c2

File tree

4 files changed

+149
-2
lines changed

4 files changed

+149
-2
lines changed

modules/client_store.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,12 @@ def bootstrap_clients_from_json() -> bool:
476476
create_db_and_tables()
477477
if not os.path.exists(CLIENTS_JSON_PATH):
478478
return False
479+
session = SessionLocal()
480+
try:
481+
if session.query(models.Client).first() or session.query(models.Account).first():
482+
return False
483+
finally:
484+
session.close()
479485
try:
480486
with open(CLIENTS_JSON_PATH, "r", encoding="ascii") as f:
481487
payload = json.load(f)

modules/market_data/trackers.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,11 +338,18 @@ def _fetch_opensky_rows() -> Tuple[List[Dict[str, Any]], List[str]]:
338338
warnings: List[str] = []
339339
now = time.time()
340340
min_refresh_env = os.getenv("OPENSKY_MIN_REFRESH")
341+
has_oauth = bool(os.getenv("OPENSKY_CLIENT_ID") and os.getenv("OPENSKY_CLIENT_SECRET"))
341342
if min_refresh_env is None:
342-
has_oauth = bool(os.getenv("OPENSKY_CLIENT_ID") and os.getenv("OPENSKY_CLIENT_SECRET"))
343343
min_refresh = 0 if has_oauth else 120
344344
else:
345-
min_refresh = int(min_refresh_env or 0)
345+
try:
346+
min_refresh = int(min_refresh_env or 0)
347+
except ValueError:
348+
warnings.append("OpenSky min refresh must be an integer (seconds).")
349+
min_refresh = 0 if has_oauth else 120
350+
if min_refresh < 0:
351+
warnings.append("OpenSky min refresh must be non-negative; using default.")
352+
min_refresh = 0 if has_oauth else 120
346353
if min_refresh > 0 and (now - TrackerProviders._OPENSKY_LAST_REQUEST) < min_refresh:
347354
wait = int(min_refresh - (now - TrackerProviders._OPENSKY_LAST_REQUEST))
348355
warnings.append(f"OpenSky refresh throttled; retry in {wait}s.")
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import json
2+
3+
from sqlalchemy import create_engine
4+
from sqlalchemy.orm import sessionmaker
5+
6+
import core.database as database
7+
import core.db_management as db_management
8+
from core import models
9+
import modules.client_store as client_store
10+
11+
12+
def _setup_temp_db(tmp_path, monkeypatch):
13+
db_path = tmp_path / "clients.db"
14+
engine = create_engine(
15+
f"sqlite:///{db_path}", connect_args={"check_same_thread": False}
16+
)
17+
session_local = sessionmaker(
18+
autocommit=False, autoflush=False, bind=engine
19+
)
20+
monkeypatch.setattr(database, "engine", engine)
21+
monkeypatch.setattr(database, "SessionLocal", session_local)
22+
monkeypatch.setattr(db_management, "engine", engine)
23+
monkeypatch.setattr(client_store, "SessionLocal", session_local)
24+
return session_local
25+
26+
27+
def _write_clients_json(path, payload):
28+
path.parent.mkdir(parents=True, exist_ok=True)
29+
path.write_text(json.dumps(payload), encoding="ascii")
30+
31+
32+
def test_bootstrap_skips_when_db_not_empty(tmp_path, monkeypatch):
33+
session_local = _setup_temp_db(tmp_path, monkeypatch)
34+
db_management.create_db_and_tables()
35+
session = session_local()
36+
try:
37+
session.add(models.Client(client_uid="c1", name="Existing Client"))
38+
session.commit()
39+
finally:
40+
session.close()
41+
42+
clients_path = tmp_path / "clients.json"
43+
_write_clients_json(
44+
clients_path,
45+
[{"client_id": "c2", "name": "Json Client", "accounts": []}],
46+
)
47+
monkeypatch.setattr(client_store, "CLIENTS_JSON_PATH", str(clients_path))
48+
49+
assert client_store.bootstrap_clients_from_json() is False
50+
51+
session = session_local()
52+
try:
53+
assert session.query(models.Client).count() == 1
54+
finally:
55+
session.close()
56+
57+
58+
def test_bootstrap_loads_when_db_empty(tmp_path, monkeypatch):
59+
session_local = _setup_temp_db(tmp_path, monkeypatch)
60+
db_management.create_db_and_tables()
61+
62+
clients_path = tmp_path / "clients.json"
63+
_write_clients_json(
64+
clients_path,
65+
[
66+
{
67+
"client_id": "c1",
68+
"name": "Json Client",
69+
"accounts": [
70+
{
71+
"account_id": "a1",
72+
"account_name": "Main",
73+
"holdings": {"AAPL": 2},
74+
}
75+
],
76+
}
77+
],
78+
)
79+
monkeypatch.setattr(client_store, "CLIENTS_JSON_PATH", str(clients_path))
80+
81+
assert client_store.bootstrap_clients_from_json() is True
82+
83+
session = session_local()
84+
try:
85+
assert session.query(models.Client).count() == 1
86+
assert session.query(models.Account).count() == 1
87+
finally:
88+
session.close()

tests/test_tracker_feed.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,49 @@ def json(self):
209209
assert points == []
210210
assert any("OpenSky HTTP 429" in warning for warning in warnings)
211211
assert TrackerProviders._OPENSKY_BACKOFF_UNTIL > time.time()
212+
213+
214+
def test_opensky_min_refresh_invalid_value(monkeypatch):
215+
monkeypatch.delenv("FLIGHT_DATA_URL", raising=False)
216+
monkeypatch.delenv("FLIGHT_DATA_PATH", raising=False)
217+
monkeypatch.setenv("OPENSKY_MIN_REFRESH", "not-a-number")
218+
monkeypatch.setenv("CLEAR_INCLUDE_COMMERCIAL", "1")
219+
TrackerProviders._OPENSKY_BACKOFF_UNTIL = 0.0
220+
TrackerProviders._OPENSKY_LAST_REQUEST = 0.0
221+
222+
class OpenSkyResponse:
223+
status_code = 200
224+
225+
def json(self):
226+
return {
227+
"states": [
228+
[
229+
"abc123",
230+
"AAL123",
231+
"United States",
232+
1700000000,
233+
1700000001,
234+
-84.43,
235+
33.63,
236+
10000.0,
237+
False,
238+
200.0,
239+
90.0,
240+
0.0,
241+
None,
242+
11000.0,
243+
"1200",
244+
False,
245+
0,
246+
]
247+
]
248+
}
249+
250+
with mock.patch(
251+
"modules.market_data.trackers.requests.get",
252+
return_value=OpenSkyResponse(),
253+
) as mocked_get:
254+
points, warnings = TrackerProviders.fetch_flights()
255+
assert points
256+
assert any("min refresh" in warning.lower() for warning in warnings)
257+
mocked_get.assert_called_once()

0 commit comments

Comments
 (0)