feat(projects): automate project infrastructure provisioning
Generic Container CI/CD / test-build-publish (push) Successful in 1m13s
Server CI/CD v2 / build-test-publish-and-deploy (push) Successful in 1m13s

This commit is contained in:
2026-09-11 10:57:51 +08:00
parent 10a7a66a41
commit 90b02057bc
38 changed files with 2345 additions and 189 deletions
@@ -5,6 +5,7 @@ from uuid import uuid4
import pytest
from sqlalchemy.dialects import postgresql
from app.infra.db.metadb.repositories import metadata_repository
from app.infra.db.metadb.repositories.metadata_repository import MetadataRepository
@@ -49,3 +50,38 @@ async def test_list_projects_for_user_only_queries_active_projects():
assert "user_project_membership.user_id" in sql
assert "projects.status = 'active'" in sql
assert [item.code for item in projects] == ["active-project"]
@pytest.mark.anyio
async def test_create_provisioned_project_commits_project_routes_and_membership_once(
monkeypatch,
):
added = []
session = SimpleNamespace(
add=added.append,
commit=AsyncMock(),
refresh=AsyncMock(),
)
monkeypatch.setattr(
metadata_repository,
"_encrypt_database_secret",
lambda value: f"encrypted::{value}",
)
user_id = uuid4()
project = await MetadataRepository(session).create_provisioned_project(
name="Demo",
code="demo",
description=None,
gs_workspace="demo",
map_extent={"bbox": [1, 2, 3, 4], "zoom": 14},
creator_user_id=user_id,
business_dsn="postgresql://business/demo",
timescale_dsn="postgresql://timescale/demo",
)
assert project.status == "active"
assert [record.db_role for record in added[1:3]] == ["biz_data", "iot_data"]
assert added[3].user_id == user_id
session.commit.assert_awaited_once()
session.refresh.assert_awaited_once_with(project)