a2a-source-edit: write tests/test_full_stack_contract.py
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from a2a_pack import PlatformUserAuth
|
||||
from a2a_pack.cli.local import load_local_project
|
||||
|
||||
import agent as agent_module
|
||||
from agent import GeneratesSvgVideoGame9jg9vdF0f510
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
@@ -12,17 +19,86 @@ def test_full_stack_product_contract():
|
||||
frontend = (ROOT / "frontend" / "src" / "App.jsx").read_text(encoding="utf-8")
|
||||
|
||||
assert "frontend:" in manifest and "mount: /app" in manifest
|
||||
assert "public: false" in manifest
|
||||
assert "resources:" in manifest and "databases:" in manifest
|
||||
assert "migrations:" in manifest and "db/migrations" in manifest
|
||||
assert "PlatformUserAuth" in source
|
||||
assert "AgentPlatformResources" in source and "AgentDatabase(" in source
|
||||
assert "Skill runner" not in frontend, "replace the generic scaffold with the product workflow"
|
||||
assert "Skill runner" not in frontend
|
||||
assert "generate_svg_asset" in frontend
|
||||
assert "DATABASE_URL" not in frontend
|
||||
|
||||
migrations = list((ROOT / "db" / "migrations").glob("*.sql"))
|
||||
assert migrations and all(path.read_text(encoding="utf-8").strip() for path in migrations)
|
||||
|
||||
card = load_local_project(ROOT).agent_cls().card()
|
||||
skill_names = {skill.name for skill in card.skills}
|
||||
assert {"generate_svg_asset", "list_recent_receipts"} <= skill_names
|
||||
databases = card.runtime.platform_resources.databases
|
||||
assert databases, "live Agent Card must declare its managed database"
|
||||
assert databases[0].migrations is not None
|
||||
assert databases[0].migrations.path == "db/migrations"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_svg_asset_smoke_without_database(monkeypatch):
|
||||
monkeypatch.delenv("DATABASE_URL", raising=False)
|
||||
auth = PlatformUserAuth(sub="stable-user", user_id=42, email="player@example.test")
|
||||
result = await GeneratesSvgVideoGame9jg9vdF0f510().local_invoke(
|
||||
"generate_svg_asset",
|
||||
auth=auth,
|
||||
asset_type="character",
|
||||
theme="forest knight",
|
||||
palette=["#22c55e", "#14532d", "#facc15"],
|
||||
size=96,
|
||||
style="pixel",
|
||||
variant_count=2,
|
||||
)
|
||||
assert result.status == "ok"
|
||||
assert result.receipt_id.startswith("rcpt_")
|
||||
assert result.asset_id.startswith("asset_")
|
||||
assert result.receipt_persisted is False
|
||||
assert len(result.svg_assets) == 2
|
||||
assert result.svg_assets[0]["svg"].startswith("<svg")
|
||||
assert "DATABASE_URL" not in result.model_dump_json()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_svg_asset_persists_receipt_when_database_configured(monkeypatch):
|
||||
calls = []
|
||||
|
||||
def fake_persist(**kwargs):
|
||||
calls.append(kwargs)
|
||||
|
||||
monkeypatch.setenv("DATABASE_URL", "postgresql://example.invalid/db")
|
||||
monkeypatch.setattr(agent_module, "_persist_asset_and_receipt", fake_persist)
|
||||
auth = PlatformUserAuth(sub="stable-user", user_id=7)
|
||||
result = await GeneratesSvgVideoGame9jg9vdF0f510().local_invoke(
|
||||
"generate_svg_asset",
|
||||
auth=auth,
|
||||
asset_type="item",
|
||||
theme="crystal key",
|
||||
palette=["#38bdf8", "#1e3a8a"],
|
||||
size=128,
|
||||
style="neon",
|
||||
variant_count=1,
|
||||
)
|
||||
assert result.status == "ok"
|
||||
assert result.receipt_persisted is True
|
||||
assert calls
|
||||
assert calls[0]["tenant_key"] == "user:7"
|
||||
assert calls[0]["receipt_id"] == result.receipt_id
|
||||
assert calls[0]["request"]["theme"] == "crystal key"
|
||||
|
||||
|
||||
def test_primary_schema_is_bounded_and_mcp_compatible():
|
||||
card = GeneratesSvgVideoGame9jg9vdF0f510().card()
|
||||
skill = next(item for item in card.skills if item.name == "generate_svg_asset")
|
||||
schema = skill.input_schema
|
||||
props = schema["properties"]
|
||||
assert set(schema["required"]) >= {"asset_type", "theme"}
|
||||
assert props["theme"]["maxLength"] == 80
|
||||
assert props["size"]["maximum"] == 512
|
||||
assert props["variant_count"]["maximum"] == 4
|
||||
assert props["asset_type"]["enum"] == ["character", "enemy", "item", "tile", "icon", "projectile"]
|
||||
assert schema["additionalProperties"] is False
|
||||
|
||||
Reference in New Issue
Block a user