maj via codex

This commit is contained in:
2026-02-22 18:34:50 +01:00
parent 20af00d653
commit 55387f4b0e
90 changed files with 9902 additions and 1251 deletions
+14 -4
View File
@@ -1,29 +1,39 @@
import os
import pytest
from fastapi.testclient import TestClient
from sqlmodel import SQLModel, create_engine, Session
from sqlmodel.pool import StaticPool
os.environ.setdefault("ENABLE_SCHEDULER", "0")
os.environ.setdefault("ENABLE_BOOTSTRAP", "0")
import app.models # noqa — force l'enregistrement des modèles
from app.main import app
from app.database import get_session
@pytest.fixture(name="session")
def session_fixture():
@pytest.fixture(name="engine")
def engine_fixture():
engine = create_engine(
"sqlite://",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
SQLModel.metadata.create_all(engine)
return engine
@pytest.fixture(name="session")
def session_fixture(engine):
with Session(engine) as session:
yield session
@pytest.fixture(name="client")
def client_fixture(session: Session):
def client_fixture(engine):
def get_session_override():
yield session
with Session(engine) as s:
yield s
app.dependency_overrides[get_session] = get_session_override
client = TestClient(app)
+75
View File
@@ -0,0 +1,75 @@
"""Tests des filtres catégorie/tag/mois du router astuces."""
from app.models.astuce import Astuce
from app.routers.astuces import list_astuces
def _seed(session):
session.add(
Astuce(
titre="Tomate mildiou",
contenu="Surveiller humidité",
categorie="maladie",
tags='["tomate", "mildiou"]',
mois="[6,7,8]",
entity_type="plant",
entity_id=1,
)
)
session.add(
Astuce(
titre="Semis salade",
contenu="Semer en ligne",
categorie="plante",
tags='["salade", "semis"]',
mois="[3,4,9]",
entity_type="plant",
entity_id=2,
)
)
session.add(
Astuce(
titre="Paillage universel",
contenu="Proteger le sol",
categorie="jardin",
tags='["sol", "eau"]',
mois=None,
)
)
session.commit()
def test_filter_by_categorie(session):
_seed(session)
out = list_astuces(entity_type=None, entity_id=None, categorie="plante", tag=None, mois=None, session=session)
assert len(out) == 1
assert out[0].titre == "Semis salade"
def test_filter_by_tag(session):
_seed(session)
out = list_astuces(entity_type=None, entity_id=None, categorie=None, tag="tomate", mois=None, session=session)
assert len(out) == 1
assert out[0].titre == "Tomate mildiou"
def test_filter_by_mois_includes_all_year(session):
_seed(session)
out = list_astuces(entity_type=None, entity_id=None, categorie=None, tag=None, mois=12, session=session)
titles = {a.titre for a in out}
assert "Paillage universel" in titles
assert "Tomate mildiou" not in titles
def test_combined_filters(session):
_seed(session)
out = list_astuces(entity_type=None, entity_id=None, categorie="maladie", tag="mildiou", mois=7, session=session)
assert len(out) == 1
assert out[0].titre == "Tomate mildiou"
def test_legacy_entity_filters(session):
_seed(session)
out = list_astuces(entity_type="plant", entity_id=2, categorie=None, tag=None, mois=None, session=session)
assert len(out) == 1
assert out[0].titre == "Semis salade"
+87
View File
@@ -0,0 +1,87 @@
"""Tests unitaires du service Open-Meteo enrichi."""
from datetime import date as real_date
import app.services.meteo as meteo
class _DummyResponse:
def __init__(self, payload: dict):
self._payload = payload
def raise_for_status(self) -> None:
return None
def json(self) -> dict:
return self._payload
def test_fetch_and_store_forecast_enriched(monkeypatch):
payload = {
"daily": {
"time": ["2026-02-21", "2026-02-22"],
"temperature_2m_min": [1.2, 2.3],
"temperature_2m_max": [8.4, 9.7],
"precipitation_sum": [0.5, 1.0],
"wind_speed_10m_max": [12.0, 15.0],
"weather_code": [3, 61],
"relative_humidity_2m_max": [88, 92],
"et0_fao_evapotranspiration": [0.9, 1.1],
},
"hourly": {
"time": [
"2026-02-21T00:00",
"2026-02-21T01:00",
"2026-02-22T00:00",
"2026-02-22T01:00",
],
"soil_temperature_0cm": [4.0, 6.0, 8.0, 10.0],
},
}
def _fake_get(*_args, **_kwargs):
return _DummyResponse(payload)
monkeypatch.setattr(meteo.httpx, "get", _fake_get)
rows = meteo.fetch_and_store_forecast(lat=45.1, lon=4.0)
assert len(rows) == 2
assert rows[0]["date"] == "2026-02-21"
assert rows[0]["label"] == "Couvert"
assert rows[0]["sol_0cm"] == 5.0
assert rows[0]["etp_mm"] == 0.9
assert rows[1]["label"] == "Pluie légère"
assert rows[1]["sol_0cm"] == 9.0
def test_fetch_and_store_forecast_handles_http_error(monkeypatch):
def _boom(*_args, **_kwargs):
raise RuntimeError("network down")
monkeypatch.setattr(meteo.httpx, "get", _boom)
rows = meteo.fetch_and_store_forecast()
assert rows == []
def test_fetch_forecast_filters_from_today(monkeypatch):
class _FakeDate(real_date):
@classmethod
def today(cls):
return cls(2026, 2, 22)
monkeypatch.setattr(meteo, "date", _FakeDate)
monkeypatch.setattr(
meteo,
"fetch_and_store_forecast",
lambda *_args, **_kwargs: [
{"date": "2026-02-21", "x": 1},
{"date": "2026-02-22", "x": 2},
{"date": "2026-02-23", "x": 3},
],
)
out = meteo.fetch_forecast(days=14)
assert [d["date"] for d in out["days"]] == ["2026-02-22", "2026-02-23"]
+12
View File
@@ -16,3 +16,15 @@ def test_delete_tool(client):
id = r.json()["id"]
r2 = client.delete(f"/api/tools/{id}")
assert r2.status_code == 204
def test_tool_with_video_url(client):
r = client.post(
"/api/tools",
json={
"nom": "Tarière",
"video_url": "/uploads/demo-outil.mp4",
},
)
assert r.status_code == 201
assert r.json()["video_url"] == "/uploads/demo-outil.mp4"