argus-netconf-exporter/tests/test_api_sqlite_errors.py

87 lines
2.6 KiB
Python

import sqlite3
from typing import Any, Dict, List
from fastapi.testclient import TestClient
from exporter.api import create_app
from exporter.config import DeviceConfig, GlobalConfig
from exporter.metrics import TransceiverCollector
from exporter.models import DeviceHealthState, DeviceMetricsSnapshot
from exporter.registry import DeviceRegistry
VALID_FERNET_KEY = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
class DummyStore:
"""简单的测试用存储,实现 API 需要的接口,并在指定操作上抛 OperationalError。"""
def __init__(self, fail_on: str | None = None) -> None:
self.fail_on = fail_on
# 与 SQLiteDeviceStore 接口对齐
def init_db(self) -> None: # pragma: no cover - 在这些测试中不会调用
return
def load_runtime_devices(self) -> List[DeviceConfig]:
return []
def save_device(self, cfg: DeviceConfig) -> None:
if self.fail_on == "save":
raise sqlite3.OperationalError("database is locked")
def delete_device(self, name: str) -> None:
if self.fail_on == "delete":
raise sqlite3.OperationalError("database is locked")
def close(self) -> None: # pragma: no cover - 这里无需验证
return
def _build_app_with_dummy_store(fail_on: str | None) -> TestClient:
gc = GlobalConfig()
gc.api_token = "token"
gc.runtime_db_path = ":memory:"
gc.password_secret = VALID_FERNET_KEY
registry = DeviceRegistry(global_scrape_interval=gc.scrape_interval_seconds)
cache: Dict[str, DeviceMetricsSnapshot] = {}
health: Dict[str, DeviceHealthState] = {}
collector = TransceiverCollector(cache, health)
store = DummyStore(fail_on=fail_on)
app = create_app(registry, store, collector, gc)
return TestClient(app)
def test_post_device_sqlite_operational_error_returns_503():
client = _build_app_with_dummy_store(fail_on="save")
payload = {
"name": "dev-save-error",
"host": "192.0.2.10",
"port": 830,
"username": "u",
"password": "p",
"enabled": True,
}
resp = client.post(
"/api/v1/devices",
headers={"X-API-Token": "token"},
json=payload,
)
assert resp.status_code == 503
assert "database is locked" in resp.json()["detail"]
def test_delete_device_sqlite_operational_error_returns_503():
client = _build_app_with_dummy_store(fail_on="delete")
resp = client.delete(
"/api/v1/devices/nonexistent",
headers={"X-API-Token": "token"},
)
assert resp.status_code == 503
assert "database is locked" in resp.json()["detail"]