This repository has been archived on 2026-07-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core-hub/tests/test_migration.py

117 lines
4.2 KiB
Python

import json
from sqlalchemy import select
from sqlalchemy.ext.asyncio import async_sessionmaker
from core_hub.migration import import_bundle, validate_bundle
from core_hub.models import Hub, MigrationRun, Widget
def minimal_bundle():
return {
"schemaVersion": "core-hub.migration.v1",
"source": "inter-hub-haskell",
"exportedAt": "2026-06-27T00:00:00Z",
"records": {
"hubs": [
{
"id": "11111111-1111-4111-8111-111111111111",
"slug": "ops-hub",
"name": "Ops Hub",
"domain": "ops.coulomb.social",
"hubKind": "domain",
"hubFamily": "vsm",
"vsmFunction": "OPS",
"vsmSystem": "1",
}
],
"hubCapabilityManifests": [
{
"id": "22222222-2222-4222-8222-222222222222",
"hubSlug": "ops-hub",
"manifestVersion": "1.0",
"status": "active",
}
],
"apiConsumers": [
{
"id": "33333333-3333-4333-8333-333333333333",
"slug": "ops-hub",
"name": "ops-hub",
"hubCapabilityManifestId": "22222222-2222-4222-8222-222222222222",
"keyPrefix": "ch_prefixonly",
}
],
"apiKeys": [
{
"id": "44444444-4444-4444-8444-444444444444",
"apiConsumerSlug": "ops-hub",
"keyPrefix": "ch_prefixonly",
"keyHash": "a" * 64,
"scopes": "framework:read hub:ops-hub:write",
}
],
"widgets": [
{
"id": "55555555-5555-4555-8555-555555555555",
"hubSlug": "ops-hub",
"name": "Readiness",
"widgetType": "ops-readiness-gate",
"capabilityRef": "ops:readiness",
"viewContext": "ops-hub/readiness",
"policyScope": "ops-registry",
}
],
"interactionEvents": [
{
"id": "66666666-6666-4666-8666-666666666666",
"widgetId": "55555555-5555-4555-8555-555555555555",
"eventType": "ops-endpoint-verified",
"metadata": {"expectedStatus": 401},
}
],
},
}
def test_validate_bundle_rejects_secret_key_material():
bundle = minimal_bundle()
bundle["records"]["apiKeys"][0]["fullKey"] = "do-not-import"
report = validate_bundle(bundle)
assert report["ok"] is False
assert any("secret-like" in error for error in report["errors"])
async def test_dry_run_reports_counts_without_writing(sqlite_engine):
sessionmaker = async_sessionmaker(sqlite_engine, expire_on_commit=False)
async with sessionmaker() as session:
report = await import_bundle(session, minimal_bundle(), dry_run=True)
assert report["ok"] is True
assert report["counts"]["hubs"]["created"] == 1
assert (await session.execute(select(Hub))).scalars().first() is None
async def test_import_bundle_persists_records_and_run_summary(sqlite_engine):
sessionmaker = async_sessionmaker(sqlite_engine, expire_on_commit=False)
async with sessionmaker() as session:
report = await import_bundle(session, minimal_bundle())
assert report["ok"] is True
assert report["migrationRunId"]
assert report["counts"]["widgets"]["created"] == 1
hub = (await session.execute(select(Hub))).scalars().one()
widget = (await session.execute(select(Widget))).scalars().one()
run = (await session.execute(select(MigrationRun))).scalars().one()
assert hub.slug == "ops-hub"
assert widget.hub_id == hub.id
assert json.loads(run.counts_json)["interactionEvents"]["created"] == 1
second = await import_bundle(session, minimal_bundle())
assert second["counts"]["hubs"]["updated"] == 1
assert second["counts"]["interactionEvents"]["updated"] == 1