from __future__ import annotations from pathlib import Path import pytest from app.core.antenna import AntennaPattern, gain from app.core.coverage import compute_coverage from app.core.vegetation import WORLDCOVER_P833, p833_coefficients_for_class from app.models.coverage import CoverageRequest from app.services import jobs def test_jobs_store_roundtrip() -> None: job_id = jobs.create_job("coverage", {"model": "fspl"}) jobs.update_job(job_id, status="running") jobs.update_job(job_id, status="done", result={"ok": True}) response = jobs.get_job(job_id) assert response is not None assert response.status == "done" assert response.result == {"ok": True} def test_coverage_fspl_geojson() -> None: request = CoverageRequest( tx={ "lat": 59.935, "lon": 30.305, "height_agl": 30, "power_dbm": 40, "frequency_mhz": 433, }, antenna={"pattern": "omni", "gain_dbi": 8}, rx={"height_agl": 2, "sensitivity_dbm": -110, "gain_dbi": 2}, model="fspl", radius_m=5000, azimuth_step_deg=90, range_step_m=500, include_vegetation=False, levels_dbm=[-90], format="geojson", ) result = compute_coverage(request) assert result["type"] == "FeatureCollection" assert len(result["features"]) >= 1 def test_worldcover_p833_mapping() -> None: coeffs = p833_coefficients_for_class("tree_cover") assert coeffs.gamma_db_per_m == WORLDCOVER_P833["tree_cover"].gamma_db_per_m def test_antenna_pattern_file(tmp_path: Path) -> None: pattern_file = tmp_path / "pattern.csv" pattern_file.write_text( "# azimuth, elevation, relative_gain\n" "0,0,0\n" "90,0,-3\n" "180,0,-20\n", encoding="utf-8", ) pattern = AntennaPattern(pattern="file", gain_dbi=8, pattern_file=str(pattern_file)) assert gain(pattern, 0, 0) == 8 assert gain(pattern, 90, 0) == 5 @pytest.mark.parametrize("model", ["itm", "p452", "p1812"]) def test_propagation_models_return_positive_loss(model: str) -> None: from app.core.geo import GeoPoint from app.core.propagation import itm_loss, p452_loss, p1812_field tx = GeoPoint(lat=59.935, lon=30.305) rx = GeoPoint(lat=59.945, lon=30.325) profile = [10.0, 12.0, 15.0, 13.0, 11.0] kwargs = { "tx_height_agl": 30.0, "rx_height_agl": 2.0, "freq_mhz": 433.0, "elevation_profile_m": profile, } if model == "itm": loss = itm_loss(tx, rx, **kwargs) elif model == "p452": loss = p452_loss(tx, rx, **kwargs) else: loss = p1812_field(tx, rx, environment="rural", **kwargs) assert loss > 0