Stazioni: sorgenti camera lette dall'acquisitore, link Acquisizione (#88)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbf7qKuxsnAVjxthRy7dnB
This commit is contained in:
2026-10-24 14:51:22 +02:00
parent 2760623b53
commit 390d6210d0
8 changed files with 253 additions and 18 deletions
@@ -254,3 +254,74 @@ def test_create_station_proxy_forwards_the_camera_fields(logged_in_client, mock_
resp = logged_in_client.post("/admin/api/stations", json=body)
assert resp.status_code == 201
mock_admin_api.post.assert_called_once_with("/api/stations", data=body)
# --- Sorgenti camera lette dall'acquisitore (#88) ---
def _fake_sources_response(status=200, payload=None):
resp = MagicMock()
resp.status_code = status
resp.json.return_value = payload
return resp
def test_camera_sources_proxy_keeps_only_the_three_fields(logged_in_client, mock_admin_api):
payload = {"sources": [
{"name": "camera:folder", "label": "Cartella", "kind": "folder", "extra": 1},
{"name": "camera:123", "label": "Basler", "kind": "gige"},
]}
with patch("blueprints.admin.http_requests.get",
return_value=_fake_sources_response(200, payload)) as get:
resp = logged_in_client.get("/admin/api/camera/sources?url=http://acq:8765/")
assert resp.status_code == 200
assert resp.get_json()["sources"][0] == {
"name": "camera:folder", "label": "Cartella", "kind": "folder"}
assert len(resp.get_json()["sources"]) == 2
assert get.call_args.args[0] == "http://acq:8765/camera/sources"
assert get.call_args.kwargs["timeout"] == 5
@pytest.mark.parametrize("url", ["ftp://x", "", "http://", "acq:8765"])
def test_camera_sources_proxy_rejects_invalid_url(logged_in_client, mock_admin_api, url):
with patch("blueprints.admin.http_requests.get") as get:
resp = logged_in_client.get("/admin/api/camera/sources", query_string={"url": url})
assert resp.status_code == 400
assert resp.get_json()["error"] is True
get.assert_not_called()
def test_camera_sources_proxy_unreachable_is_502(logged_in_client, mock_admin_api):
import requests
with patch("blueprints.admin.http_requests.get",
side_effect=requests.ConnectionError("rifiutata")):
resp = logged_in_client.get("/admin/api/camera/sources?url=http://acq:8765")
assert resp.status_code == 502
assert "rifiutata" in resp.get_json()["detail"]
@pytest.mark.parametrize("status,payload", [(200, {"altro": 1}), (200, {"sources": "x"}), (500, {"sources": []})])
def test_camera_sources_proxy_invalid_response_is_502(logged_in_client, mock_admin_api, status, payload):
with patch("blueprints.admin.http_requests.get",
return_value=_fake_sources_response(status, payload)):
resp = logged_in_client.get("/admin/api/camera/sources?url=http://acq:8765")
assert resp.status_code == 502
def test_camera_sources_proxy_non_admin_is_redirected(client, mock_admin_api):
with client.session_transaction() as sess:
sess["api_key"] = "test-key"
sess["user"] = {"id": 2, "username": "operator", "roles": ["MeasurementTec"],
"is_admin": False, "active": True}
sess["user_id"] = 2
with patch("blueprints.admin.http_requests.get") as get:
resp = client.get("/admin/api/camera/sources?url=http://acq:8765")
assert resp.status_code in (301, 302)
get.assert_not_called()
def test_station_form_has_the_camera_sources_picker(logged_in_client, mock_admin_api):
mock_admin_api.get.return_value = []
html = logged_in_client.get("/admin/stations").get_data(as_text=True)
assert "cameraSourcesList" in html
assert "loadCameraSources" in html
assert "/acquisizione" in html
@@ -120,7 +120,7 @@ class TestStationCameraCalibration:
assert resp.status_code == 200
assert body["state"] == "calibrated"
assert body["calibration"]["px_per_mm"] == 20.03
assert body["calibration_url"] == "http://acq:8765/calibrazione"
assert body["calibration_url"] == "http://acq:8765/acquisizione"
args, kwargs = get.call_args
assert args[0] == "http://acq:8765/camera/calibration"
assert kwargs["params"] == {"source": "camera:folder"}
@@ -130,7 +130,7 @@ class TestStationCameraCalibration:
resp, _ = self._get(logged_in_client, _fake(404, b"{}", {"detail": "no"}))
assert resp.status_code == 200
assert resp.get_json()["state"] == "uncalibrated"
assert resp.get_json()["calibration_url"] == "http://acq:8765/calibrazione"
assert resp.get_json()["calibration_url"] == "http://acq:8765/acquisizione"
def test_unreachable(self, logged_in_client, mock_api_client):
_stations(mock_api_client)