File size: 5,208 Bytes
a7ffb22 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 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")
|