mirror of
https://github.com/langgenius/dify.git
synced 2026-07-21 18:58:35 +08:00
143 lines
5.1 KiB
Python
143 lines
5.1 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from pydantic import SecretStr, ValidationError
|
|
|
|
from configs.extra.knowledge_fs_config import KnowledgeFSConfig
|
|
|
|
_REPOSITORY_ROOT = Path(__file__).resolve().parents[4]
|
|
_KNOWLEDGE_FS_DOCKER_VARIABLES = (
|
|
"KNOWLEDGE_FS_ENABLED",
|
|
"KNOWLEDGE_FS_BASE_URL",
|
|
"KNOWLEDGE_FS_JWT_SECRET",
|
|
"KNOWLEDGE_FS_SSE_READ_TIMEOUT_SECONDS",
|
|
"KNOWLEDGE_FS_TIMEOUT_SECONDS",
|
|
)
|
|
|
|
|
|
def test_knowledge_fs_config_normalizes_complete_connection() -> None:
|
|
config = KnowledgeFSConfig(
|
|
KNOWLEDGE_FS_ENABLED=True,
|
|
KNOWLEDGE_FS_BASE_URL=" https://knowledge-fs.test/ ",
|
|
KNOWLEDGE_FS_JWT_SECRET=" production-secret-with-at-least-32-bytes ",
|
|
)
|
|
|
|
assert config.KNOWLEDGE_FS_BASE_URL == "https://knowledge-fs.test"
|
|
assert isinstance(config.KNOWLEDGE_FS_JWT_SECRET, SecretStr)
|
|
assert config.KNOWLEDGE_FS_JWT_SECRET.get_secret_value() == "production-secret-with-at-least-32-bytes"
|
|
assert "production-secret" not in repr(config)
|
|
assert "production-secret" not in config.model_dump_json()
|
|
assert config.KNOWLEDGE_FS_SSE_READ_TIMEOUT_SECONDS == 300.0
|
|
|
|
|
|
def test_knowledge_fs_config_treats_blank_connection_as_disabled() -> None:
|
|
config = KnowledgeFSConfig(
|
|
KNOWLEDGE_FS_BASE_URL=" ",
|
|
KNOWLEDGE_FS_JWT_SECRET="",
|
|
)
|
|
|
|
assert config.KNOWLEDGE_FS_BASE_URL is None
|
|
assert config.KNOWLEDGE_FS_JWT_SECRET is None
|
|
assert config.KNOWLEDGE_FS_ENABLED is False
|
|
|
|
|
|
def test_knowledge_fs_config_requires_connection_when_enabled() -> None:
|
|
with pytest.raises(ValidationError, match="connection settings are required"):
|
|
KnowledgeFSConfig(KNOWLEDGE_FS_ENABLED=True)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("base_url", "jwt_secret"),
|
|
[
|
|
("https://knowledge-fs.test", None),
|
|
(None, "production-secret-with-at-least-32-bytes"),
|
|
],
|
|
)
|
|
def test_disabled_knowledge_fs_config_allows_partial_connection(base_url: str | None, jwt_secret: str | None) -> None:
|
|
config = KnowledgeFSConfig(
|
|
KNOWLEDGE_FS_ENABLED=False,
|
|
KNOWLEDGE_FS_BASE_URL=base_url,
|
|
KNOWLEDGE_FS_JWT_SECRET=jwt_secret,
|
|
)
|
|
|
|
assert config.KNOWLEDGE_FS_ENABLED is False
|
|
|
|
|
|
def test_knowledge_fs_docker_config_is_not_shadowed_by_root_env() -> None:
|
|
root_env_example = (_REPOSITORY_ROOT / "docker/.env.example").read_text(encoding="utf-8")
|
|
api_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/api.env.example").read_text(encoding="utf-8")
|
|
|
|
for variable in _KNOWLEDGE_FS_DOCKER_VARIABLES:
|
|
assert f"{variable}=" not in root_env_example
|
|
assert f"{variable}=" in api_env_example
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("base_url", "jwt_secret"),
|
|
[
|
|
("https://knowledge-fs.test", None),
|
|
(None, "production-secret-with-at-least-32-bytes"),
|
|
],
|
|
)
|
|
def test_knowledge_fs_config_rejects_partial_connection(base_url: str | None, jwt_secret: str | None) -> None:
|
|
with pytest.raises(ValidationError, match="must be configured together"):
|
|
KnowledgeFSConfig(
|
|
KNOWLEDGE_FS_ENABLED=True,
|
|
KNOWLEDGE_FS_BASE_URL=base_url,
|
|
KNOWLEDGE_FS_JWT_SECRET=jwt_secret,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("base_url", ["knowledge-fs.test", "ftp://knowledge-fs.test", "http:///missing-host"])
|
|
def test_knowledge_fs_config_rejects_non_http_absolute_urls(base_url: str) -> None:
|
|
with pytest.raises(ValidationError, match="absolute HTTP\\(S\\) URL"):
|
|
KnowledgeFSConfig(
|
|
KNOWLEDGE_FS_BASE_URL=base_url,
|
|
KNOWLEDGE_FS_JWT_SECRET="production-secret-with-at-least-32-bytes",
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"base_url",
|
|
[
|
|
"https://knowledge-fs.test:notaport",
|
|
"https://knowledge-fs.test:65536",
|
|
],
|
|
)
|
|
def test_knowledge_fs_config_rejects_invalid_ports(base_url: str) -> None:
|
|
with pytest.raises(ValidationError, match="valid port"):
|
|
KnowledgeFSConfig(
|
|
KNOWLEDGE_FS_BASE_URL=base_url,
|
|
KNOWLEDGE_FS_JWT_SECRET="production-secret-with-at-least-32-bytes",
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"base_url",
|
|
[
|
|
"https://user:password@knowledge-fs.test",
|
|
"https://knowledge-fs.test?region=us",
|
|
"https://knowledge-fs.test#gateway",
|
|
],
|
|
)
|
|
def test_knowledge_fs_config_rejects_unsafe_base_url_components(base_url: str) -> None:
|
|
with pytest.raises(ValidationError, match="must not include credentials, query, or fragment"):
|
|
KnowledgeFSConfig(
|
|
KNOWLEDGE_FS_BASE_URL=base_url,
|
|
KNOWLEDGE_FS_JWT_SECRET="production-secret-with-at-least-32-bytes",
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("timeout_seconds", [float("inf"), float("nan"), 60.0001])
|
|
def test_knowledge_fs_config_rejects_unbounded_timeouts(timeout_seconds: float) -> None:
|
|
with pytest.raises(ValidationError):
|
|
KnowledgeFSConfig(KNOWLEDGE_FS_TIMEOUT_SECONDS=timeout_seconds)
|
|
|
|
|
|
@pytest.mark.parametrize("timeout_seconds", [float("inf"), float("nan"), 3600.0001])
|
|
def test_knowledge_fs_config_rejects_unbounded_sse_read_timeouts(timeout_seconds: float) -> None:
|
|
with pytest.raises(ValidationError):
|
|
KnowledgeFSConfig(KNOWLEDGE_FS_SSE_READ_TIMEOUT_SECONDS=timeout_seconds)
|