reflex/tests/units/test_config.py
benedikt-bartscher 9d29e7f3ee
fix and test bug in config env loading (#4205)
* fix and test bug in config env loading

* streamline env var interpretation with @adhami3310

* improve error messages, fix invalid value for TELEMETRY_ENABLED

* just a small hint

* ruffing

* fix typo from review
2024-10-24 10:27:23 -07:00

227 lines
6.7 KiB
Python

import multiprocessing
import os
from pathlib import Path
from typing import Any, Dict
import pytest
import reflex as rx
import reflex.config
from reflex.config import environment
from reflex.constants import Endpoint
def test_requires_app_name():
"""Test that a config requires an app_name."""
with pytest.raises(ValueError):
rx.Config() # type: ignore
def test_set_app_name(base_config_values):
"""Test that the app name is set to the value passed in.
Args:
base_config_values: Config values.
"""
config = rx.Config(**base_config_values)
assert config.app_name == base_config_values["app_name"]
@pytest.mark.parametrize(
"env_var, value",
[
("APP_NAME", "my_test_app"),
("FRONTEND_PORT", 3001),
("FRONTEND_PATH", "/test"),
("BACKEND_PORT", 8001),
("API_URL", "https://mybackend.com:8000"),
("DEPLOY_URL", "https://myfrontend.com"),
("BACKEND_HOST", "127.0.0.1"),
("DB_URL", "postgresql://user:pass@localhost:5432/db"),
("REDIS_URL", "redis://localhost:6379"),
("TIMEOUT", 600),
("TELEMETRY_ENABLED", False),
("TELEMETRY_ENABLED", True),
],
)
def test_update_from_env(
base_config_values: Dict[str, Any],
monkeypatch: pytest.MonkeyPatch,
env_var: str,
value: Any,
):
"""Test that environment variables override config values.
Args:
base_config_values: Config values.
monkeypatch: The pytest monkeypatch object.
env_var: The environment variable name.
value: The environment variable value.
"""
monkeypatch.setenv(env_var, str(value))
assert os.environ.get(env_var) == str(value)
config = rx.Config(**base_config_values)
assert getattr(config, env_var.lower()) == value
def test_update_from_env_path(
base_config_values: Dict[str, Any],
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
):
"""Test that environment variables override config values.
Args:
base_config_values: Config values.
monkeypatch: The pytest monkeypatch object.
tmp_path: The pytest tmp_path fixture object.
"""
monkeypatch.setenv("BUN_PATH", "/test")
assert os.environ.get("BUN_PATH") == "/test"
with pytest.raises(ValueError):
rx.Config(**base_config_values)
monkeypatch.setenv("BUN_PATH", str(tmp_path))
assert os.environ.get("BUN_PATH") == str(tmp_path)
config = rx.Config(**base_config_values)
assert config.bun_path == tmp_path
@pytest.mark.parametrize(
"kwargs, expected",
[
(
{"app_name": "test_app", "api_url": "http://example.com"},
f"{Endpoint.EVENT}",
),
(
{"app_name": "test_app", "api_url": "http://example.com/api"},
f"/api{Endpoint.EVENT}",
),
],
)
def test_event_namespace(mocker, kwargs, expected):
"""Test the event namespace.
Args:
mocker: The pytest mock object.
kwargs: The Config kwargs.
expected: Expected namespace
"""
conf = rx.Config(**kwargs)
mocker.patch("reflex.config.get_config", return_value=conf)
config = reflex.config.get_config()
assert conf == config
assert config.get_event_namespace() == expected
DEFAULT_CONFIG = rx.Config(app_name="a")
@pytest.mark.parametrize(
("config_kwargs", "env_vars", "set_persistent_vars", "exp_config_values"),
[
(
{},
{},
{},
{
"api_url": DEFAULT_CONFIG.api_url,
"backend_port": DEFAULT_CONFIG.backend_port,
"deploy_url": DEFAULT_CONFIG.deploy_url,
"frontend_port": DEFAULT_CONFIG.frontend_port,
},
),
# Ports set in config kwargs
(
{"backend_port": 8001, "frontend_port": 3001},
{},
{},
{
"api_url": "http://localhost:8001",
"backend_port": 8001,
"deploy_url": "http://localhost:3001",
"frontend_port": 3001,
},
),
# Ports set in environment take precedence
(
{"backend_port": 8001, "frontend_port": 3001},
{"BACKEND_PORT": 8002},
{},
{
"api_url": "http://localhost:8002",
"backend_port": 8002,
"deploy_url": "http://localhost:3001",
"frontend_port": 3001,
},
),
# Ports set on the command line take precedence
(
{"backend_port": 8001, "frontend_port": 3001},
{"BACKEND_PORT": 8002},
{"frontend_port": "3005"},
{
"api_url": "http://localhost:8002",
"backend_port": 8002,
"deploy_url": "http://localhost:3005",
"frontend_port": 3005,
},
),
# api_url / deploy_url already set should not be overridden
(
{"api_url": "http://foo.bar:8900", "deploy_url": "http://foo.bar:3001"},
{"BACKEND_PORT": 8002},
{"frontend_port": "3005"},
{
"api_url": "http://foo.bar:8900",
"backend_port": 8002,
"deploy_url": "http://foo.bar:3001",
"frontend_port": 3005,
},
),
],
)
def test_replace_defaults(
monkeypatch,
config_kwargs,
env_vars,
set_persistent_vars,
exp_config_values,
):
"""Test that the config replaces defaults with values from the environment.
Args:
monkeypatch: The pytest monkeypatch object.
config_kwargs: The config kwargs.
env_vars: The environment variables.
set_persistent_vars: The values passed to config._set_persistent variables.
exp_config_values: The expected config values.
"""
mock_os_env = os.environ.copy()
monkeypatch.setattr(reflex.config.os, "environ", mock_os_env) # type: ignore
mock_os_env.update({k: str(v) for k, v in env_vars.items()})
c = rx.Config(app_name="a", **config_kwargs)
c._set_persistent(**set_persistent_vars)
for key, value in exp_config_values.items():
assert getattr(c, key) == value
def reflex_dir_constant():
return environment.REFLEX_DIR
def test_reflex_dir_env_var(monkeypatch, tmp_path):
"""Test that the REFLEX_DIR environment variable is used to set the Reflex.DIR constant.
Args:
monkeypatch: The pytest monkeypatch object.
tmp_path: The pytest tmp_path object.
"""
monkeypatch.setenv("REFLEX_DIR", str(tmp_path))
mp_ctx = multiprocessing.get_context(method="spawn")
with mp_ctx.Pool(processes=1) as pool:
assert pool.apply(reflex_dir_constant) == tmp_path