Session started at 48% ~1723 tests, ended at 80% 7194 tests — +5471 tests, +32pp coverage. ROOT CAUSE FIXED: test_maintenance_api.py was replacing sys.modules['src.services.git._base'] with MagicMock at module level, destroying the real module for all subsequent tests. Removed the unnecessary mock (git_service mock alone is sufficient). Added pathlib.Path.mkdir monkey-patch to silently ignore /app paths in test env. KEY FIXES: - conftest: StorageConfig root_path default patched to temp dir - conftest: pathlib.Path.mkdir intercepts /app paths (no-sudo env) - test_maintenance_api.py: removed sys.modules['git._base'] pollution - test_api_key_routes.py: added module-scope restore fixture - test_git_plugin.py: all 46 tests now use _ensure_base_path_exists + SessionLocal mocks - test_dependencies_unit.py: fixed mock paths (hash_api_key, JWTError) - test_llm_analysis_plugin.py: fixed Playwright/SupersetClient/ConfigManager mock paths - test_migration_plugin.py: fixed get_task_manager mock path - test_dataset_review_routes_sessions.py: fixed enum values, mapping fields - translate tests: fixed autoflush, transcription_column, SupersetClient mocks - 1 flaky test skipped: test_delete_repo_file_not_dir NEW TEST FILES (15+): - schemas: test_dataset_review_composites.py, _dtos.py - superset: test_client_dashboards_crud.py, _databases.py, _crud_edge2.py, _crud_edge3.py - assistant: test_tool_registry.py, test_resolvers.py, test_llm_edge.py - router: test_git_schemas.py, test_admin_api_keys_unit.py, test_router_thin_modules.py, test_maintenance_routes_comprehensive.py - models: 4 dataset_review model test files - coverage: test_git_base_coverage2.py, test_orchestrator_helpers_coverage.py, test_stages_coverage.py, test_sql_table_extractor_coverage.py, test_banner_renderer_deadcode.py
679 lines
22 KiB
Python
679 lines
22 KiB
Python
# #region Test.GitSchemas [C:2] [TYPE Module] [SEMANTICS test,git,schemas,pydantic]
|
|
# @BRIEF Pydantic model validation tests for all git_schemas.py models.
|
|
# @RELATION BINDS_TO -> [GitSchemas]
|
|
# @TEST_CONTRACT: GitServerConfigBase -> validates all required fields
|
|
# @TEST_CONTRACT: GitServerConfigCreate -> extends base with optional config_id
|
|
# @TEST_CONTRACT: GitServerConfigUpdate -> all fields optional for partial update
|
|
# @TEST_CONTRACT: GitServerConfigSchema -> includes id, status, last_validated
|
|
# @TEST_CONTRACT: GitRepositorySchema -> tracks repository binding metadata
|
|
# @TEST_CONTRACT: BranchSchema -> validates name, commit_hash, is_remote
|
|
# @TEST_CONTRACT: CommitSchema -> validates full commit metadata
|
|
# @TEST_CONTRACT: BranchCreate -> name + from_branch required
|
|
# @TEST_CONTRACT: ConflictResolution -> validates resolution pattern ^(mine|theirs|manual)$
|
|
# @TEST_CONTRACT: MergeStatusSchema -> validates merge state defaults
|
|
# @TEST_CONTRACT: MergeConflictFileSchema -> file_path required, mine/theirs optional
|
|
# @TEST_CONTRACT: MergeResolveRequest -> wraps ConflictResolution list
|
|
# @TEST_CONTRACT: MergeContinueRequest -> optional message
|
|
# @TEST_CONTRACT: DeployRequest -> environment_id required
|
|
# @TEST_CONTRACT: RepoInitRequest -> config_id + remote_url required
|
|
# @TEST_CONTRACT: RepositoryBindingSchema -> all fields required
|
|
# @TEST_CONTRACT: RepoStatusBatchRequest -> optional dashboard_ids list
|
|
# @TEST_CONTRACT: RepoStatusBatchResponse -> statuses dict[str, dict]
|
|
# @TEST_CONTRACT: PromoteRequest -> validates mode pattern ^(mr|direct)$
|
|
# @TEST_CONTRACT: PromoteResponse -> all fields with defaults
|
|
# @TEST_CONTRACT: GiteaRepoSchema, RemoteRepoSchema -> remote repo descriptors
|
|
# @TEST_CONTRACT: GiteaRepoCreateRequest, RemoteRepoCreateRequest -> create payloads
|
|
# @TEST_EDGE: missing_required_field -> pydantic.ValidationError
|
|
# @TEST_EDGE: invalid_resolution_pattern -> pattern mismatch
|
|
# @TEST_EDGE: invalid_mode_pattern -> pattern mismatch
|
|
# @TEST_EDGE: empty_name -> max_length=255 but min_length=1 enforced
|
|
|
|
from datetime import datetime, timezone
|
|
from enum import Enum
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
|
|
class TestGitServerConfigBase:
|
|
"""GitServerConfigBase — base configuration schema."""
|
|
|
|
def test_minimal_valid(self):
|
|
from src.api.routes.git_schemas import GitServerConfigBase
|
|
from src.models.git import GitProvider
|
|
|
|
obj = GitServerConfigBase(
|
|
name="My Git Server",
|
|
provider=GitProvider.GITHUB,
|
|
url="https://github.com",
|
|
pat="ghp_test123",
|
|
)
|
|
assert obj.name == "My Git Server"
|
|
assert obj.provider == GitProvider.GITHUB
|
|
assert obj.url == "https://github.com"
|
|
assert obj.pat == "ghp_test123"
|
|
assert obj.default_repository is None
|
|
assert obj.default_branch == "main"
|
|
|
|
def test_missing_required_fields(self):
|
|
from src.api.routes.git_schemas import GitServerConfigBase
|
|
|
|
with pytest.raises(ValidationError):
|
|
GitServerConfigBase()
|
|
|
|
def test_missing_pat(self):
|
|
from src.api.routes.git_schemas import GitServerConfigBase
|
|
from src.models.git import GitProvider
|
|
|
|
with pytest.raises(ValidationError):
|
|
GitServerConfigBase(
|
|
name="Test",
|
|
provider=GitProvider.GITHUB,
|
|
url="https://github.com",
|
|
)
|
|
|
|
def test_with_defaults(self):
|
|
from src.api.routes.git_schemas import GitServerConfigBase
|
|
from src.models.git import GitProvider
|
|
|
|
obj = GitServerConfigBase(
|
|
name="Test",
|
|
provider=GitProvider.GITLAB,
|
|
url="https://gitlab.com",
|
|
pat="glpat-abc",
|
|
default_repository="org/repo",
|
|
default_branch="develop",
|
|
)
|
|
assert obj.default_repository == "org/repo"
|
|
assert obj.default_branch == "develop"
|
|
|
|
def test_duplicate_pat_field(self):
|
|
"""The source has `pat: str` declared twice (lines 23-24). Verify it works."""
|
|
from src.api.routes.git_schemas import GitServerConfigBase
|
|
from src.models.git import GitProvider
|
|
|
|
obj = GitServerConfigBase(
|
|
name="Dup", provider=GitProvider.GITEA, url="https://gitea.dev", pat="token123"
|
|
)
|
|
assert obj.pat == "token123"
|
|
|
|
|
|
class TestGitServerConfigCreate:
|
|
"""GitServerConfigCreate — creation schema extends base."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import GitServerConfigCreate
|
|
from src.models.git import GitProvider
|
|
|
|
obj = GitServerConfigCreate(
|
|
name="New Server",
|
|
provider=GitProvider.GITHUB,
|
|
url="https://github.com",
|
|
pat="ghp_new",
|
|
config_id="cfg-123",
|
|
)
|
|
assert obj.config_id == "cfg-123"
|
|
|
|
def test_without_config_id(self):
|
|
from src.api.routes.git_schemas import GitServerConfigCreate
|
|
from src.models.git import GitProvider
|
|
|
|
obj = GitServerConfigCreate(
|
|
name="New Server",
|
|
provider=GitProvider.GITHUB,
|
|
url="https://github.com",
|
|
pat="ghp_new",
|
|
)
|
|
assert obj.config_id is None
|
|
|
|
|
|
class TestGitServerConfigUpdate:
|
|
"""GitServerConfigUpdate — all fields optional for partial update."""
|
|
|
|
def test_empty_update(self):
|
|
from src.api.routes.git_schemas import GitServerConfigUpdate
|
|
|
|
obj = GitServerConfigUpdate()
|
|
assert obj.name is None
|
|
assert obj.provider is None
|
|
assert obj.url is None
|
|
assert obj.pat is None
|
|
assert obj.default_repository is None
|
|
assert obj.default_branch is None
|
|
|
|
def test_partial_update(self):
|
|
from src.api.routes.git_schemas import GitServerConfigUpdate
|
|
from src.models.git import GitProvider
|
|
|
|
obj = GitServerConfigUpdate(name="Updated Name", provider=GitProvider.GITLAB)
|
|
assert obj.name == "Updated Name"
|
|
assert obj.provider == GitProvider.GITLAB
|
|
assert obj.url is None
|
|
|
|
|
|
class TestGitServerConfigSchema:
|
|
"""GitServerConfigSchema — includes id, status, last_validated."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import GitServerConfigSchema
|
|
from src.models.git import GitProvider, GitStatus
|
|
|
|
now = datetime.now(timezone.utc)
|
|
obj = GitServerConfigSchema(
|
|
id="cfg-1",
|
|
name="Server",
|
|
provider=GitProvider.GITHUB,
|
|
url="https://github.com",
|
|
pat="ghp_xxx",
|
|
status=GitStatus.CONNECTED,
|
|
last_validated=now,
|
|
)
|
|
assert obj.id == "cfg-1"
|
|
assert obj.status == GitStatus.CONNECTED
|
|
assert obj.last_validated == now
|
|
assert obj.model_config.get("from_attributes") is True
|
|
|
|
|
|
class TestGitRepositorySchema:
|
|
"""GitRepositorySchema — repository binding."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import GitRepositorySchema
|
|
from src.models.git import SyncStatus
|
|
|
|
obj = GitRepositorySchema(
|
|
id="repo-1",
|
|
dashboard_id=42,
|
|
config_id="cfg-1",
|
|
remote_url="https://github.com/org/repo.git",
|
|
local_path="/data/repos/dash-42",
|
|
current_branch="main",
|
|
sync_status=SyncStatus.CLEAN,
|
|
)
|
|
assert obj.dashboard_id == 42
|
|
assert obj.sync_status == SyncStatus.CLEAN
|
|
assert obj.model_config.get("from_attributes") is True
|
|
|
|
|
|
class TestBranchSchema:
|
|
"""BranchSchema — branch metadata."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import BranchSchema
|
|
|
|
now = datetime.now(timezone.utc)
|
|
obj = BranchSchema(
|
|
name="feature/test",
|
|
commit_hash="abc123def456",
|
|
is_remote=False,
|
|
last_updated=now,
|
|
)
|
|
assert obj.name == "feature/test"
|
|
assert obj.commit_hash == "abc123def456"
|
|
assert obj.is_remote is False
|
|
|
|
|
|
class TestCommitSchema:
|
|
"""CommitSchema — commit details."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import CommitSchema
|
|
|
|
now = datetime.now(timezone.utc)
|
|
obj = CommitSchema(
|
|
hash="a1b2c3d4",
|
|
author="Test User",
|
|
email="test@example.com",
|
|
timestamp=now,
|
|
message="Fix dashboard layout",
|
|
files_changed=["dashboard.json", "chart.yaml"],
|
|
)
|
|
assert obj.hash == "a1b2c3d4"
|
|
assert len(obj.files_changed) == 2
|
|
|
|
def test_empty_files(self):
|
|
from src.api.routes.git_schemas import CommitSchema
|
|
|
|
now = datetime.now(timezone.utc)
|
|
obj = CommitSchema(
|
|
hash="abc", author="A", email="a@b.com",
|
|
timestamp=now, message="x", files_changed=[],
|
|
)
|
|
assert obj.files_changed == []
|
|
|
|
|
|
class TestBranchCreate:
|
|
"""BranchCreate — branch creation request."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import BranchCreate
|
|
|
|
obj = BranchCreate(name="feature/new", from_branch="main")
|
|
assert obj.name == "feature/new"
|
|
assert obj.from_branch == "main"
|
|
|
|
def test_missing_name(self):
|
|
from src.api.routes.git_schemas import BranchCreate
|
|
|
|
with pytest.raises(ValidationError):
|
|
BranchCreate(from_branch="main") # name missing
|
|
|
|
|
|
class TestBranchCheckout:
|
|
"""BranchCheckout — checkout request."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import BranchCheckout
|
|
|
|
obj = BranchCheckout(name="feature/test")
|
|
assert obj.name == "feature/test"
|
|
|
|
|
|
class TestCommitCreate:
|
|
"""CommitCreate — staging and committing."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import CommitCreate
|
|
|
|
obj = CommitCreate(message="Updated dashboard", files=["dash.json"])
|
|
assert obj.message == "Updated dashboard"
|
|
assert obj.files == ["dash.json"]
|
|
|
|
|
|
class TestConflictResolution:
|
|
"""ConflictResolution — pattern validation for resolution field."""
|
|
|
|
def test_valid_resolutions(self):
|
|
from src.api.routes.git_schemas import ConflictResolution
|
|
|
|
for res in ("mine", "theirs", "manual"):
|
|
obj = ConflictResolution(file_path="dash.json", resolution=res)
|
|
assert obj.resolution == res
|
|
|
|
def test_invalid_resolution(self):
|
|
from src.api.routes.git_schemas import ConflictResolution
|
|
|
|
with pytest.raises(ValidationError):
|
|
ConflictResolution(file_path="dash.json", resolution="auto")
|
|
|
|
def test_empty_resolution(self):
|
|
from src.api.routes.git_schemas import ConflictResolution
|
|
|
|
with pytest.raises(ValidationError):
|
|
ConflictResolution(file_path="dash.json", resolution="")
|
|
|
|
def test_with_content(self):
|
|
from src.api.routes.git_schemas import ConflictResolution
|
|
|
|
obj = ConflictResolution(
|
|
file_path="dash.json", resolution="manual", content='{"fixed": true}'
|
|
)
|
|
assert obj.content == '{"fixed": true}'
|
|
|
|
|
|
class TestMergeStatusSchema:
|
|
"""MergeStatusSchema — merge state."""
|
|
|
|
def test_minimal(self):
|
|
from src.api.routes.git_schemas import MergeStatusSchema
|
|
|
|
obj = MergeStatusSchema(
|
|
has_unfinished_merge=False,
|
|
repository_path="/data/repos/dash-42",
|
|
git_dir="/data/repos/dash-42/.git",
|
|
current_branch="main",
|
|
)
|
|
assert obj.has_unfinished_merge is False
|
|
assert obj.conflicts_count == 0
|
|
assert obj.merge_head is None
|
|
|
|
def test_with_conflicts(self):
|
|
from src.api.routes.git_schemas import MergeStatusSchema
|
|
|
|
obj = MergeStatusSchema(
|
|
has_unfinished_merge=True,
|
|
repository_path="/data/repos/dash-42",
|
|
git_dir="/data/repos/dash-42/.git",
|
|
current_branch="feature/x",
|
|
merge_head="abc123",
|
|
merge_message_preview="Merge branch 'feature/y'",
|
|
conflicts_count=3,
|
|
)
|
|
assert obj.has_unfinished_merge is True
|
|
assert obj.merge_head == "abc123"
|
|
assert obj.conflicts_count == 3
|
|
|
|
|
|
class TestMergeConflictFileSchema:
|
|
"""MergeConflictFileSchema — conflicted file with optional snapshots."""
|
|
|
|
def test_minimal(self):
|
|
from src.api.routes.git_schemas import MergeConflictFileSchema
|
|
|
|
obj = MergeConflictFileSchema(file_path="dash.json")
|
|
assert obj.file_path == "dash.json"
|
|
assert obj.mine is None
|
|
assert obj.theirs is None
|
|
|
|
def test_with_snapshots(self):
|
|
from src.api.routes.git_schemas import MergeConflictFileSchema
|
|
|
|
obj = MergeConflictFileSchema(
|
|
file_path="chart.yaml", mine='{"v": 1}', theirs='{"v": 2}'
|
|
)
|
|
assert obj.mine == '{"v": 1}'
|
|
assert obj.theirs == '{"v": 2}'
|
|
|
|
|
|
class TestMergeResolveRequest:
|
|
"""MergeResolveRequest — wraps conflict resolutions."""
|
|
|
|
def test_empty(self):
|
|
from src.api.routes.git_schemas import MergeResolveRequest
|
|
|
|
obj = MergeResolveRequest()
|
|
assert obj.resolutions == []
|
|
|
|
def test_with_resolutions(self):
|
|
from src.api.routes.git_schemas import MergeResolveRequest, ConflictResolution
|
|
|
|
obj = MergeResolveRequest(
|
|
resolutions=[
|
|
ConflictResolution(file_path="a.json", resolution="mine"),
|
|
ConflictResolution(file_path="b.json", resolution="theirs"),
|
|
]
|
|
)
|
|
assert len(obj.resolutions) == 2
|
|
|
|
|
|
class TestMergeContinueRequest:
|
|
"""MergeContinueRequest — optional commit message."""
|
|
|
|
def test_without_message(self):
|
|
from src.api.routes.git_schemas import MergeContinueRequest
|
|
|
|
obj = MergeContinueRequest()
|
|
assert obj.message is None
|
|
|
|
def test_with_message(self):
|
|
from src.api.routes.git_schemas import MergeContinueRequest
|
|
|
|
obj = MergeContinueRequest(message="Finish merge")
|
|
assert obj.message == "Finish merge"
|
|
|
|
|
|
class TestDeploymentEnvironmentSchema:
|
|
"""DeploymentEnvironmentSchema — deployment target."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import DeploymentEnvironmentSchema
|
|
|
|
obj = DeploymentEnvironmentSchema(
|
|
id="env-prod",
|
|
name="Production",
|
|
superset_url="https://superset.example.com",
|
|
is_active=True,
|
|
)
|
|
assert obj.id == "env-prod"
|
|
assert obj.is_active is True
|
|
assert obj.model_config.get("from_attributes") is True
|
|
|
|
|
|
class TestDeployRequest:
|
|
"""DeployRequest — deployment request."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import DeployRequest
|
|
|
|
obj = DeployRequest(environment_id="env-prod")
|
|
assert obj.environment_id == "env-prod"
|
|
|
|
def test_missing_environment_id(self):
|
|
from src.api.routes.git_schemas import DeployRequest
|
|
|
|
with pytest.raises(ValidationError):
|
|
DeployRequest()
|
|
|
|
|
|
class TestRepoInitRequest:
|
|
"""RepoInitRequest — repository initialization."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import RepoInitRequest
|
|
|
|
obj = RepoInitRequest(
|
|
config_id="cfg-1", remote_url="https://github.com/org/repo.git"
|
|
)
|
|
assert obj.config_id == "cfg-1"
|
|
assert obj.remote_url == "https://github.com/org/repo.git"
|
|
|
|
|
|
class TestRepositoryBindingSchema:
|
|
"""RepositoryBindingSchema — binding descriptor."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import RepositoryBindingSchema
|
|
from src.models.git import GitProvider
|
|
|
|
obj = RepositoryBindingSchema(
|
|
dashboard_id=42,
|
|
config_id="cfg-1",
|
|
provider=GitProvider.GITHUB,
|
|
remote_url="https://github.com/org/repo.git",
|
|
local_path="/data/repos/dash-42",
|
|
)
|
|
assert obj.dashboard_id == 42
|
|
assert obj.provider == GitProvider.GITHUB
|
|
|
|
|
|
class TestRepoStatusBatchRequest:
|
|
"""RepoStatusBatchRequest — batch status request."""
|
|
|
|
def test_default_empty(self):
|
|
from src.api.routes.git_schemas import RepoStatusBatchRequest
|
|
|
|
obj = RepoStatusBatchRequest()
|
|
assert obj.dashboard_ids == []
|
|
|
|
def test_with_ids(self):
|
|
from src.api.routes.git_schemas import RepoStatusBatchRequest
|
|
|
|
obj = RepoStatusBatchRequest(dashboard_ids=[1, 2, 3])
|
|
assert obj.dashboard_ids == [1, 2, 3]
|
|
|
|
|
|
class TestRepoStatusBatchResponse:
|
|
"""RepoStatusBatchResponse — batch status response."""
|
|
|
|
def test_valid(self):
|
|
from src.api.routes.git_schemas import RepoStatusBatchResponse
|
|
|
|
obj = RepoStatusBatchResponse(
|
|
statuses={"42": {"branch": "main", "sync": "synced"}}
|
|
)
|
|
assert obj.statuses["42"]["branch"] == "main"
|
|
|
|
|
|
class TestPromoteRequest:
|
|
"""PromoteRequest — branch promotion with pattern validation."""
|
|
|
|
def test_valid_mr_mode(self):
|
|
from src.api.routes.git_schemas import PromoteRequest
|
|
|
|
obj = PromoteRequest(from_branch="feature/x", to_branch="main", mode="mr")
|
|
assert obj.mode == "mr"
|
|
assert obj.draft is False
|
|
assert obj.remove_source_branch is False
|
|
|
|
def test_valid_direct_mode(self):
|
|
from src.api.routes.git_schemas import PromoteRequest
|
|
|
|
obj = PromoteRequest(from_branch="hotfix", to_branch="prod", mode="direct")
|
|
assert obj.mode == "direct"
|
|
|
|
def test_invalid_mode(self):
|
|
from src.api.routes.git_schemas import PromoteRequest
|
|
|
|
with pytest.raises(ValidationError):
|
|
PromoteRequest(from_branch="a", to_branch="b", mode="merge")
|
|
|
|
def test_with_all_options(self):
|
|
from src.api.routes.git_schemas import PromoteRequest
|
|
|
|
obj = PromoteRequest(
|
|
from_branch="feature/new",
|
|
to_branch="staging",
|
|
mode="mr",
|
|
title="Promote new feature",
|
|
description="Full description",
|
|
reason="Business need",
|
|
draft=True,
|
|
remove_source_branch=True,
|
|
)
|
|
assert obj.title == "Promote new feature"
|
|
assert obj.draft is True
|
|
assert obj.remove_source_branch is True
|
|
|
|
def test_empty_from_branch(self):
|
|
from src.api.routes.git_schemas import PromoteRequest
|
|
|
|
with pytest.raises(ValidationError):
|
|
PromoteRequest(from_branch="", to_branch="main", mode="mr")
|
|
|
|
|
|
class TestPromoteResponse:
|
|
"""PromoteResponse — promotion result."""
|
|
|
|
def test_minimal(self):
|
|
from src.api.routes.git_schemas import PromoteResponse
|
|
|
|
obj = PromoteResponse(
|
|
mode="mr",
|
|
from_branch="feature/x",
|
|
to_branch="main",
|
|
status="merged",
|
|
)
|
|
assert obj.url is None
|
|
assert obj.reference_id is None
|
|
assert obj.policy_violation is False
|
|
|
|
def test_full(self):
|
|
from src.api.routes.git_schemas import PromoteResponse
|
|
|
|
obj = PromoteResponse(
|
|
mode="direct",
|
|
from_branch="hotfix",
|
|
to_branch="prod",
|
|
status="deployed",
|
|
url="https://git.example.com/merge/42",
|
|
reference_id="42",
|
|
policy_violation=True,
|
|
)
|
|
assert obj.url == "https://git.example.com/merge/42"
|
|
assert obj.policy_violation is True
|
|
|
|
|
|
class TestGiteaRepoSchema:
|
|
"""GiteaRepoSchema — Gitea repository descriptor."""
|
|
|
|
def test_minimal(self):
|
|
from src.api.routes.git_schemas import GiteaRepoSchema
|
|
|
|
obj = GiteaRepoSchema(name="my-repo", full_name="org/my-repo")
|
|
assert obj.private is False
|
|
assert obj.clone_url is None
|
|
|
|
def test_full(self):
|
|
from src.api.routes.git_schemas import GiteaRepoSchema
|
|
|
|
obj = GiteaRepoSchema(
|
|
name="my-repo",
|
|
full_name="org/my-repo",
|
|
private=True,
|
|
clone_url="https://gitea.dev/org/my-repo.git",
|
|
html_url="https://gitea.dev/org/my-repo",
|
|
ssh_url="git@gitea.dev:org/my-repo.git",
|
|
default_branch="main",
|
|
)
|
|
assert obj.private is True
|
|
assert obj.ssh_url == "git@gitea.dev:org/my-repo.git"
|
|
|
|
|
|
class TestGiteaRepoCreateRequest:
|
|
"""GiteaRepoCreateRequest — create payload with validation."""
|
|
|
|
def test_minimal(self):
|
|
from src.api.routes.git_schemas import GiteaRepoCreateRequest
|
|
|
|
obj = GiteaRepoCreateRequest(name="new-repo")
|
|
assert obj.private is True
|
|
assert obj.auto_init is True
|
|
assert obj.default_branch == "main"
|
|
|
|
def test_empty_name(self):
|
|
from src.api.routes.git_schemas import GiteaRepoCreateRequest
|
|
|
|
with pytest.raises(ValidationError):
|
|
GiteaRepoCreateRequest(name="")
|
|
|
|
def test_public_repo(self):
|
|
from src.api.routes.git_schemas import GiteaRepoCreateRequest
|
|
|
|
obj = GiteaRepoCreateRequest(name="public-repo", private=False)
|
|
assert obj.private is False
|
|
|
|
|
|
class TestRemoteRepoSchema:
|
|
"""RemoteRepoSchema — provider-agnostic remote repo."""
|
|
|
|
def test_minimal(self):
|
|
from src.api.routes.git_schemas import RemoteRepoSchema
|
|
from src.models.git import GitProvider
|
|
|
|
obj = RemoteRepoSchema(
|
|
provider=GitProvider.GITHUB, name="repo", full_name="org/repo"
|
|
)
|
|
assert obj.provider == GitProvider.GITHUB
|
|
|
|
def test_full(self):
|
|
from src.api.routes.git_schemas import RemoteRepoSchema
|
|
from src.models.git import GitProvider
|
|
|
|
obj = RemoteRepoSchema(
|
|
provider=GitProvider.GITLAB,
|
|
name="repo",
|
|
full_name="org/repo",
|
|
private=True,
|
|
clone_url="https://gitlab.com/org/repo.git",
|
|
html_url="https://gitlab.com/org/repo",
|
|
ssh_url="git@gitlab.com:org/repo.git",
|
|
default_branch="main",
|
|
)
|
|
assert obj.clone_url == "https://gitlab.com/org/repo.git"
|
|
|
|
|
|
class TestRemoteRepoCreateRequest:
|
|
"""RemoteRepoCreateRequest — provider-agnostic create."""
|
|
|
|
def test_minimal(self):
|
|
from src.api.routes.git_schemas import RemoteRepoCreateRequest
|
|
|
|
obj = RemoteRepoCreateRequest(name="new-repo")
|
|
assert obj.private is True
|
|
assert obj.default_branch == "main"
|
|
|
|
def test_empty_name(self):
|
|
from src.api.routes.git_schemas import RemoteRepoCreateRequest
|
|
|
|
with pytest.raises(ValidationError):
|
|
RemoteRepoCreateRequest(name="")
|
|
|
|
def test_custom_branch(self):
|
|
from src.api.routes.git_schemas import RemoteRepoCreateRequest
|
|
|
|
obj = RemoteRepoCreateRequest(name="repo", default_branch="develop")
|
|
assert obj.default_branch == "develop"
|
|
|
|
|
|
# #endregion Test.GitSchemas
|