mathly / mathly2 /tests /test_config.py
3v324v23's picture
Add specifications for exercise tests, grades, learning path, lesson quizzes, readiness meter, real tests, rewards, simulation tests, skill mastery, smart board, student home, and test countdown
a7ffb22
Raw History Blame Contribute Delete
5.21 kB
import pytest
from mathly2 import config
from mathly2.config import load_settings
NAMES = ("SUPABASE_URL", "SUPABASE_PUBLISHABLE_KEY", "SUPABASE_SECRET_KEY", "TEACHER_EMAILS", "DEVELOPER_EMAILS", "ADMIN_EMAILS", "ANTHROPIC_API_KEY")
@pytest.fixture(autouse=True)
def clean_environment(monkeypatch):
"""Start with none of the settings in the environment; monkeypatch puts back whatever was there afterwards
(load_dotenv writes into os.environ, so this also stops one test leaking into the next)."""
for name in NAMES:
monkeypatch.setenv(name, "")
monkeypatch.delenv(name)
def write(tmp_path, text):
path = tmp_path / ".env"
path.write_text(text, encoding="utf-8")
return path
def test_the_env_file_fills_in_what_the_environment_does_not_set(tmp_path):
settings = load_settings(write(tmp_path, "TEACHER_EMAILS=A@School.test, b@school.test\n"))
assert settings.teachers == {"a@school.test", "b@school.test"}
assert settings.supabase_on is False # no Supabase values: local development
def test_a_real_environment_variable_wins_over_the_file(tmp_path, monkeypatch):
monkeypatch.setenv("TEACHER_EMAILS", "real@school.test")
settings = load_settings(write(tmp_path, "TEACHER_EMAILS=file@school.test\n"))
assert settings.teachers == {"real@school.test"}
def test_all_three_supabase_values_in_the_file_turn_supabase_on(tmp_path):
text = "SUPABASE_URL=https://p.supabase.test/\nSUPABASE_PUBLISHABLE_KEY=pub\nSUPABASE_SECRET_KEY=sec\n"
settings = load_settings(write(tmp_path, text))
assert settings.supabase_on and settings.supabase_url == "https://p.supabase.test"
def test_a_half_configured_file_is_refused(tmp_path):
with pytest.raises(ValueError, match="all of SUPABASE_URL"):
load_settings(write(tmp_path, "SUPABASE_URL=https://p.supabase.test\n"))
def test_a_missing_env_file_is_fine(tmp_path):
assert load_settings(tmp_path / "nope.env").teachers == frozenset()
def test_the_two_default_files_are_this_apps_own_and_the_repository_root_one():
assert config.ENV_FILE.parent.name == "mathly2" and config.ENV_FILE.name == ".env"
assert config.ROOT_ENV_FILE == config.ENV_FILE.parent.parent / ".env" and config.ROOT_ENV_FILE.parent.name == "mathly"
def test_the_repository_env_is_used_when_this_app_has_none(tmp_path, monkeypatch):
monkeypatch.setattr(config, "ENV_FILE", tmp_path / "missing.env")
monkeypatch.setattr(config, "ROOT_ENV_FILE", write(tmp_path, "ADMIN_EMAILS=root-admin@x.test\nTEACHER_EMAILS=root-teacher@x.test\n"))
settings = load_settings()
assert settings.admins == {"root-admin@x.test"} and settings.teachers == {"root-teacher@x.test"}
def test_order_is_environment_then_this_apps_file_then_the_repository_file(tmp_path, monkeypatch):
own = tmp_path / "own.env"
own.write_text("TEACHER_EMAILS=own@x.test\nADMIN_EMAILS=own-admin@x.test\n", encoding="utf-8")
root = tmp_path / "root.env"
root.write_text("TEACHER_EMAILS=root@x.test\nADMIN_EMAILS=root-admin@x.test\nDEVELOPER_EMAILS=root-dev@x.test\n", encoding="utf-8")
monkeypatch.setattr(config, "ENV_FILE", own)
monkeypatch.setattr(config, "ROOT_ENV_FILE", root)
monkeypatch.setenv("TEACHER_EMAILS", "env@x.test")
settings = load_settings()
assert settings.teachers == {"env@x.test"} # the environment wins over both files
assert settings.admins == {"own-admin@x.test"} # this app's file wins over the repository's
assert settings.developers == {"root-dev@x.test"} # the repository's file fills what is left
def test_passing_a_file_reads_only_that_file(tmp_path, monkeypatch):
monkeypatch.setattr(config, "ROOT_ENV_FILE", write(tmp_path, "ADMIN_EMAILS=root-admin@x.test\n"))
assert load_settings(tmp_path / "nope.env").admins == frozenset()
def test_the_example_file_lists_every_setting_with_empty_values():
example = (config.ENV_FILE.parent / ".env.example").read_text(encoding="utf-8")
for name in ("SUPABASE_URL", "SUPABASE_PUBLISHABLE_KEY", "SUPABASE_SECRET_KEY", "TEACHER_EMAILS"):
assert f"\n{name}=\n" in example
def test_the_container_image_never_gets_the_env_file():
ignore = (config.ENV_FILE.parent / "Dockerfile.dockerignore").read_text(encoding="utf-8").split()
assert "mathly2/.env" in ignore
def test_developers_and_admins_come_from_the_environment_and_the_file(tmp_path, monkeypatch):
monkeypatch.setenv("DEVELOPER_EMAILS", "Dev@School.test")
settings = load_settings(write(tmp_path, "ADMIN_EMAILS=head@school.test, deputy@school.test\nDEVELOPER_EMAILS=file-dev@school.test\n"))
assert settings.developers == {"dev@school.test"} # the environment wins over the file
assert settings.admins == {"head@school.test", "deputy@school.test"} # from the file
assert settings.teachers == frozenset()
def test_the_example_file_and_readme_name_the_new_settings():
base = config.ENV_FILE.parent
for name in ("DEVELOPER_EMAILS", "ADMIN_EMAILS"):
assert f"\n{name}=\n" in (base / ".env.example").read_text(encoding="utf-8")
assert f"`{name}`" in (base / "README.md").read_text(encoding="utf-8")