Some checks failed
CI / lint-and-test (push) Failing after 27s
- Added a global exception handler to log unhandled exceptions and return a generic 500 JSON response without exposing details to the client. - Updated the configuration to validate the `DATABASE_URL` format, ensuring it starts with `sqlite://` or `postgresql://`, and log warnings for invalid formats. - Introduced safe parsing for numeric environment variables (`HTTP_PORT`, `INIT_DATA_MAX_AGE_SECONDS`) with defaults on invalid values, including logging warnings for out-of-range values. - Enhanced the duty schedule parser to enforce limits on the number of schedule rows and the length of full names and duty strings, raising appropriate errors when exceeded. - Updated internationalization messages to include generic error responses for import failures and parsing issues, improving user experience. - Added unit tests to verify the new error handling and configuration validation behaviors.
120 lines
4.7 KiB
Python
120 lines
4.7 KiB
Python
"""Tests for config.is_admin, config.can_access_miniapp, and require_bot_token."""
|
|
|
|
import pytest
|
|
|
|
import duty_teller.config as config
|
|
|
|
|
|
def test_is_admin_true_when_in_admin_list(monkeypatch):
|
|
monkeypatch.setattr(config, "ADMIN_USERNAMES", {"admin1", "admin2"})
|
|
assert config.is_admin("admin1") is True
|
|
assert config.is_admin("ADMIN1") is True
|
|
assert config.is_admin("admin2") is True
|
|
|
|
|
|
def test_is_admin_false_when_not_in_list(monkeypatch):
|
|
monkeypatch.setattr(config, "ADMIN_USERNAMES", {"admin1"})
|
|
assert config.is_admin("other") is False
|
|
assert config.is_admin("") is False
|
|
|
|
|
|
def test_can_access_miniapp_allowed_username(monkeypatch):
|
|
monkeypatch.setattr(config, "ALLOWED_USERNAMES", {"user1"})
|
|
monkeypatch.setattr(config, "ADMIN_USERNAMES", set())
|
|
assert config.can_access_miniapp("user1") is True
|
|
assert config.can_access_miniapp("USER1") is True
|
|
|
|
|
|
def test_can_access_miniapp_admin_has_access(monkeypatch):
|
|
monkeypatch.setattr(config, "ALLOWED_USERNAMES", set())
|
|
monkeypatch.setattr(config, "ADMIN_USERNAMES", {"admin1"})
|
|
assert config.can_access_miniapp("admin1") is True
|
|
|
|
|
|
def test_can_access_miniapp_denied(monkeypatch):
|
|
monkeypatch.setattr(config, "ALLOWED_USERNAMES", {"user1"})
|
|
monkeypatch.setattr(config, "ADMIN_USERNAMES", set())
|
|
assert config.can_access_miniapp("other") is False
|
|
assert config.can_access_miniapp("") is False
|
|
|
|
|
|
def test_settings_from_env_parse_admin_phones_adds_normalized(monkeypatch):
|
|
"""Settings.from_env() parses ADMIN_PHONES and adds normalized phone to admin_phones."""
|
|
monkeypatch.setenv("ADMIN_PHONES", "+7 900 123-45-67")
|
|
settings = config.Settings.from_env()
|
|
assert settings.admin_phones == {"79001234567"}
|
|
|
|
|
|
def test_normalize_phone():
|
|
"""Phone is normalized to digits only."""
|
|
assert config.normalize_phone("+7 900 123-45-67") == "79001234567"
|
|
assert config.normalize_phone("8 (900) 123-45-67") == "89001234567"
|
|
assert config.normalize_phone("79001234567") == "79001234567"
|
|
assert config.normalize_phone("") == ""
|
|
assert config.normalize_phone(None) == ""
|
|
|
|
|
|
def test_can_access_miniapp_by_phone(monkeypatch):
|
|
monkeypatch.setattr(config, "ALLOWED_PHONES", {"79001234567", "79007654321"})
|
|
monkeypatch.setattr(config, "ADMIN_PHONES", set())
|
|
assert config.can_access_miniapp_by_phone("+7 900 123-45-67") is True
|
|
assert config.can_access_miniapp_by_phone("79007654321") is True
|
|
assert config.can_access_miniapp_by_phone("79001111111") is False
|
|
assert config.can_access_miniapp_by_phone(None) is False
|
|
assert config.can_access_miniapp_by_phone("") is False
|
|
|
|
|
|
def test_can_access_miniapp_by_phone_admin(monkeypatch):
|
|
monkeypatch.setattr(config, "ALLOWED_PHONES", set())
|
|
monkeypatch.setattr(config, "ADMIN_PHONES", {"79001111111"})
|
|
assert config.can_access_miniapp_by_phone("+7 900 111-11-11") is True
|
|
assert config.can_access_miniapp_by_phone("79002222222") is False
|
|
|
|
|
|
def test_is_admin_by_phone(monkeypatch):
|
|
monkeypatch.setattr(config, "ADMIN_PHONES", {"79001111111"})
|
|
assert config.is_admin_by_phone("+7 900 111-11-11") is True
|
|
assert config.is_admin_by_phone("79001234567") is False
|
|
assert config.is_admin_by_phone(None) is False
|
|
|
|
|
|
def test_require_bot_token_raises_system_exit_when_empty(monkeypatch):
|
|
"""require_bot_token() raises SystemExit with message about BOT_TOKEN when empty."""
|
|
monkeypatch.setattr(config, "BOT_TOKEN", "")
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
config.require_bot_token()
|
|
assert "BOT_TOKEN" in str(exc_info.value)
|
|
assert exc_info.value.code != 0
|
|
|
|
|
|
def test_require_bot_token_does_not_raise_when_set(monkeypatch):
|
|
"""require_bot_token() does nothing when BOT_TOKEN is set."""
|
|
monkeypatch.setattr(config, "BOT_TOKEN", "123:ABC")
|
|
config.require_bot_token()
|
|
|
|
|
|
def test_settings_from_env_invalid_http_port_uses_default(monkeypatch):
|
|
"""Invalid HTTP_PORT (non-numeric or out of range) yields default or clamped value."""
|
|
monkeypatch.delenv("HTTP_PORT", raising=False)
|
|
settings = config.Settings.from_env()
|
|
assert 1 <= settings.http_port <= 65535
|
|
|
|
monkeypatch.setenv("HTTP_PORT", "not-a-number")
|
|
settings = config.Settings.from_env()
|
|
assert settings.http_port == 8080
|
|
|
|
monkeypatch.setenv("HTTP_PORT", "0")
|
|
settings = config.Settings.from_env()
|
|
assert settings.http_port == 1
|
|
|
|
monkeypatch.setenv("HTTP_PORT", "99999")
|
|
settings = config.Settings.from_env()
|
|
assert settings.http_port == 65535
|
|
|
|
|
|
def test_settings_from_env_invalid_init_data_max_age_uses_default(monkeypatch):
|
|
"""Invalid INIT_DATA_MAX_AGE_SECONDS yields default 0."""
|
|
monkeypatch.setenv("INIT_DATA_MAX_AGE_SECONDS", "invalid")
|
|
settings = config.Settings.from_env()
|
|
assert settings.init_data_max_age_seconds == 0
|