mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 20:14:36 +00:00
Coverage baseline raised from 13.65% to 26% (+12.35%) Gate raised from 12% to 18% Tasks completed: - COV-001: Command system unit tests (100% coverage) - COV-002: API service unit tests batch 1 (user/apikey/model/provider) - COV-003: Provider model manager unit tests - COV-004: Pipeline remaining stage tests (aggregator/cntfilter/longtext/msgtrun) - COV-005: Storage and utils coverage pass - COV-006: Gate ratchet 12%→15% - COV-007: Gate ratchet 15%→18% - COV-008: API service batch 2 (bot/pipeline/webhook/space/maintenance/mcp) - COV-009: Blocked - API controller circular import issue documented - COV-010: Plugin runtime unit tests (+0.08%) - COV-011: RAG and vector unit tests (+0.68%) - COV-012: Core boot and migration unit tests - COV-013: Provider requester logic unit tests (+0.62%) Key additions: - tests/utils/import_isolation.py: sys.modules isolation for circular imports - Provider requester mock tests: proved HTTP-dependent code can be tested locally - Vector filter utilities: 100% coverage on pure functions - API services: fake persistence pattern for unit testing Blocked issue COV-009 documented in langbot-test-plan/1.5/issues/ Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
223 lines
6.7 KiB
Python
223 lines
6.7 KiB
Python
"""
|
|
Tests for langbot.pkg.utils.paths module.
|
|
|
|
Tests path utility functions:
|
|
- get_frontend_path: locates frontend build files
|
|
- get_resource_path: locates resource files
|
|
- _check_if_source_install: detects source install mode
|
|
|
|
Uses tmp_path for file system isolation where applicable.
|
|
"""
|
|
|
|
import os
|
|
import pytest
|
|
from unittest.mock import patch
|
|
|
|
|
|
class TestCheckIfSourceInstall:
|
|
"""Test _check_if_source_install function."""
|
|
|
|
def test_returns_true_for_source_install(self, tmp_path, monkeypatch):
|
|
"""Should return True when main.py with LangBot marker exists."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# LangBot/main.py\n# This is the entry point')
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths._check_if_source_install()
|
|
assert result is True
|
|
|
|
paths._is_source_install = None
|
|
|
|
def test_returns_false_when_no_main_py(self, tmp_path, monkeypatch):
|
|
"""Should return False when main.py doesn't exist."""
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths._check_if_source_install()
|
|
assert result is False
|
|
|
|
paths._is_source_install = None
|
|
|
|
def test_returns_false_when_main_py_without_marker(self, tmp_path, monkeypatch):
|
|
"""Should return False when main.py exists but lacks LangBot marker."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# Some other project\nprint("hello")')
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths._check_if_source_install()
|
|
assert result is False
|
|
|
|
paths._is_source_install = None
|
|
|
|
def test_handles_io_error_gracefully(self, tmp_path, monkeypatch):
|
|
"""Should return False when main.py cannot be read."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# LangBot/main.py\n')
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
# Patch open to raise IOError
|
|
with patch("builtins.open", side_effect=IOError("Cannot read")):
|
|
result = paths._check_if_source_install()
|
|
assert result is False
|
|
|
|
paths._is_source_install = None
|
|
|
|
|
|
class TestGetFrontendPath:
|
|
"""Test get_frontend_path function."""
|
|
|
|
def test_returns_web_dist_by_default(self):
|
|
"""Should return a path containing web/dist as default."""
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths.get_frontend_path()
|
|
# The result should contain web/dist or be an absolute path to it
|
|
assert "web/dist" in result or result.endswith("dist")
|
|
|
|
paths._is_source_install = None
|
|
|
|
def test_finds_dist_directory_in_source_mode(self, tmp_path, monkeypatch):
|
|
"""Should find web/dist when running from source mode."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# LangBot/main.py\n')
|
|
|
|
web_dist = tmp_path / "web" / "dist"
|
|
web_dist.mkdir(parents=True)
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths.get_frontend_path()
|
|
assert result == "web/dist"
|
|
|
|
paths._is_source_install = None
|
|
|
|
def test_prefers_dist_over_out_in_source_mode(self, tmp_path, monkeypatch):
|
|
"""Should prefer web/dist over web/out when both exist in source mode."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# LangBot/main.py\n')
|
|
|
|
web_dist = tmp_path / "web" / "dist"
|
|
web_dist.mkdir(parents=True)
|
|
web_out = tmp_path / "web" / "out"
|
|
web_out.mkdir(parents=True)
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths.get_frontend_path()
|
|
assert result == "web/dist"
|
|
|
|
paths._is_source_install = None
|
|
|
|
|
|
class TestGetResourcePath:
|
|
"""Test get_resource_path function."""
|
|
|
|
def test_returns_original_path_when_not_found(self, tmp_path, monkeypatch):
|
|
"""Should return original path when resource not found."""
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths.get_resource_path("nonexistent/file.txt")
|
|
assert result == "nonexistent/file.txt"
|
|
|
|
paths._is_source_install = None
|
|
|
|
def test_finds_resource_in_current_directory_source_mode(self, tmp_path, monkeypatch):
|
|
"""Should find resource in current directory when in source mode."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# LangBot/main.py\n')
|
|
|
|
resource_file = tmp_path / "templates" / "config.yaml"
|
|
resource_file.parent.mkdir(parents=True, exist_ok=True)
|
|
resource_file.write_text("test: value")
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths.get_resource_path("templates/config.yaml")
|
|
assert os.path.exists(result)
|
|
|
|
paths._is_source_install = None
|
|
|
|
def test_returns_relative_path_in_source_mode(self, tmp_path, monkeypatch):
|
|
"""Should return relative path if resource exists in source mode."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# LangBot/main.py\n')
|
|
|
|
resource_file = tmp_path / "test_resource.txt"
|
|
resource_file.write_text("test content")
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
result = paths.get_resource_path("test_resource.txt")
|
|
assert result == "test_resource.txt"
|
|
|
|
paths._is_source_install = None
|
|
|
|
|
|
class TestPathFunctionsCaching:
|
|
"""Test that path functions use caching correctly."""
|
|
|
|
def test_source_install_cache_is_used(self, tmp_path, monkeypatch):
|
|
"""_check_if_source_install should use cached result."""
|
|
main_py = tmp_path / "main.py"
|
|
main_py.write_text('# LangBot/main.py\n')
|
|
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
from langbot.pkg.utils import paths
|
|
|
|
paths._is_source_install = None
|
|
|
|
# First call sets cache
|
|
result1 = paths._check_if_source_install()
|
|
assert result1 is True
|
|
assert paths._is_source_install is True
|
|
|
|
# Second call uses cache (no file read needed)
|
|
result2 = paths._check_if_source_install()
|
|
assert result2 is True
|
|
|
|
paths._is_source_install = None
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"]) |