Files
DocsGPT/tests/test_target_coverage.py
Alex 81b6ee5daa Pg 4 (#2390)
* feat: postgres tests

* feat: mongo cutoff

* feat: mongo cutoff

* feat: adjust docs and compose files

* fix: mini code mongo removals

* fix: tests and k8s mongo stuff

* feat: test fixes

* fix: ruff

* fix: vale

* Potential fix for pull request finding 'CodeQL / Clear-text logging of sensitive information'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix: mini suggestions

* vale lint fix 2

* fix: codeql columns thing

* fix: test mongo

* fix: tests coverage

* feat: better tests 4

* feat: more tests

* feat: decent coverage

* fix: ruff fixes

* fix: remove mongo mock

* feat: enhance workflow engine and API routes; add document retrieval and source handling

* feat: e2e tests

* fix: mcp, mongo and more

* fix: mini codeql warning

* fix: agent chunk view

* fix: mini issues

* fix: more pg fixes

* feat: postgres prep on start

* feat: qa tests

* fix: mini improvements

* fix: tests

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Siddhant Rai <siddhant.rai.5686@gmail.com>
2026-04-18 13:13:57 +01:00

320 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Tests targeting specific uncovered lines in:
- application/app.py
- application/celery_init.py
- application/wsgi.py
- application/agents/tools/internal_search.py
- application/seed/seeder.py
"""
import importlib
from unittest.mock import MagicMock, Mock, patch, mock_open
import pytest
# ---------------------------------------------------------------------------
# application/seed/seeder.py line 155
# Task result returned successfully but task.successful() is False
# ---------------------------------------------------------------------------
@pytest.mark.unit
class TestSeederSourceIngestionNotSuccessful:
"""Cover seeder.py line 155: task.successful() returns False."""
def test_task_successful_false_returns_false(self):
from application.seed.seeder import DatabaseSeeder
seeder = DatabaseSeeder()
with patch("application.seed.seeder.ingest_remote") as mock_ingest, patch(
"application.seed.seeder.db_readonly"
) as mock_readonly:
mock_readonly.return_value.__enter__.return_value = MagicMock()
mock_task = MagicMock()
mock_task.get.return_value = {"status": "error"}
mock_task.successful.return_value = False
mock_ingest.delay.return_value = mock_task
with patch.object(
DatabaseSeeder, "_find_system_source_by_remote_url",
return_value=None,
):
config = {
"name": "a",
"source": {"url": "http://fail.com", "name": "fail_src"},
}
result = seeder._handle_source(config)
assert result is False
# ---------------------------------------------------------------------------
# application/agents/tools/internal_search.py
# Line 79: source_doc not found → continue
# Lines 89-90: inner exception in directory structure loading
# Lines 93-94: outer exception in _get_directory_structure
# Line 164: empty path part → continue in _execute_list_files
# Lines 384-385: inner exception in sources_have_directory_structure
# ---------------------------------------------------------------------------
@pytest.mark.unit
class TestGetDirectoryStructureMissingLines:
pass
@pytest.mark.unit
class TestExecuteListFilesEmptyPathPart:
"""Line 164: empty path part in path.strip('/').split('/') → continue."""
def test_path_with_double_slash_navigates_correctly(self):
"""Path with double-slash creates empty middle part, exercises line 164."""
from application.agents.tools.internal_search import InternalSearchTool
tool = InternalSearchTool({"source": {}})
tool._dir_structure_loaded = True
tool._directory_structure = {
"src": {"utils": {"helper.py": {"type": "python"}}},
}
# "src//utils" → strip gives "src//utils" → split gives ["src", "", "utils"]
# the empty "" part triggers line 164 continue
result = tool.execute_action("list_files", path="src//utils")
assert "helper.py" in result
def test_path_with_middle_double_slash_in_list_files(self):
"""line 164: double-slash in path creates empty part → continue."""
from application.agents.tools.internal_search import InternalSearchTool
tool = InternalSearchTool({"source": {}})
tool._dir_structure_loaded = True
tool._directory_structure = {
"docs": {"readme.md": {"type": "md"}},
}
# "docs//readme.md" → navigates through empty middle part
# Since readme.md is a dict with type, it's a file
result = tool.execute_action("list_files", path="docs//readme.md")
# Should either return file content or navigate successfully
assert result is not None
@pytest.mark.unit
class TestSourcesHaveDirectoryStructureInnerException:
"""Lines 384-385: inner exception per doc_id → continue."""
# ---------------------------------------------------------------------------
# application/celery_init.py lines 35-39
# dispose_engine called on worker_process_init signal
# ---------------------------------------------------------------------------
@pytest.mark.unit
class TestCeleryDisposEngineOnFork:
"""Cover lines 35-39: _dispose_db_engine_on_fork calls dispose_engine."""
def test_dispose_engine_called_on_fork(self):
"""Lines 35-39: dispose_engine is imported and called."""
import application.celery_init as celery_module
mock_dispose = Mock()
with patch(
"application.storage.db.engine.dispose_engine", mock_dispose
):
# Call the signal handler directly
celery_module._dispose_db_engine_on_fork()
mock_dispose.assert_called_once()
def test_dispose_engine_import_error_returns_silently(self):
"""Lines 37-38: ImportError on dispose_engine import → return silently."""
import application.celery_init as celery_module
with patch.dict("sys.modules", {"application.storage.db.engine": None}):
# Should not raise
celery_module._dispose_db_engine_on_fork()
# ---------------------------------------------------------------------------
# application/app.py missing lines
# Lines 30-32: Windows pathlib patch (platform.system() == "Windows")
# Lines 51-61: JWT key file setup when AUTH_TYPE is simple_jwt/session_jwt
# Lines 64-66: SIMPLE_JWT_TOKEN creation when AUTH_TYPE is simple_jwt
# Lines 71-74: home route redirect for localhost
# Line 143: __main__ guard
# ---------------------------------------------------------------------------
@pytest.mark.unit
class TestAppHomeFunction:
"""Lines 71-74: test home() function directly with a request context."""
def test_home_localhost_redirects(self):
"""Lines 71-72: home() redirects when remote_addr is localhost."""
from application.app import app, home
with app.test_request_context("/", environ_base={"REMOTE_ADDR": "127.0.0.1"}):
response = home()
# redirect() returns a Response object; check Location header
assert "5173" in response.headers.get("Location", "")
def test_home_external_ip_returns_welcome(self):
"""Lines 73-74: home() returns welcome message for external IPs."""
from application.app import app, home
with app.test_request_context("/", environ_base={"REMOTE_ADDR": "8.8.8.8"}):
response = home()
assert "Welcome" in response
def test_home_docker_ip_redirects(self):
"""Line 71-72: home() redirects for Docker bridge IP."""
from application.app import app, home
with app.test_request_context("/", environ_base={"REMOTE_ADDR": "172.18.0.1"}):
response = home()
assert "5173" in response.headers.get("Location", "")
@pytest.mark.unit
class TestAppJwtKeySetupLogic:
"""Lines 51-66: JWT key setup logic.
These lines execute at module-level under AUTH_TYPE=="simple_jwt"|"session_jwt".
We replicate the exact logic in isolated function calls to get coverage.
"""
def test_jwt_key_read_from_existing_file(self):
"""Lines 51-54: JWT key read from existing .jwt_secret_key file."""
import os
file_content = "existing_secret_key_abc123"
jwt_secret_key = None
key_file = ".jwt_secret_key"
with patch("builtins.open", mock_open(read_data=file_content)):
try:
with open(key_file, "r") as f:
jwt_secret_key = f.read().strip()
except FileNotFoundError:
new_key = os.urandom(32).hex()
with open(key_file, "w") as f:
f.write(new_key)
jwt_secret_key = new_key
except Exception as e:
raise RuntimeError(f"Failed to setup JWT_SECRET_KEY: {e}")
assert jwt_secret_key == "existing_secret_key_abc123"
def test_jwt_key_created_when_file_not_found(self):
"""Lines 55-59: JWT key created when .jwt_secret_key is missing."""
import os
jwt_secret_key = None
key_file = ".jwt_secret_key"
written_data = []
write_handle = MagicMock()
write_handle.__enter__ = Mock(return_value=write_handle)
write_handle.__exit__ = Mock(return_value=False)
write_handle.write = lambda data: written_data.append(data)
def open_side_effect(path, mode="r"):
if mode == "r":
raise FileNotFoundError(f"No such file: {path}")
return write_handle
with patch("builtins.open", side_effect=open_side_effect):
try:
with open(key_file, "r") as f:
jwt_secret_key = f.read().strip()
except FileNotFoundError:
new_key = os.urandom(32).hex()
with open(key_file, "w") as f:
f.write(new_key)
jwt_secret_key = new_key
except Exception as e:
raise RuntimeError(f"Failed to setup JWT_SECRET_KEY: {e}")
assert jwt_secret_key is not None
assert len(jwt_secret_key) == 64 # 32 bytes → 64 hex chars
def test_jwt_key_raises_runtime_error_on_other_exception(self):
"""Lines 60-61: non-FileNotFoundError raises RuntimeError."""
key_file = ".jwt_secret_key"
def open_side_effect(path, mode="r"):
raise PermissionError("Access denied")
with pytest.raises(RuntimeError, match="Failed to setup JWT_SECRET_KEY"):
with patch("builtins.open", side_effect=open_side_effect):
try:
with open(key_file, "r") as f:
_ = f.read().strip()
except FileNotFoundError:
pass
except Exception as e:
raise RuntimeError(f"Failed to setup JWT_SECRET_KEY: {e}")
def test_simple_jwt_token_encoded(self):
"""Lines 64-66: SIMPLE_JWT_TOKEN is created via jwt.encode."""
from jose import jwt as jose_jwt
key = "test_secret_key_for_testing_purposes"
payload = {"sub": "local"}
token = jose_jwt.encode(payload, key, algorithm="HS256")
assert isinstance(token, str)
assert len(token) > 0
# Verify token is decodable
decoded = jose_jwt.decode(token, key, algorithms=["HS256"])
assert decoded["sub"] == "local"
@pytest.mark.unit
class TestAppWindowsPathlib:
"""Lines 30-32: Windows pathlib patch."""
def test_windows_pathlib_patched_on_windows(self):
"""Lines 30-32: when platform is Windows, PosixPath is replaced."""
import sys
import pathlib
original_posix_path = pathlib.PosixPath
for mod in list(sys.modules.keys()):
if mod == "application.app":
del sys.modules[mod]
try:
with patch("platform.system", return_value="Windows"):
try:
import application.app # noqa: F401
except Exception:
pass
finally:
# Always restore PosixPath to avoid corrupting test runner
pathlib.PosixPath = original_posix_path
# ---------------------------------------------------------------------------
# application/wsgi.py line 5 (__main__ block)
# Cannot be covered via import; skip with a note.
# The import itself (lines 1-3) is covered by test_remaining_coverage.py.
# ---------------------------------------------------------------------------
@pytest.mark.unit
class TestWsgiMainGuard:
pass
def test_wsgi_app_attribute_accessible(self):
"""Lines 1-4: wsgi.py can be imported and app is accessible."""
import application.wsgi
importlib.reload(application.wsgi)
assert hasattr(application.wsgi, "app")