Track observation source health states

This commit is contained in:
2569718930@qq.com
2026-06-14 19:06:03 +08:00
parent ccc8866229
commit d0c8d4c11b
3 changed files with 260 additions and 17 deletions
+125
View File
@@ -162,6 +162,62 @@ def test_raw_observation_store_records_latest_observation(tmp_path):
assert latest["payload"]["temp_c"] == 24.0
def test_raw_observation_failure_preserves_last_success_and_increments_errors(tmp_path):
from src.database.db_manager import DBManager
db = DBManager(str(tmp_path / "polyweather.db"))
db.append_raw_observation(
source="amsc_awos",
city="Qingdao",
value=24.0,
observed_at="2026-06-14T01:00:00+00:00",
fetched_at="2026-06-14T01:01:00+00:00",
station_code="ZSQD",
station_name="Qingdao Jiaodong",
status="ok",
payload={"temp_c": 24.0},
)
db.append_raw_observation(
source="amsc_awos",
city="qingdao",
fetched_at="2026-06-14T01:02:00+00:00",
status="timeout",
payload={"error": "upstream timeout"},
)
latest = db.get_latest_raw_observation("amsc_awos", "qingdao")
assert latest is not None
assert latest["status"] == "timeout"
assert latest["value"] is None
assert latest["error_count"] == 1
assert latest["last_success_at"] == "2026-06-14T01:01:00+00:00"
assert latest["payload"]["error"] == "upstream timeout"
def test_raw_observation_store_computes_source_latency_when_times_are_known(tmp_path):
from src.database.db_manager import DBManager
db = DBManager(str(tmp_path / "polyweather.db"))
db.append_raw_observation(
source="amsc_awos",
city="Qingdao",
value=24.0,
observed_at="2026-06-14T01:00:00+00:00",
fetched_at="2026-06-14T01:01:30+00:00",
station_code="ZSQD",
status="ok",
payload={"temp_c": 24.0},
)
latest = db.get_latest_raw_observation("amsc_awos", "qingdao")
assert latest is not None
assert latest["source_latency_sec"] == 90.0
def test_observation_refresh_request_queue_claims_pending_requests(tmp_path):
from src.database.db_manager import DBManager
@@ -254,6 +310,40 @@ def test_observation_collector_writes_raw_observation_store(tmp_path):
assert latest["station_code"] == "ZSQD"
def test_observation_collector_records_no_results_source_health(tmp_path):
from src.database.db_manager import DBManager
from web.observation_collector_service import (
ObservationCollector,
ObservationSourceProfile,
)
db = DBManager(str(tmp_path / "polyweather.db"))
class FakeWeather:
def _uses_fahrenheit(self, city):
return False
def _attach_china_amsc_awos_data(self, results, city, use_fahrenheit):
return None
collector = ObservationCollector(
weather=FakeWeather(),
profiles=[ObservationSourceProfile("amsc_awos", ("qingdao",), 180)],
observation_store=db,
async_cache_refresh=False,
)
assert collector.run_due_once(now_ts=1000.0) == 0
latest = db.get_latest_raw_observation("amsc_awos", "qingdao")
assert latest is not None
assert latest["status"] == "no_results"
assert latest["value"] is None
assert latest["error_count"] == 1
assert latest["last_success_at"] == ""
assert latest["payload"]["status"] == "no_results"
def test_observation_collector_writes_canonical_latest_from_source(tmp_path):
from src.database.db_manager import DBManager
from web.observation_collector_service import (
@@ -294,6 +384,41 @@ def test_observation_collector_writes_canonical_latest_from_source(tmp_path):
assert canonical["payload"]["observed_at"] == "2026-06-14T01:00:00+00:00"
def test_observation_collector_canonical_uses_source_freshness_profile(tmp_path):
from src.database.db_manager import DBManager
from web.observation_collector_service import ObservationCollector
db = DBManager(str(tmp_path / "polyweather.db"))
collector = ObservationCollector(
weather=object(),
profiles=[],
observation_store=db,
async_cache_refresh=False,
)
collector._store_canonical_temperature_from_observation(
city="qingdao",
source="amsc_awos",
row={
"source": "amsc_awos",
"source_label": "AMSC AWOS",
"temp_c": 24.0,
"observation_time": "2026-06-14T01:00:00+00:00",
"icao": "ZSQD",
},
value=24.0,
observed_at="2026-06-14T01:00:00+00:00",
fetched_at="2026-06-14T01:05:00+00:00",
)
canonical = db.get_canonical_temperature("qingdao")
assert canonical is not None
assert canonical["payload"]["freshness_status"] == "expected_wait"
assert canonical["payload"]["freshness_sec"] == 300
assert canonical["payload"]["confidence"] < 0.92
def test_observation_collector_consumes_refresh_request_queue(tmp_path):
from src.database.db_manager import DBManager
from web.observation_collector_service import (