- ~60 new/extended test files across api, core, plugins, services, schemas: routes, superset clients, task_manager, lineage, git, translate, dashboard-testing, load-testing, migration, llm_analysis, scheduler, ssl - .coveragerc: enable branch coverage; exclude src/__tests__ (test files) and src/scripts (CLI/ops tools) from the denominator - bug fixes found while testing: * settings: PUT /settings/reports registered under duplicated prefix * schemas/lineage: FleetReportDTO missing run_status (route always 500) * dashboard_testing/baseline_inheritance: visual entry read wrong field * superset_client/_databases: logger extra name shadowed LogRecord attr * routes/datasets: _yaml_string_paths recursion without yield from * translate/sql_generator: restore explicit-type timestamp contract * baseline_catalog: remove unreachable dashboard_id fallback - conftest fixes: pytest_plugins to rootdir conftest (pytest 9), test filename collision, TMPDIR-safe integration fixtures
587 lines
23 KiB
Python
587 lines
23 KiB
Python
# #region Test.Api.GitHelpers [C:3] [TYPE Module] [SEMANTICS test,git,helpers]
|
|
# @BRIEF Unit tests for git helper functions.
|
|
# @RELATION BINDS_TO -> [Api.Helpers.GitHelpers]
|
|
# @TEST_EDGE: no_repo_path
|
|
# @TEST_EDGE: config_not_found -> 404
|
|
# @TEST_EDGE: slug_not_found -> 404
|
|
# @TEST_EDGE: empty_ref -> 400
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
_src = str(Path(__file__).resolve().parent.parent.parent / "src")
|
|
if _src not in sys.path:
|
|
sys.path.insert(0, _src)
|
|
|
|
|
|
# ── _build_no_repo_status_payload ──
|
|
|
|
class TestBuildNoRepoStatusPayload:
|
|
def test_payload_structure(self):
|
|
from src.api.routes.git._helpers import _build_no_repo_status_payload
|
|
payload = _build_no_repo_status_payload()
|
|
assert payload["sync_status"] == "NO_REPO"
|
|
assert payload["has_repo"] is False
|
|
assert payload["is_dirty"] is False
|
|
assert payload["untracked_files"] == []
|
|
|
|
|
|
# ── _handle_unexpected_git_route_error ──
|
|
|
|
class TestHandleUnexpectedGitRouteError:
|
|
def test_raises_http_500(self):
|
|
from fastapi import HTTPException
|
|
from src.api.routes.git._helpers import _handle_unexpected_git_route_error
|
|
with pytest.raises(HTTPException) as exc:
|
|
_handle_unexpected_git_route_error("test_route", RuntimeError("boom"))
|
|
assert exc.value.status_code == 500
|
|
assert "test_route failed" in exc.value.detail
|
|
|
|
|
|
# ── _resolve_repository_status ──
|
|
|
|
class TestResolveRepositoryStatus:
|
|
@pytest.mark.asyncio
|
|
async def test_repo_path_exists(self):
|
|
mock_service = MagicMock()
|
|
mock_service._get_repo_path = AsyncMock(return_value="/tmp/some-repo")
|
|
mock_service.get_status = AsyncMock(return_value={"sync_status": "OK"})
|
|
|
|
with patch("src.api.routes.git._helpers.get_git_service", return_value=mock_service), \
|
|
patch("os.path.exists", return_value=True):
|
|
from src.api.routes.git._helpers import _resolve_repository_status
|
|
result = await _resolve_repository_status(42)
|
|
assert result["sync_status"] == "OK"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_repo_path_missing(self):
|
|
mock_service = MagicMock()
|
|
mock_service._get_repo_path = AsyncMock(return_value="/nonexistent")
|
|
|
|
with patch("src.api.routes.git._helpers.get_git_service", return_value=mock_service), \
|
|
patch("os.path.exists", return_value=False):
|
|
from src.api.routes.git._helpers import _resolve_repository_status
|
|
result = await _resolve_repository_status(42)
|
|
assert result["sync_status"] == "NO_REPO"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_returns_404(self):
|
|
from fastapi import HTTPException
|
|
|
|
mock_service = MagicMock()
|
|
mock_service._get_repo_path = AsyncMock(return_value="/tmp/repo")
|
|
mock_service.get_status = AsyncMock(side_effect=HTTPException(status_code=404, detail="No repo"))
|
|
|
|
with patch("src.api.routes.git._helpers.get_git_service", return_value=mock_service), \
|
|
patch("os.path.exists", return_value=True):
|
|
from src.api.routes.git._helpers import _resolve_repository_status
|
|
result = await _resolve_repository_status(42)
|
|
assert result["sync_status"] == "NO_REPO"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_raises_other_http(self):
|
|
from fastapi import HTTPException
|
|
|
|
mock_service = MagicMock()
|
|
mock_service._get_repo_path = AsyncMock(return_value="/tmp/repo")
|
|
mock_service.get_status = AsyncMock(side_effect=HTTPException(status_code=500, detail="Server error"))
|
|
|
|
with patch("src.api.routes.git._helpers.get_git_service", return_value=mock_service), \
|
|
patch("os.path.exists", return_value=True):
|
|
from src.api.routes.git._helpers import _resolve_repository_status
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_repository_status(42)
|
|
assert exc.value.status_code == 500
|
|
|
|
|
|
# ── _get_git_config_or_404 ──
|
|
|
|
class TestGetGitConfigOr404:
|
|
def test_config_found(self):
|
|
mock_db = MagicMock()
|
|
mock_db.query.return_value.filter.return_value.first.return_value = MagicMock(id="cfg-1")
|
|
|
|
from src.api.routes.git._helpers import _get_git_config_or_404
|
|
result = _get_git_config_or_404(mock_db, "cfg-1")
|
|
assert result is not None
|
|
|
|
def test_config_not_found(self):
|
|
from fastapi import HTTPException
|
|
mock_db = MagicMock()
|
|
mock_db.query.return_value.filter.return_value.first.return_value = None
|
|
|
|
from src.api.routes.git._helpers import _get_git_config_or_404
|
|
with pytest.raises(HTTPException) as exc:
|
|
_get_git_config_or_404(mock_db, "cfg-missing")
|
|
assert exc.value.status_code == 404
|
|
|
|
|
|
# ── _find_dashboard_id_by_slug (sync) ──
|
|
|
|
class TestFindDashboardIdBySlug:
|
|
@pytest.mark.asyncio
|
|
async def test_found(self):
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
from src.api.routes.git._helpers import _find_dashboard_id_by_slug
|
|
result = await _find_dashboard_id_by_slug(client, "my-slug")
|
|
assert result == 42
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_not_found(self):
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.return_value = (0, [])
|
|
|
|
from src.api.routes.git._helpers import _find_dashboard_id_by_slug
|
|
result = await _find_dashboard_id_by_slug(client, "ghost")
|
|
assert result is None
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_exception_then_second_query(self):
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.side_effect = [
|
|
Exception("Fail"),
|
|
(1, [{"id": 99}]),
|
|
]
|
|
|
|
from src.api.routes.git._helpers import _find_dashboard_id_by_slug
|
|
result = await _find_dashboard_id_by_slug(client, "retry")
|
|
assert result == 99
|
|
|
|
|
|
# ── _resolve_dashboard_id_from_ref (sync) ──
|
|
|
|
class TestResolveDashboardIdFromRef:
|
|
@pytest.mark.asyncio
|
|
async def test_numeric_ref(self):
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref
|
|
result = await _resolve_dashboard_id_from_ref("123", MagicMock())
|
|
assert result == 123
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_slug_ref(self):
|
|
mock_config = MagicMock()
|
|
env = MagicMock()
|
|
env.id = "env-1"
|
|
mock_config.get_environments.return_value = [env]
|
|
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
with patch("src.api.routes.git._helpers.SupersetClient", return_value=client):
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref
|
|
result = await _resolve_dashboard_id_from_ref("my-slug", mock_config, "env-1")
|
|
assert result == 42
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_empty_ref(self):
|
|
from fastapi import HTTPException
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_dashboard_id_from_ref("", MagicMock())
|
|
assert exc.value.status_code == 400
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_slug_no_env_id(self):
|
|
from fastapi import HTTPException
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_dashboard_id_from_ref("slug", MagicMock())
|
|
assert exc.value.status_code == 400
|
|
assert "env_id is required" in exc.value.detail
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_env_not_found(self):
|
|
from fastapi import HTTPException
|
|
mock_config = MagicMock()
|
|
mock_config.get_environments.return_value = []
|
|
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_dashboard_id_from_ref("slug", mock_config, "env-ghost")
|
|
assert exc.value.status_code == 404
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_slug_not_found(self):
|
|
from fastapi import HTTPException
|
|
mock_config = MagicMock()
|
|
env = MagicMock()
|
|
env.id = "env-1"
|
|
mock_config.get_environments.return_value = [env]
|
|
|
|
client = MagicMock()
|
|
client.get_dashboards_page.return_value = (0, [])
|
|
|
|
with patch("src.api.routes.git._helpers.SupersetClient", return_value=client):
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_dashboard_id_from_ref("ghost-slug", mock_config, "env-1")
|
|
assert exc.value.status_code == 404
|
|
|
|
|
|
# ── _find_dashboard_id_by_slug_async ──
|
|
|
|
class TestFindDashboardIdBySlugAsync:
|
|
@pytest.mark.asyncio
|
|
async def test_found(self):
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
|
|
from src.api.routes.git._helpers import _find_dashboard_id_by_slug_async
|
|
result = await _find_dashboard_id_by_slug_async(client, "slug")
|
|
assert result == 42
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_not_found(self):
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.return_value = (0, [])
|
|
|
|
from src.api.routes.git._helpers import _find_dashboard_id_by_slug_async
|
|
result = await _find_dashboard_id_by_slug_async(client, "ghost")
|
|
assert result is None
|
|
|
|
|
|
# ── _resolve_dashboard_id_from_ref_async ──
|
|
|
|
class TestResolveDashboardIdFromRefAsync:
|
|
@pytest.mark.asyncio
|
|
async def test_numeric_ref(self):
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref_async
|
|
result = await _resolve_dashboard_id_from_ref_async("123", MagicMock())
|
|
assert result == 123
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_slug_ref(self):
|
|
mock_config = MagicMock()
|
|
env = MagicMock()
|
|
env.id = "env-1"
|
|
mock_config.get_environments.return_value = [env]
|
|
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.return_value = (1, [{"id": 42}])
|
|
client.aclose = AsyncMock()
|
|
|
|
with patch("src.core.async_superset_client.AsyncSupersetClient", return_value=client):
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref_async
|
|
result = await _resolve_dashboard_id_from_ref_async("slug", mock_config, "env-1")
|
|
assert result == 42
|
|
client.aclose.assert_awaited_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_empty_ref(self):
|
|
from fastapi import HTTPException
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref_async
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_dashboard_id_from_ref_async("", MagicMock())
|
|
assert exc.value.status_code == 400
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_slug_not_found_async(self):
|
|
from fastapi import HTTPException
|
|
mock_config = MagicMock()
|
|
env = MagicMock()
|
|
env.id = "env-1"
|
|
mock_config.get_environments.return_value = [env]
|
|
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.return_value = (0, [])
|
|
client.aclose = AsyncMock()
|
|
|
|
with patch("src.core.async_superset_client.AsyncSupersetClient", return_value=client):
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref_async
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_dashboard_id_from_ref_async("ghost", mock_config, "env-1")
|
|
assert exc.value.status_code == 404
|
|
client.aclose.assert_awaited_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_no_env_id(self):
|
|
from fastapi import HTTPException
|
|
from src.api.routes.git._helpers import _resolve_dashboard_id_from_ref_async
|
|
with pytest.raises(HTTPException) as exc:
|
|
await _resolve_dashboard_id_from_ref_async("slug", MagicMock())
|
|
assert exc.value.status_code == 400
|
|
|
|
|
|
# ── _resolve_repo_key_from_ref ──
|
|
|
|
class TestResolveRepoKeyFromRef:
|
|
@pytest.mark.asyncio
|
|
async def test_slug_ref_returns_slug(self):
|
|
from src.api.routes.git._helpers import _resolve_repo_key_from_ref
|
|
result = await _resolve_repo_key_from_ref("my-dash", 42, MagicMock())
|
|
assert result == "my-dash"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_numeric_ref_returns_dashboard_id_fallback(self):
|
|
from src.api.routes.git._helpers import _resolve_repo_key_from_ref
|
|
result = await _resolve_repo_key_from_ref("123", 42, MagicMock())
|
|
assert result == "dashboard-42"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_numeric_ref_with_env_lookup(self):
|
|
mock_config = MagicMock()
|
|
env = MagicMock()
|
|
env.id = "env-1"
|
|
mock_config.get_environments.return_value = [env]
|
|
|
|
client = AsyncMock()
|
|
client.get_dashboard.return_value = {"result": {"slug": "real-slug"}}
|
|
|
|
with patch("src.api.routes.git._helpers.SupersetClient", return_value=client):
|
|
from src.api.routes.git._helpers import _resolve_repo_key_from_ref
|
|
result = await _resolve_repo_key_from_ref("123", 42, mock_config, "env-1")
|
|
assert result == "real-slug"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_env_lookup_fails_uses_fallback(self):
|
|
mock_config = MagicMock()
|
|
env = MagicMock()
|
|
env.id = "env-1"
|
|
mock_config.get_environments.return_value = [env]
|
|
|
|
client = MagicMock()
|
|
client.get_dashboard.side_effect = Exception("API error")
|
|
|
|
with patch("src.api.routes.git._helpers.SupersetClient", return_value=client):
|
|
from src.api.routes.git._helpers import _resolve_repo_key_from_ref
|
|
result = await _resolve_repo_key_from_ref("123", 42, mock_config, "env-1")
|
|
assert result == "dashboard-42"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_empty_ref_uses_fallback(self):
|
|
from src.api.routes.git._helpers import _resolve_repo_key_from_ref
|
|
result = await _resolve_repo_key_from_ref("", 42, MagicMock())
|
|
assert result == "dashboard-42"
|
|
|
|
|
|
# ── _sanitize_optional_identity_value ──
|
|
|
|
class TestSanitizeOptionalIdentityValue:
|
|
def test_none(self):
|
|
from src.api.routes.git._helpers import _sanitize_optional_identity_value
|
|
assert _sanitize_optional_identity_value(None) is None
|
|
|
|
def test_empty(self):
|
|
from src.api.routes.git._helpers import _sanitize_optional_identity_value
|
|
assert _sanitize_optional_identity_value("") is None
|
|
|
|
def test_whitespace(self):
|
|
from src.api.routes.git._helpers import _sanitize_optional_identity_value
|
|
assert _sanitize_optional_identity_value(" ") is None
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git._helpers import _sanitize_optional_identity_value
|
|
assert _sanitize_optional_identity_value(" alice ") == "alice"
|
|
|
|
|
|
# ── _resolve_current_user_git_identity ──
|
|
|
|
class TestResolveCurrentUserGitIdentity:
|
|
def test_db_is_none(self):
|
|
from src.api.routes.git._helpers import _resolve_current_user_git_identity
|
|
assert _resolve_current_user_git_identity(None, MagicMock()) is None
|
|
|
|
def test_no_user_id(self):
|
|
from src.api.routes.git._helpers import _resolve_current_user_git_identity
|
|
user = MagicMock()
|
|
user.id = None
|
|
assert _resolve_current_user_git_identity(MagicMock(), user) is None
|
|
|
|
def test_preference_found(self):
|
|
mock_db = MagicMock()
|
|
pref = MagicMock()
|
|
pref.git_username = "alice"
|
|
pref.git_email = "alice@example.com"
|
|
mock_db.query.return_value.filter.return_value.first.return_value = pref
|
|
|
|
user = MagicMock()
|
|
user.id = "user-1"
|
|
|
|
from src.api.routes.git._helpers import _resolve_current_user_git_identity
|
|
result = _resolve_current_user_git_identity(mock_db, user)
|
|
assert result == ("alice", "alice@example.com")
|
|
|
|
def test_preference_not_found(self):
|
|
mock_db = MagicMock()
|
|
mock_db.query.return_value.filter.return_value.first.return_value = None
|
|
|
|
user = MagicMock()
|
|
user.id = "user-1"
|
|
|
|
from src.api.routes.git._helpers import _resolve_current_user_git_identity
|
|
assert _resolve_current_user_git_identity(mock_db, user) is None
|
|
|
|
def test_preference_missing_git_fields(self):
|
|
mock_db = MagicMock()
|
|
pref = MagicMock()
|
|
pref.git_username = None
|
|
pref.git_email = None
|
|
mock_db.query.return_value.filter.return_value.first.return_value = pref
|
|
|
|
user = MagicMock()
|
|
user.id = "user-1"
|
|
|
|
from src.api.routes.git._helpers import _resolve_current_user_git_identity
|
|
assert _resolve_current_user_git_identity(mock_db, user) is None
|
|
|
|
def test_query_exception(self):
|
|
mock_db = MagicMock()
|
|
mock_db.query.return_value.filter.return_value.first.side_effect = Exception("DB error")
|
|
|
|
user = MagicMock()
|
|
user.id = "user-1"
|
|
|
|
from src.api.routes.git._helpers import _resolve_current_user_git_identity
|
|
assert _resolve_current_user_git_identity(mock_db, user) is None
|
|
|
|
def test_db_without_query_attr(self):
|
|
from src.api.routes.git._helpers import _resolve_current_user_git_identity
|
|
assert _resolve_current_user_git_identity(object(), MagicMock()) is None
|
|
|
|
|
|
# ── _apply_git_identity_from_profile ──
|
|
|
|
class TestApplyGitIdentityFromProfile:
|
|
@pytest.mark.asyncio
|
|
async def test_identity_resolved_and_applied(self):
|
|
mock_service = MagicMock()
|
|
mock_service.configure_identity = AsyncMock()
|
|
|
|
with patch("src.api.routes.git._helpers.get_git_service", return_value=mock_service), \
|
|
patch("src.api.routes.git._helpers._resolve_current_user_git_identity",
|
|
return_value=("alice", "alice@example.com")):
|
|
from src.api.routes.git._helpers import _apply_git_identity_from_profile
|
|
await _apply_git_identity_from_profile(42, MagicMock(), MagicMock())
|
|
mock_service.configure_identity.assert_awaited_once_with(42, "alice", "alice@example.com")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_identity_not_resolved(self):
|
|
with patch("src.api.routes.git._helpers._resolve_current_user_git_identity",
|
|
return_value=None):
|
|
from src.api.routes.git._helpers import _apply_git_identity_from_profile
|
|
# Should not raise
|
|
await _apply_git_identity_from_profile(42, MagicMock(), MagicMock())
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_service_has_no_configure_identity(self):
|
|
mock_service = MagicMock(spec=[]) # no configure_identity attribute
|
|
|
|
with patch("src.api.routes.git._helpers.get_git_service", return_value=mock_service), \
|
|
patch("src.api.routes.git._helpers._resolve_current_user_git_identity",
|
|
return_value=("alice", "alice@example.com")):
|
|
from src.api.routes.git._helpers import _apply_git_identity_from_profile
|
|
# Should not raise
|
|
await _apply_git_identity_from_profile(42, MagicMock(), MagicMock())
|
|
# #endregion Test.Api.GitHelpers
|
|
|
|
|
|
# #region Test.Api.GitHelpers.FinalBranches [C:3] [TYPE Module]
|
|
# @defgroup find-by-slug failure, repo-key slug resolution, sanitize, token decrypt, identity await.
|
|
|
|
from src.api.routes.git._helpers import (
|
|
_apply_git_identity_from_profile,
|
|
_find_dashboard_id_by_slug,
|
|
_resolve_current_user_git_token,
|
|
_sanitize_optional_identity_value,
|
|
_resolve_repo_key_from_ref,
|
|
)
|
|
|
|
|
|
class TestFindDashboardIdBySlugFailures:
|
|
@pytest.mark.asyncio
|
|
async def test_all_queries_fail_returns_none(self):
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.side_effect = RuntimeError("superset down")
|
|
result = await _find_dashboard_id_by_slug(client, "my-slug")
|
|
assert result is None
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_first_variant_fails_second_succeeds(self):
|
|
client = AsyncMock()
|
|
client.get_dashboards_page.side_effect = [
|
|
RuntimeError("bad op"),
|
|
(1, [{"id": 42}]),
|
|
]
|
|
result = await _find_dashboard_id_by_slug(client, "my-slug")
|
|
assert result == 42
|
|
# #endregion Test.Api.GitHelpers.FinalBranches.FindSlug
|
|
|
|
|
|
class TestResolveRepoKeyFromRefSlug:
|
|
@pytest.mark.asyncio
|
|
async def test_env_with_slug_returns_slug(self):
|
|
config_manager = MagicMock()
|
|
env = SimpleNamespace(id="env-1")
|
|
config_manager.get_environments.return_value = [env]
|
|
with patch("src.api.routes.git._helpers.SupersetClient") as client_cls:
|
|
client = AsyncMock()
|
|
client_cls.return_value = client
|
|
client.get_dashboard = AsyncMock(return_value={"result": {"slug": "my-slug"}})
|
|
result = await _resolve_repo_key_from_ref("", 5, config_manager, env_id="env-1")
|
|
assert result == "my-slug"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_env_lookup_failure_falls_back(self):
|
|
config_manager = MagicMock()
|
|
config_manager.get_environments.side_effect = RuntimeError("cfg down")
|
|
result = await _resolve_repo_key_from_ref("", 5, config_manager, env_id="env-1")
|
|
assert result == "dashboard-5"
|
|
# #endregion Test.Api.GitHelpers.FinalBranches.RepoKey
|
|
|
|
|
|
class TestSanitizeOptionalIdentityValue:
|
|
def test_non_string_int_returns_none(self):
|
|
assert _sanitize_optional_identity_value(3.14) is None
|
|
assert _sanitize_optional_identity_value(["x"]) is None
|
|
|
|
def test_blank_returns_none(self):
|
|
assert _sanitize_optional_identity_value(" ") is None
|
|
assert _sanitize_optional_identity_value("") is None
|
|
# #endregion Test.Api.GitHelpers.FinalBranches.Sanitize
|
|
|
|
|
|
class TestResolveCurrentUserGitToken:
|
|
def test_db_none_returns_none(self):
|
|
assert _resolve_current_user_git_token(None, SimpleNamespace(id="u1")) is None
|
|
|
|
def test_decrypt_failure_returns_none(self):
|
|
db = MagicMock()
|
|
pref = MagicMock()
|
|
pref.git_personal_access_token_encrypted = "encrypted"
|
|
db.query.return_value.filter.return_value.first.return_value = pref
|
|
with patch("src.api.routes.git._helpers.EncryptionManager") as enc_cls:
|
|
enc_cls.return_value.decrypt.side_effect = RuntimeError("bad key")
|
|
result = _resolve_current_user_git_token(db, SimpleNamespace(id="u1"))
|
|
assert result is None
|
|
|
|
def test_decrypt_success(self):
|
|
db = MagicMock()
|
|
pref = MagicMock()
|
|
pref.git_personal_access_token_encrypted = "encrypted"
|
|
db.query.return_value.filter.return_value.first.return_value = pref
|
|
with patch("src.api.routes.git._helpers.EncryptionManager") as enc_cls:
|
|
enc_cls.return_value.decrypt.return_value = "pat-1"
|
|
result = _resolve_current_user_git_token(db, SimpleNamespace(id="u1"))
|
|
assert result == "pat-1"
|
|
# #endregion Test.Api.GitHelpers.FinalBranches.Token
|
|
|
|
|
|
class TestApplyGitIdentityAwait:
|
|
@pytest.mark.asyncio
|
|
async def test_awaitable_identity_result(self):
|
|
configure = AsyncMock()
|
|
service = MagicMock()
|
|
service.configure_identity = configure
|
|
with patch("src.api.routes.git._helpers.get_git_service", return_value=service), \
|
|
patch("src.api.routes.git._helpers._resolve_current_user_git_identity", return_value=("name", "email")):
|
|
await _apply_git_identity_from_profile(5, MagicMock(), SimpleNamespace(id="u1"))
|
|
configure.assert_awaited_once_with(5, "name", "email")
|
|
# #endregion Test.Api.GitHelpers.FinalBranches.Identity
|