Ctrl K
ComunidadGuías…

backend/tests/test_config_literal_settings.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""PUT /config rejects values outside a setting's declared choices.

``reload_settings`` overlays saved values with ``model_copy`` (no
validation), so a ``Literal[...]`` on ``UISettings`` never guarded what the
API stored. The track variant policy settings are the Literal fields today;
the check derives the allowed values from the field itself, so a future
Literal setting is covered without touching the route.
"""

import pytest


def test_every_literal_setting_is_checked():
    from routes.config.bounds import literal_choices

    assert literal_choices("cleanup_track_variant_mode") == {"all", "one_per_language"}
    assert literal_choices("cleanup_sidecar_policy") == {"keep_embedded", "drop_if_real_sidecar"}
    assert literal_choices("foreign_track_sweep_budget_s") is None


@pytest.mark.parametrize(
    "key,value",
    [
        ("cleanup_track_variant_mode", "one_track"),
        ("cleanup_track_variant_mode", ""),
        ("cleanup_track_variant_mode", 1),
        ("cleanup_sidecar_policy", "drop"),
        ("cleanup_sidecar_policy", None),
    ],
)
def test_a_value_outside_the_choices_is_rejected_and_nothing_saved(client, key, value):
    from db.config import get_config_entry

    with client.application.app_context():
        before = get_config_entry("cleanup_keep_sdh")
    response = client.put("/api/v1/config", json={"cleanup_keep_sdh": True, key: value})
    assert response.status_code == 400, response.get_json()
    assert key in response.get_json()["error"]
    with client.application.app_context():
        assert get_config_entry("cleanup_keep_sdh") == before


@pytest.mark.parametrize(
    "key,value",
    [
        ("cleanup_track_variant_mode", "one_per_language"),
        ("cleanup_track_variant_mode", "all"),
        ("cleanup_sidecar_policy", "drop_if_real_sidecar"),
    ],
)
def test_a_valid_choice_roundtrips(client, key, value):
    response = client.put("/api/v1/config", json={key: value})
    assert response.status_code == 200, response.get_json()
    assert response.get_json()["config"][key] == value


def test_an_optional_literal_setting_is_checked_too(monkeypatch):
    """``Literal[...] | None`` is a Union, not a Literal: its choices are the
    literal values plus None."""
    from typing import Literal

    from pydantic.fields import FieldInfo

    from config_settings import UISettings
    from routes.config.bounds import literal_choices, literal_keys

    monkeypatch.setitem(
        UISettings.model_fields,
        "zz_optional_mode",
        FieldInfo(annotation=Literal["a", "b"] | None, default=None),
    )
    assert literal_choices("zz_optional_mode") == {"a", "b", None}
    assert "zz_optional_mode" in literal_keys()


# --- POST /config/import (night review I2) ---------------------------------------


def test_import_skips_a_literal_value_outside_the_choices(client):
    """An import saved any writable key as a string; a bad Literal value then
    broke reload_settings for everything. It is skipped and reported."""
    from db.config import get_config_entry

    response = client.post(
        "/api/v1/config/import",
        json={
            "cleanup_track_variant_mode": "one_track",
            "cleanup_sidecar_policy": "drop_if_real_sidecar",
        },
    )
    assert response.status_code == 200, response.get_json()
    body = response.get_json()
    assert "cleanup_track_variant_mode" not in body["imported_keys"]
    assert "cleanup_sidecar_policy" in body["imported_keys"]
    skipped = {e["key"]: e["error"] for e in body["skipped_invalid"]}
    assert "cleanup_track_variant_mode" in skipped
    assert "one_per_language" in skipped["cleanup_track_variant_mode"]
    with client.application.app_context():
        assert get_config_entry("cleanup_track_variant_mode") != "one_track"
        assert get_config_entry("cleanup_sidecar_policy") == "drop_if_real_sidecar"


@pytest.mark.parametrize("value", ["5", 10**9, "abc", True])
def test_import_skips_an_out_of_range_sweep_budget(client, value):
    from db.config import get_config_entry

    response = client.post("/api/v1/config/import", json={"foreign_track_sweep_budget_s": value})
    assert response.status_code == 200, response.get_json()
    body = response.get_json()
    assert "foreign_track_sweep_budget_s" not in body["imported_keys"]
    assert [e["key"] for e in body["skipped_invalid"]] == ["foreign_track_sweep_budget_s"]
    with client.application.app_context():
        assert get_config_entry("foreign_track_sweep_budget_s") != str(value)


def test_import_saves_a_valid_sweep_budget_as_an_integer(client):
    from db.config import get_config_entry

    response = client.post("/api/v1/config/import", json={"foreign_track_sweep_budget_s": " 900 "})
    assert response.status_code == 200, response.get_json()
    assert "foreign_track_sweep_budget_s" in response.get_json()["imported_keys"]
    with client.application.app_context():
        assert get_config_entry("foreign_track_sweep_budget_s") == "900"