"""Unit tests for `harness.settings` — the minimal, extensible server-level TOML config loader (phase settings). Stdlib `tomllib`; defaults baked in; absent/malformed file degrades to defaults (never crashes the harness); unknown keys warn-and-ignore; a present known key of the wrong type errors clearly. """ from __future__ import annotations import os import sys import pytest sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "runner")) from harness import settings # noqa: E402 def _write(tmp_path, text: str) -> str: p = tmp_path / "settings.toml" p.write_text(text) return str(p) def test_absent_file_yields_defaults(tmp_path): # a path that does not exist → all-defaults, no exception missing = str(tmp_path / "nope.toml") s = settings.load(missing) assert s.skip_canonicals_for_upgrade is False def test_absent_key_yields_default(tmp_path): # present file, present table, but the key omitted → default p = _write(tmp_path, "[upgrade]\n") assert settings.load(p).skip_canonicals_for_upgrade is False def test_empty_file_yields_defaults(tmp_path): p = _write(tmp_path, "") assert settings.load(p).skip_canonicals_for_upgrade is False def test_flag_true_read(tmp_path): p = _write(tmp_path, "[upgrade]\nskip_canonicals_for_upgrade = true\n") assert settings.load(p).skip_canonicals_for_upgrade is True def test_flag_false_read(tmp_path): p = _write(tmp_path, "[upgrade]\nskip_canonicals_for_upgrade = false\n") assert settings.load(p).skip_canonicals_for_upgrade is False def test_malformed_toml_degrades_to_defaults(tmp_path): # syntactically broken TOML must NOT crash the harness — WARN + defaults. p = _write(tmp_path, "[upgrade\nskip_canonicals_for_upgrade = tru") s = settings.load(p) # must not raise assert s.skip_canonicals_for_upgrade is False def test_wrong_type_errors_clearly(tmp_path): # a present key of the wrong type is a loud, actionable error (distinct from a malformed file). p = _write(tmp_path, '[upgrade]\nskip_canonicals_for_upgrade = "yes"\n') with pytest.raises(TypeError) as e: settings.load(p) assert "skip_canonicals_for_upgrade" in str(e.value) assert "bool" in str(e.value) def test_int_not_accepted_for_bool(tmp_path): # bool is an int subclass — a stray 1/0 must not silently coerce to a flag. p = _write(tmp_path, "[upgrade]\nskip_canonicals_for_upgrade = 1\n") with pytest.raises(TypeError): settings.load(p) def test_unknown_key_warns_and_ignored(tmp_path, capsys): p = _write( tmp_path, "[upgrade]\nskip_canonicals_for_upgrade = true\nfuture_knob = 7\n", ) s = settings.load(p) assert s.skip_canonicals_for_upgrade is True # known key still honored err = capsys.readouterr().err assert "unknown key" in err and "future_knob" in err def test_unknown_table_warns_and_ignored(tmp_path, capsys): p = _write(tmp_path, "[future_section]\nx = 1\n") s = settings.load(p) assert s.skip_canonicals_for_upgrade is False err = capsys.readouterr().err assert "unknown table" in err and "future_section" in err def test_non_table_section_ignored(tmp_path, capsys): # a key named like a table but given a scalar — warn, ignore, fall back to defaults for that table. p = _write(tmp_path, "upgrade = 5\n") s = settings.load(p) assert s.skip_canonicals_for_upgrade is False assert "not a table" in capsys.readouterr().err def test_env_var_path_override(tmp_path, monkeypatch): p = _write(tmp_path, "[upgrade]\nskip_canonicals_for_upgrade = true\n") monkeypatch.setenv("CCCI_SETTINGS", p) assert settings.load().skip_canonicals_for_upgrade is True def test_default_path_is_absolute_host_path(): # the live file is an absolute host override co-located with the deployed checkout. assert settings.DEFAULT_PATH == "/etc/cc-ci/settings.toml" assert os.path.isabs(settings.DEFAULT_PATH)