82a22eaa93
Files changed: - .gitea/workflows/ci.yml - .gitignore - CHANGES.md - EVALS.md - INSTALL-MCP.md - INSTALL.md - VERSION - instructions/setup-instance.md - reports/CONTRACT.md - tools/CONTRACT.md - tools/chemenu/commands/doctor.py - tools/chemenu/config.py - tools/chemenu/mcp/server.py - tools/chemenu/telemetry/policy.py - tools/chemenu/telemetry/schema.py - tools/chemenu/telemetry/writer.py - tools/chemenu/tests/conftest.py - tools/chemenu/tests/test_doctor.py - tools/chemenu/tests/test_mcp_server.py - tools/chemenu/tests/test_telemetry_emit.py - tools/chemenu/tests/test_telemetry_policy.py - tools/chemenu/version.py
128 lines
4.3 KiB
Python
128 lines
4.3 KiB
Python
"""Telemetry policy: installation-form default, the two overrides that beat
|
|
it, and the caching split between the filesystem-derived half and the
|
|
always-live environment half."""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from chemenu.telemetry import policy
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clean_env(monkeypatch):
|
|
for var in (policy.ENV_ENABLED, policy.ENV_MAX_SESSION_BYTES, policy.ENV_KEEP_SESSIONS):
|
|
monkeypatch.delenv(var, raising=False)
|
|
policy.reset_cache()
|
|
yield
|
|
policy.reset_cache()
|
|
|
|
|
|
def _stamp(root: Path) -> None:
|
|
(root / ".wikitool-release.json").write_text("{}", encoding="utf-8")
|
|
|
|
|
|
def _config_file(root: Path, **fields) -> None:
|
|
import json
|
|
|
|
(root / ".wikitool-telemetry.json").write_text(json.dumps(fields), encoding="utf-8")
|
|
|
|
|
|
def test_a_dev_checkout_defaults_on(tmp_path):
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.enabled is True
|
|
assert "dev checkout" in pol.reason
|
|
|
|
|
|
def test_a_stamped_distribution_defaults_off(tmp_path):
|
|
_stamp(tmp_path)
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.enabled is False
|
|
assert "distributed instance" in pol.reason
|
|
|
|
|
|
def test_the_config_file_overrides_the_form_default(tmp_path):
|
|
_stamp(tmp_path)
|
|
_config_file(tmp_path, enabled=True)
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.enabled is True
|
|
assert ".wikitool-telemetry.json" in pol.reason
|
|
|
|
|
|
def test_the_env_var_overrides_the_config_file_in_both_directions(tmp_path, monkeypatch):
|
|
_config_file(tmp_path, enabled=True)
|
|
monkeypatch.setenv(policy.ENV_ENABLED, "0")
|
|
assert policy.resolve(tmp_path).enabled is False
|
|
|
|
_stamp(tmp_path)
|
|
_config_file(tmp_path, enabled=False)
|
|
monkeypatch.setenv(policy.ENV_ENABLED, "1")
|
|
assert policy.resolve(tmp_path).enabled is True
|
|
|
|
|
|
def test_default_caps(tmp_path):
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.max_session_bytes == policy.DEFAULT_MAX_SESSION_BYTES
|
|
assert pol.keep_sessions == policy.DEFAULT_KEEP_SESSIONS
|
|
|
|
|
|
def test_the_config_file_can_set_both_caps(tmp_path):
|
|
_config_file(tmp_path, max_session_bytes=1024, keep_sessions=5)
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.max_session_bytes == 1024
|
|
assert pol.keep_sessions == 5
|
|
|
|
|
|
def test_env_caps_override_the_config_file(tmp_path, monkeypatch):
|
|
_config_file(tmp_path, max_session_bytes=1024, keep_sessions=5)
|
|
monkeypatch.setenv(policy.ENV_MAX_SESSION_BYTES, "2048")
|
|
monkeypatch.setenv(policy.ENV_KEEP_SESSIONS, "9")
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.max_session_bytes == 2048
|
|
assert pol.keep_sessions == 9
|
|
|
|
|
|
def test_a_non_positive_or_unparsable_override_is_ignored(tmp_path, monkeypatch):
|
|
monkeypatch.setenv(policy.ENV_MAX_SESSION_BYTES, "0")
|
|
monkeypatch.setenv(policy.ENV_KEEP_SESSIONS, "not-a-number")
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.max_session_bytes == policy.DEFAULT_MAX_SESSION_BYTES
|
|
assert pol.keep_sessions == policy.DEFAULT_KEEP_SESSIONS
|
|
|
|
|
|
def test_a_malformed_config_file_is_treated_as_absent(tmp_path):
|
|
(tmp_path / ".wikitool-telemetry.json").write_text("{not json", encoding="utf-8")
|
|
pol = policy.resolve(tmp_path)
|
|
assert pol.enabled is True # falls through to the dev-checkout form default
|
|
|
|
|
|
def test_the_filesystem_half_is_cached_per_root(tmp_path):
|
|
"""Writing the stamp *after* the first resolve must not retroactively
|
|
change the cached answer - `reset_cache()` is required to see it."""
|
|
first = policy.resolve(tmp_path)
|
|
assert first.enabled is True
|
|
_stamp(tmp_path)
|
|
still_cached = policy.resolve(tmp_path)
|
|
assert still_cached.enabled is True
|
|
policy.reset_cache()
|
|
assert policy.resolve(tmp_path).enabled is False
|
|
|
|
|
|
def test_the_env_override_is_always_live_even_with_a_cached_root(tmp_path, monkeypatch):
|
|
"""The env var must never need a `reset_cache()` to take effect - only the
|
|
filesystem-derived half is cached."""
|
|
assert policy.resolve(tmp_path).enabled is True
|
|
monkeypatch.setenv(policy.ENV_ENABLED, "0")
|
|
assert policy.resolve(tmp_path).enabled is False
|
|
monkeypatch.delenv(policy.ENV_ENABLED)
|
|
assert policy.resolve(tmp_path).enabled is True
|
|
|
|
|
|
def test_resolve_defaults_to_config_root(tmp_path, monkeypatch):
|
|
from chemenu import config
|
|
|
|
monkeypatch.setattr(config, "ROOT", tmp_path)
|
|
_stamp(tmp_path)
|
|
assert policy.resolve().enabled is False
|