n8n/packages/@n8n/task-runner-python/tests/unit/test_env.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

224 lines
8.4 KiB
Python
Raw Normal View History

import os
import tempfile
from pathlib import Path
import pytest
from unittest.mock import patch
from src.env import read_env, read_int_env, read_bool_env, read_str_env, read_float_env
class TestReadEnv:
def test_returns_direct_env_var_when_exists(self):
with patch.dict(os.environ, {"TEST_VAR": "direct_value"}):
result = read_env("TEST_VAR")
assert result == "direct_value"
def test_returns_none_when_no_env_var(self):
with patch.dict(os.environ, clear=True):
result = read_env("NONEXISTENT_VAR")
assert result is None
def test_reads_from_file_when_file_env_var_exists(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("file_value\n")
f.flush()
with patch.dict(os.environ, {"TEST_VAR_FILE": f.name}):
result = read_env("TEST_VAR")
assert result == "file_value"
def test_strips_whitespace_from_file_content(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write(" value_with_spaces \n\n")
f.flush()
with patch.dict(os.environ, {"TEST_VAR_FILE": f.name}):
result = read_env("TEST_VAR")
assert result == "value_with_spaces"
def test_direct_env_var_takes_precedence_over_file(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("file_value")
f.flush()
with patch.dict(
os.environ,
{"TEST_VAR": "direct_value", "TEST_VAR_FILE": f.name},
):
result = read_env("TEST_VAR")
assert result == "direct_value"
def test_raises_error_when_file_not_found(self):
with patch.dict(os.environ, {"TEST_VAR_FILE": "/nonexistent/file.txt"}):
with pytest.raises(ValueError) as exc_info:
read_env("TEST_VAR")
assert "Failed to read TEST_VAR_FILE from file" in str(exc_info.value)
def test_handles_empty_file(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("")
f.flush()
with patch.dict(os.environ, {"TEST_VAR_FILE": f.name}):
result = read_env("TEST_VAR")
assert result == ""
def test_handles_multiline_file_content(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("line1\nline2\nline3")
f.flush()
with patch.dict(os.environ, {"TEST_VAR_FILE": f.name}):
result = read_env("TEST_VAR")
assert result == "line1\nline2\nline3"
def test_handles_unicode_content(self):
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=True) as f:
f.write("unicode: 你好世界 🌍")
f.flush()
with patch.dict(os.environ, {"TEST_VAR_FILE": f.name}):
result = read_env("TEST_VAR")
assert result == "unicode: 你好世界 🌍"
def test_raises_error_with_permission_denied(self):
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
f.write("secret_value")
temp_file_path = f.name
try:
Path(temp_file_path).chmod(0o000) # Make file unreadable
with patch.dict(os.environ, {"TEST_VAR_FILE": temp_file_path}):
with pytest.raises(ValueError) as exc_info:
read_env("TEST_VAR")
assert "Failed to read TEST_VAR_FILE from file" in str(exc_info.value)
finally:
Path(temp_file_path).chmod(0o644)
Path(temp_file_path).unlink()
class TestReadStrEnv:
def test_returns_string_from_direct_env(self):
with patch.dict(os.environ, {"TEST_STR": "hello world"}):
result = read_str_env("TEST_STR", default="default")
assert result == "hello world"
def test_returns_string_from_file(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("file content")
f.flush()
with patch.dict(os.environ, {"TEST_STR_FILE": f.name}):
result = read_str_env("TEST_STR", default="default")
assert result == "file content"
def test_returns_default_when_not_set(self):
with patch.dict(os.environ, clear=True):
result = read_str_env("TEST_STR", default="fallback")
assert result == "fallback"
def test_handles_empty_string_from_env(self):
with patch.dict(os.environ, {"TEST_STR": ""}):
result = read_str_env("TEST_STR", default="default")
assert result == ""
class TestReadIntEnv:
def test_returns_int_from_direct_env(self):
with patch.dict(os.environ, {"TEST_INT": "42"}):
result = read_int_env("TEST_INT", default=0)
assert result == 42
def test_returns_int_from_file(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("123")
f.flush()
with patch.dict(os.environ, {"TEST_INT_FILE": f.name}):
result = read_int_env("TEST_INT", default=0)
assert result == 123
def test_returns_default_when_not_set(self):
with patch.dict(os.environ, clear=True):
result = read_int_env("TEST_INT", default=999)
assert result == 999
def test_raises_error_for_invalid_int(self):
with patch.dict(os.environ, {"TEST_INT": "not_a_number"}):
with pytest.raises(ValueError) as exc_info:
read_int_env("TEST_INT", default=0)
assert "must be an integer" in str(exc_info.value)
def test_handles_negative_numbers(self):
with patch.dict(os.environ, {"TEST_INT": "-42"}):
result = read_int_env("TEST_INT", default=0)
assert result == -42
class TestReadBoolEnv:
def test_returns_true_for_true_string(self):
with patch.dict(os.environ, {"TEST_BOOL": "true"}):
result = read_bool_env("TEST_BOOL", default=False)
assert result is True
def test_returns_false_for_false_string(self):
with patch.dict(os.environ, {"TEST_BOOL": "false"}):
result = read_bool_env("TEST_BOOL", default=True)
assert result is False
def test_returns_true_from_file(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("true")
f.flush()
with patch.dict(os.environ, {"TEST_BOOL_FILE": f.name}):
result = read_bool_env("TEST_BOOL", default=False)
assert result is True
def test_returns_default_when_not_set(self):
with patch.dict(os.environ, clear=True):
result = read_bool_env("TEST_BOOL", default=True)
assert result is True
class TestReadFloatEnv:
def test_returns_float_from_direct_env(self):
with patch.dict(os.environ, {"TEST_FLOAT": "3.14"}):
result = read_float_env("TEST_FLOAT", default=0.0)
assert result == 3.14
def test_returns_float_from_file(self):
with tempfile.NamedTemporaryFile(mode="w", delete=True) as f:
f.write("2.718")
f.flush()
with patch.dict(os.environ, {"TEST_FLOAT_FILE": f.name}):
result = read_float_env("TEST_FLOAT", default=0.0)
assert result == 2.718
def test_returns_default_when_not_set(self):
with patch.dict(os.environ, clear=True):
result = read_float_env("TEST_FLOAT", default=9.99)
assert result == 9.99
def test_raises_error_for_invalid_float(self):
with patch.dict(os.environ, {"TEST_FLOAT": "not_a_number"}):
with pytest.raises(ValueError) as exc_info:
read_float_env("TEST_FLOAT", default=0.0)
assert "must be a float" in str(exc_info.value)
def test_handles_negative_numbers(self):
with patch.dict(os.environ, {"TEST_FLOAT": "-42.5"}):
result = read_float_env("TEST_FLOAT", default=0.0)
assert result == -42.5
def test_handles_integer_values(self):
with patch.dict(os.environ, {"TEST_FLOAT": "42"}):
result = read_float_env("TEST_FLOAT", default=0.0)
assert result == 42.0
def test_handles_zero(self):
with patch.dict(os.environ, {"TEST_FLOAT": "0"}):
result = read_float_env("TEST_FLOAT", default=1.0)
assert result == 0.0