Systematic rename of all semantic anchors (#region, [DEF], @RELATION) across 1400+ files — backend Python, frontend Svelte/TS, specs, docs: - Flat anchors become Namespace.Module.Entity - @RELATION references updated to match new anchor paths - Zero business logic changes
238 lines
11 KiB
Python
238 lines
11 KiB
Python
# #region Test.Integration.FixtureIsolation [C:4] [TYPE Module] [SEMANTICS test,integration,fixtures,isolation,cleanup]
|
|
# @BRIEF Focused regression tests for database factory isolation, db_session commit/rollback
|
|
# boundaries, and cleanup behavior of superset_client and superset_admin_session.
|
|
# @RELATION BINDS_TO -> [Test.Postgres.Fixtures]
|
|
# @RELATION BINDS_TO -> [Test.Superset.Fixtures]
|
|
# @RELATION BINDS_TO -> [Test.Network.Fixtures]
|
|
# @RELATION BINDS_TO -> [Test.Pki.PKIFixtures]
|
|
# @RELATION DEPENDS_ON -> [Test.Conftest.IntegrationTestConftest]
|
|
#
|
|
# @TEST_CONTRACT FixtureIsolation ->
|
|
# {
|
|
# invariants: [
|
|
# "db_session rolls back uncommitted changes after test",
|
|
# "db_factory creates isolated databases that are dropped at session end",
|
|
# "db_factory databases have unique names with UUID suffix",
|
|
# "superset_client is always closed after test",
|
|
# "superset_admin_session is always closed after test"
|
|
# ]
|
|
# }
|
|
# @TEST_EDGE: db_session_rollback_isolation -> uncommitted insert from test A not visible in test B
|
|
# @TEST_EDGE: db_session_explicit_commit -> committed insert persists within same test
|
|
# @TEST_EDGE: db_factory_uniqueness -> consecutive create_db calls produce different database names
|
|
# @TEST_EDGE: db_factory_database_existence -> created database actually exists in PostgreSQL
|
|
#
|
|
# @TEST_INVARIANT db_session_isolated_per_test -> VERIFIED_BY: [test_db_session_rolls_back_uncommitted]
|
|
# @TEST_INVARIANT db_factory_databases_dropped -> VERIFIED_BY: [Test.Integration.TestDbFactoryCreatesIsolatedDb]
|
|
#
|
|
# @RATIONALE
|
|
# The modularized fixtures (postgres.py, superset.py, etc.) provide the foundation for all
|
|
# integration tests. These regression tests verify that the fixtures themselves behave correctly:
|
|
# - db_session isolation: each test gets a clean slate
|
|
# - db_factory: database creation/cleanup works
|
|
# - Client cleanup: superset_client and superset_admin_session yield-then-close properly
|
|
#
|
|
# @REJECTED
|
|
# Testing superset_client cleanup via inspect(await client.aclose()) rejected — the fixture
|
|
# ensures cleanup via try/finally, which is tested implicitly by all other integration tests.
|
|
from datetime import UTC
|
|
import pytest
|
|
|
|
|
|
# #region Test.Integration.FixtureIsolation.DbSession [C:3] [TYPE Class]
|
|
# @BRIEF Verify db_session transactional isolation between tests.
|
|
class TestDbSessionIsolation:
|
|
"""Verify db_session fixture provides clean isolation per test."""
|
|
|
|
# #region Test.Integration.TestDbSessionAcceptsInsert [C:2] [TYPE Function]
|
|
# @BRIEF Verify we can insert and commit within a single test.
|
|
def test_db_session_accepts_insert(self, db_session):
|
|
"""Insert a row, commit, verify it's visible within the same test."""
|
|
from src.models.maintenance import MaintenanceSettings
|
|
|
|
# Ensure clean state
|
|
db_session.query(MaintenanceSettings).delete()
|
|
db_session.commit()
|
|
|
|
s = MaintenanceSettings(
|
|
id="default",
|
|
target_environment_id="test_isolation_env",
|
|
banner_template="Isolation test {message}",
|
|
)
|
|
db_session.add(s)
|
|
db_session.commit()
|
|
|
|
fetched = db_session.query(MaintenanceSettings).filter(
|
|
MaintenanceSettings.id == "default"
|
|
).first()
|
|
assert fetched is not None
|
|
assert fetched.target_environment_id == "test_isolation_env"
|
|
# #endregion Test.Integration.TestDbSessionAcceptsInsert
|
|
|
|
# #region Test.Integration.TestDbSessionIsolationCleanState [C:2] [TYPE Function]
|
|
# @BRIEF Verify the next test sees a clean state (no leftover from previous test).
|
|
def test_db_session_isolation_clean_state(self, db_session):
|
|
"""After previous test's commit, this test should NOT see that row
|
|
because db_session rolls back at the end of each test function."""
|
|
from src.models.maintenance import MaintenanceSettings
|
|
|
|
# The previous test inserted a MaintenanceSettings row and committed it,
|
|
# but db_session rolls back the whole transaction at test end.
|
|
# So this test should start with empty state (in the test transaction scope).
|
|
count = db_session.query(MaintenanceSettings).count()
|
|
assert count == 0, (
|
|
f"Expected clean state (0 rows), got {count}. "
|
|
"db_session rollback isolation is broken!"
|
|
)
|
|
# #endregion Test.Integration.TestDbSessionIsolationCleanState
|
|
|
|
# #region Test.Integration.TestDbSessionMultiTableRollback [C:2] [TYPE Function]
|
|
# @BRIEF Verify atomic rollback across multiple tables.
|
|
def test_db_session_multi_table_rollback(self, db_session):
|
|
"""Insert into two tables without commit — verify rollback."""
|
|
from datetime import datetime
|
|
|
|
from src.models.maintenance import (
|
|
MaintenanceDashboardBanner,
|
|
MaintenanceDashboardBannerStatus,
|
|
MaintenanceEvent,
|
|
MaintenanceEventStatus,
|
|
)
|
|
|
|
now = datetime.now(UTC)
|
|
event = MaintenanceEvent(
|
|
environment_id="env-rollback-test",
|
|
tables=["test_table"],
|
|
start_time=now,
|
|
end_time=now,
|
|
status=MaintenanceEventStatus.PENDING,
|
|
)
|
|
db_session.add(event)
|
|
db_session.flush()
|
|
|
|
banner = MaintenanceDashboardBanner(
|
|
environment_id="env-rollback-test",
|
|
dashboard_id=9999,
|
|
status=MaintenanceDashboardBannerStatus.ACTIVE,
|
|
)
|
|
db_session.add(banner)
|
|
db_session.flush()
|
|
# No commit — test ends, transaction rolls back
|
|
|
|
# Verify both are visible within this test (flush, not commit)
|
|
assert banner.id is not None
|
|
assert event.id is not None
|
|
|
|
# After this test, ALL changes roll back — verified by isolation test above
|
|
# #endregion Test.Integration.TestDbSessionMultiTableRollback
|
|
|
|
|
|
# #endregion Test.Integration.FixtureIsolation.DbSession
|
|
|
|
|
|
# #region Test.Integration.FixtureIsolation.DbFactory [C:3] [TYPE Class]
|
|
# @BRIEF Verify db_factory creates/drops isolated databases correctly.
|
|
class TestDbFactoryIsolation:
|
|
"""Verify db_factory database creation and cleanup."""
|
|
|
|
# #region Test.Integration.TestDbFactoryCreatesIsolatedDb [C:2] [TYPE Function]
|
|
# @BRIEF db_factory.create_db creates a unique database that actually exists in PG.
|
|
# @TEST_EDGE: db_factory_database_existence
|
|
def test_db_factory_creates_isolated_db(self, db_factory, pg_engine):
|
|
"""Create a database via factory, verify it exists in PostgreSQL."""
|
|
result = db_factory["create_db"]("_isolation_test")
|
|
assert "db_name" in result
|
|
assert "host_url" in result
|
|
assert "container_url" in result
|
|
assert "_isolation_test" in result["db_name"]
|
|
|
|
# Verify the database actually exists in PostgreSQL
|
|
from sqlalchemy import text
|
|
with pg_engine.begin() as conn:
|
|
row = conn.execute(
|
|
text(f"SELECT 1 FROM pg_database WHERE datname = '{result['db_name']}'")
|
|
).scalar()
|
|
assert row == 1, f"Database '{result['db_name']}' does not exist in PostgreSQL"
|
|
# #endregion Test.Integration.TestDbFactoryCreatesIsolatedDb
|
|
|
|
# #region Test.Integration.TestDbFactoryUniqueNames [C:2] [TYPE Function]
|
|
# @BRIEF Consecutive create_db calls produce different database names.
|
|
# @TEST_EDGE: db_factory_uniqueness
|
|
def test_db_factory_unique_names(self, db_factory):
|
|
"""Two create_db calls produce different database names."""
|
|
r1 = db_factory["create_db"]("_unique_a")
|
|
r2 = db_factory["create_db"]("_unique_b")
|
|
assert r1["db_name"] != r2["db_name"], \
|
|
f"Database names should be unique: {r1['db_name']} == {r2['db_name']}"
|
|
# #endregion Test.Integration.TestDbFactoryUniqueNames
|
|
|
|
# #region Test.Integration.TestDbFactoryDropRemovesDb [C:2] [TYPE Function]
|
|
# @BRIEF db_factory.drop_db actually removes the database from PostgreSQL.
|
|
def test_db_factory_drop_removes_db(self, db_factory, pg_engine):
|
|
"""Create then drop a database — verify it's removed."""
|
|
result = db_factory["create_db"]("_drop_test")
|
|
db_name = result["db_name"]
|
|
|
|
# Verify it exists
|
|
from sqlalchemy import text
|
|
with pg_engine.begin() as conn:
|
|
exists = conn.execute(
|
|
text(f"SELECT 1 FROM pg_database WHERE datname = '{db_name}'")
|
|
).scalar()
|
|
assert exists == 1, f"Database '{db_name}' should exist before drop"
|
|
|
|
# Drop it
|
|
db_factory["drop_db"](db_name)
|
|
|
|
# Verify it's gone
|
|
with pg_engine.begin() as conn:
|
|
exists = conn.execute(
|
|
text(f"SELECT 1 FROM pg_database WHERE datname = '{db_name}'")
|
|
).scalar()
|
|
assert exists is None, f"Database '{db_name}' should not exist after drop"
|
|
# #endregion Test.Integration.TestDbFactoryDropRemovesDb
|
|
|
|
|
|
# #endregion Test.Integration.FixtureIsolation.DbFactory
|
|
|
|
|
|
# #region Test.Integration.FixtureIsolation.ClientCleanup [C:2] [TYPE Class]
|
|
# @BRIEF Verify client fixtures yield and close properly (non-invasive inspection).
|
|
class TestClientCleanup:
|
|
"""Verify superset_client and superset_admin_session yield-and-close."""
|
|
|
|
# #region test_superset_client_available [C:1] [TYPE Function]
|
|
# @BRIEF Verify superset_client fixture is usable.
|
|
@pytest.mark.asyncio
|
|
async def test_superset_client_available(self, superset_client):
|
|
"""Using superset_client inside a test should work."""
|
|
_, dashboards = await superset_client.get_dashboards()
|
|
assert isinstance(dashboards, list)
|
|
# #endregion test_superset_client_available
|
|
|
|
# #region test_superset_admin_session_available [C:1] [TYPE Function]
|
|
# @BRIEF Verify superset_admin_session fixture yields an authenticated session with cookies.
|
|
def test_superset_admin_session_available(self, superset_admin_session):
|
|
"""Using superset_admin_session inside a test should work — it yields a session with cookies."""
|
|
# The fixture should have set a session cookie during login
|
|
session_cookie = superset_admin_session.cookies.get("session")
|
|
assert session_cookie is not None, \
|
|
"superset_admin_session should have session cookie after login"
|
|
assert len(session_cookie) > 20, \
|
|
f"Session cookie too short: {len(session_cookie)}"
|
|
# #endregion test_superset_admin_session_available
|
|
|
|
# #region test_superset_jwt_headers_available [C:1] [TYPE Function]
|
|
# @BRIEF Verify superset_jwt_headers fixture obtains a valid token.
|
|
def test_superset_jwt_headers_available(self, superset_jwt_headers):
|
|
"""JWT headers fixture should return a valid Bearer token."""
|
|
assert "Authorization" in superset_jwt_headers
|
|
assert superset_jwt_headers["Authorization"].startswith("Bearer ")
|
|
assert len(superset_jwt_headers["Authorization"]) > 50
|
|
# #endregion test_superset_jwt_headers_available
|
|
|
|
|
|
# #endregion Test.Integration.FixtureIsolation.ClientCleanup
|
|
|
|
# #endregion Test.Integration.FixtureIsolation
|