maj via codex
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
@@ -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"]
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user