Newer
Older
navi-1 / tests / unit / tools / test_share_file.py
@Eugene Sukhodolskiy Eugene Sukhodolskiy on 29 Apr 3 KB Complete phase 7 regression test coverage
"""Unit tests for share_file tool."""

from urllib.parse import unquote, urlparse

import pytest

import navi.tools.share_file as share_file_mod
from navi.tools.base import current_session_id
from navi.tools.share_file import ShareFileTool


class TestShareFileTool:
    @pytest.fixture
    def tool(self, monkeypatch, tmp_path):
        async def _to_thread(func, *args, **kwargs):
            return func(*args, **kwargs)

        monkeypatch.setattr(share_file_mod.asyncio, "to_thread", _to_thread)
        monkeypatch.setattr(share_file_mod.settings, "session_files_dir", str(tmp_path / "sessions"))
        monkeypatch.setattr(share_file_mod.settings, "share_file_max_size_mb", 1024)
        monkeypatch.setattr(share_file_mod.settings, "public_url", "http://localhost:8000")
        token = current_session_id.set("sess 1")
        try:
            yield ShareFileTool()
        finally:
            current_session_id.reset(token)

    async def test_rejects_relative_path(self, tool):
        result = await tool.execute({"path": "workspace/report.txt"})

        assert not result.success
        assert result.error == "path_not_absolute"

    async def test_copies_file_into_session_dir(self, tool, tmp_path):
        src = tmp_path / "report.txt"
        src.write_text("hello")

        result = await tool.execute({"path": str(src), "filename": "clean report.txt"})

        assert result.success
        dest = tmp_path / "sessions" / "sess 1" / "clean report.txt"
        assert dest.read_text() == "hello"
        assert result.metadata["filename"] == "clean report.txt"

    async def test_rejects_files_over_share_limit(self, tool, monkeypatch, tmp_path):
        monkeypatch.setattr(share_file_mod.settings, "share_file_max_size_mb", 0)
        src = tmp_path / "too_large.bin"
        src.write_bytes(b"x")

        result = await tool.execute({"path": str(src)})

        assert not result.success
        assert result.error == "file_too_large"

    async def test_url_quotes_session_and_filename(self, tool, tmp_path):
        src = tmp_path / "source.txt"
        src.write_text("hello")

        result = await tool.execute({"path": str(src), "filename": "отчёт #1.txt"})

        assert result.success
        parsed = urlparse(result.metadata["url"])
        assert parsed.path.endswith(
            "/sessions/sess%201/files/%D0%BE%D1%82%D1%87%D1%91%D1%82%20%231.txt"
        )
        assert unquote(parsed.path).endswith("/sessions/sess 1/files/отчёт #1.txt")

    async def test_duplicate_filename_gets_numbered_copy(self, tool, tmp_path):
        src = tmp_path / "source.txt"
        src.write_text("new")
        existing = tmp_path / "sessions" / "sess 1" / "report.txt"
        existing.parent.mkdir(parents=True)
        existing.write_text("old")

        result = await tool.execute({"path": str(src), "filename": "report.txt"})

        assert result.success
        assert existing.read_text() == "old"
        numbered = tmp_path / "sessions" / "sess 1" / "report_1.txt"
        assert numbered.read_text() == "new"
        assert result.metadata["filename"] == "report_1.txt"