mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
Remove unused imports in test files: - test_config_loader.py: remove unused os - test_taskmgr.py: remove unused Mock - test_preproc.py: remove unused unsupported_query, image_chain Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
309 lines
9.1 KiB
Python
309 lines
9.1 KiB
Python
"""
|
|
Unit tests for configuration loading and overrides.
|
|
|
|
Tests cover:
|
|
- Valid YAML config loading
|
|
- Valid JSON config loading
|
|
- Invalid YAML/JSON error behavior
|
|
- Missing config file behavior
|
|
- Template completion
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
import json
|
|
|
|
from langbot.pkg.config.impls.yaml import YAMLConfigFile
|
|
from langbot.pkg.config.impls.json import JSONConfigFile
|
|
from langbot.pkg.config.manager import ConfigManager
|
|
|
|
|
|
class TestYAMLConfigFile:
|
|
"""Tests for YAML config file handling."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_valid_yaml_loads(self, tmp_path):
|
|
"""Valid YAML config should load correctly."""
|
|
config_file = tmp_path / "test_config.yaml"
|
|
|
|
# Write valid YAML
|
|
config_file.write_text("""
|
|
name: test_app
|
|
version: 1.0
|
|
settings:
|
|
debug: true
|
|
port: 8080
|
|
""")
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default', 'version': '0.1'},
|
|
)
|
|
|
|
result = await yaml_file.load(completion=False)
|
|
|
|
assert result['name'] == 'test_app'
|
|
assert result['version'] == 1.0
|
|
assert result['settings']['debug'] is True
|
|
assert result['settings']['port'] == 8080
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_invalid_yaml_raises_error(self, tmp_path):
|
|
"""Invalid YAML should raise clear error."""
|
|
config_file = tmp_path / "invalid.yaml"
|
|
|
|
# Write invalid YAML (unclosed bracket)
|
|
config_file.write_text("""
|
|
name: test
|
|
settings:
|
|
- item1
|
|
- item2
|
|
- [unclosed
|
|
""")
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default'},
|
|
)
|
|
|
|
with pytest.raises(Exception, match="Syntax error"):
|
|
await yaml_file.load(completion=False)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_missing_config_creates_from_template(self, tmp_path):
|
|
"""Missing config file should be created from template."""
|
|
config_file = tmp_path / "new_config.yaml"
|
|
|
|
# File doesn't exist yet
|
|
assert not config_file.exists()
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'new_app', 'version': '1.0'},
|
|
)
|
|
|
|
result = await yaml_file.load()
|
|
|
|
assert config_file.exists()
|
|
assert result['name'] == 'new_app'
|
|
assert result['version'] == '1.0'
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_template_completion(self, tmp_path):
|
|
"""Config should be completed with template defaults."""
|
|
config_file = tmp_path / "partial.yaml"
|
|
|
|
# Write partial config missing some template keys
|
|
config_file.write_text("""
|
|
name: custom_name
|
|
""")
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default_name', 'version': '2.0', 'debug': False},
|
|
)
|
|
|
|
result = await yaml_file.load(completion=True)
|
|
|
|
# Existing key preserved
|
|
assert result['name'] == 'custom_name'
|
|
# Missing keys filled from template
|
|
assert result['version'] == '2.0'
|
|
assert result['debug'] is False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_yaml_save(self, tmp_path):
|
|
"""YAML config can be saved."""
|
|
config_file = tmp_path / "save_test.yaml"
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'test'},
|
|
)
|
|
|
|
await yaml_file.save({'name': 'saved_app', 'new_key': 'new_value'})
|
|
|
|
assert config_file.exists()
|
|
content = config_file.read_text()
|
|
assert 'saved_app' in content
|
|
assert 'new_key' in content
|
|
|
|
def test_yaml_save_sync(self, tmp_path):
|
|
"""YAML config can be saved synchronously."""
|
|
config_file = tmp_path / "sync_save.yaml"
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'test'},
|
|
)
|
|
|
|
yaml_file.save_sync({'name': 'sync_saved'})
|
|
|
|
assert config_file.exists()
|
|
content = config_file.read_text()
|
|
assert 'sync_saved' in content
|
|
|
|
|
|
class TestJSONConfigFile:
|
|
"""Tests for JSON config file handling."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_valid_json_loads(self, tmp_path):
|
|
"""Valid JSON config should load correctly."""
|
|
config_file = tmp_path / "test_config.json"
|
|
|
|
# Write valid JSON
|
|
config_file.write_text(json.dumps({
|
|
'name': 'json_app',
|
|
'version': '1.0',
|
|
'settings': {'debug': True, 'port': 8080},
|
|
}))
|
|
|
|
json_file = JSONConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default', 'version': '0.1'},
|
|
)
|
|
|
|
result = await json_file.load(completion=False)
|
|
|
|
assert result['name'] == 'json_app'
|
|
assert result['version'] == '1.0'
|
|
assert result['settings']['debug'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_invalid_json_raises_error(self, tmp_path):
|
|
"""Invalid JSON should raise clear error."""
|
|
config_file = tmp_path / "invalid.json"
|
|
|
|
# Write invalid JSON (missing closing brace)
|
|
config_file.write_text('{"name": "test", "unclosed": ')
|
|
|
|
json_file = JSONConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default'},
|
|
)
|
|
|
|
with pytest.raises(Exception, match="Syntax error"):
|
|
await json_file.load(completion=False)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_missing_json_creates_from_template(self, tmp_path):
|
|
"""Missing JSON file should be created from template."""
|
|
config_file = tmp_path / "new_config.json"
|
|
|
|
json_file = JSONConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'new_json_app', 'version': '1.0'},
|
|
)
|
|
|
|
result = await json_file.load()
|
|
|
|
assert config_file.exists()
|
|
assert result['name'] == 'new_json_app'
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_json_save(self, tmp_path):
|
|
"""JSON config can be saved."""
|
|
config_file = tmp_path / "save_test.json"
|
|
|
|
json_file = JSONConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'test'},
|
|
)
|
|
|
|
await json_file.save({'name': 'saved_json', 'new_key': 'value'})
|
|
|
|
assert config_file.exists()
|
|
content = config_file.read_text()
|
|
data = json.loads(content)
|
|
assert data['name'] == 'saved_json'
|
|
|
|
|
|
class TestConfigManager:
|
|
"""Tests for ConfigManager."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_config_manager_load(self, tmp_path):
|
|
"""ConfigManager loads config correctly."""
|
|
config_file = tmp_path / "manager_test.yaml"
|
|
config_file.write_text('name: managed_app\nversion: "1.0"\n')
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default', 'version': '0.1'},
|
|
)
|
|
|
|
manager = ConfigManager(yaml_file)
|
|
await manager.load_config()
|
|
|
|
assert manager.data['name'] == 'managed_app'
|
|
assert manager.data['version'] == '1.0'
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_config_manager_dump(self, tmp_path):
|
|
"""ConfigManager can dump config."""
|
|
config_file = tmp_path / "dump_test.yaml"
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default'},
|
|
)
|
|
|
|
manager = ConfigManager(yaml_file)
|
|
manager.data = {'name': 'dumped', 'new_field': 'value'}
|
|
|
|
await manager.dump_config()
|
|
|
|
content = config_file.read_text()
|
|
assert 'dumped' in content
|
|
|
|
def test_config_manager_dump_sync(self, tmp_path):
|
|
"""ConfigManager can dump config synchronously."""
|
|
config_file = tmp_path / "sync_dump.yaml"
|
|
|
|
yaml_file = YAMLConfigFile(
|
|
str(config_file),
|
|
template_data={'name': 'default'},
|
|
)
|
|
|
|
manager = ConfigManager(yaml_file)
|
|
manager.data = {'name': 'sync_dumped'}
|
|
|
|
manager.dump_config_sync()
|
|
|
|
assert config_file.exists()
|
|
|
|
|
|
class TestConfigExists:
|
|
"""Tests for config file existence check."""
|
|
|
|
def test_yaml_exists_true(self, tmp_path):
|
|
"""exists() returns True for existing file."""
|
|
config_file = tmp_path / "exists.yaml"
|
|
config_file.write_text('name: test')
|
|
|
|
yaml_file = YAMLConfigFile(str(config_file), template_data={})
|
|
assert yaml_file.exists() is True
|
|
|
|
def test_yaml_exists_false(self, tmp_path):
|
|
"""exists() returns False for missing file."""
|
|
config_file = tmp_path / "missing.yaml"
|
|
|
|
yaml_file = YAMLConfigFile(str(config_file), template_data={})
|
|
assert yaml_file.exists() is False
|
|
|
|
def test_json_exists_true(self, tmp_path):
|
|
"""exists() returns True for existing JSON file."""
|
|
config_file = tmp_path / "exists.json"
|
|
config_file.write_text('{}')
|
|
|
|
json_file = JSONConfigFile(str(config_file), template_data={})
|
|
assert json_file.exists() is True
|
|
|
|
def test_json_exists_false(self, tmp_path):
|
|
"""exists() returns False for missing JSON file."""
|
|
config_file = tmp_path / "missing.json"
|
|
|
|
json_file = JSONConfigFile(str(config_file), template_data={})
|
|
assert json_file.exists() is False |