forked from diegoecab/oci-deal-accelerator
Diagram generation: ref-arch-driven procedure + spec validator + KB enrichment
The diagram path now follows a documented standard procedure (lookup the closest Oracle Architecture Center reference → confirm components → author absolute_layout → spec validator → render → visually verify) and ships persistent guardrails so layout regressions can't recur. Persistent procedure changes (apply to all users, all sessions): - tools/diagram_spec_validator.py — geometry checks (CONTAINER_TOO_THIN, CONTAINER_PADDING_VIOLATION, LABEL_OVERFLOW_PARENT) run BEFORE either renderer (drawio + PPTX). Catches the subnet-collapse / label-overflow bugs that the post-render drawio validator missed. - tools/oci_diagram_gen.py + tools/oci_pptx_diagram_gen.py — call the spec validator before emitting any output. Adds mysql / mysql_heatwave type aliases. - tools/archcenter_pattern_lookup.py — scores against cached page descriptions (not just the 1-line summary), supports --queries for multi-fragment composition, and applies synonym expansion via kb/architecture-center/synonyms.yaml so "LB HA cross AD" matches "load balancer high availability availability domain". - kb/architecture-center/synonyms.yaml — canonical synonym table (load balancer, autonomous database, data guard, …) used by the lookup scorer. KB enrichment: - tools/archcenter_description_fetcher.py + 121 cached _description.md under kb/diagram/assets/archcenter-refs/<slug>/. Removes the runtime dependency on docs.oracle.com when authoring specs and feeds the pattern-lookup scorer. - 110+ cached .drawio / .svg / .png references for offline reuse, plus the OCI Toolkit v24.2 import (kb/diagram/assets/oci-toolkit-drawio). Documentation: - docs/skill/output-formats.md — new "Standard diagram-generation procedure (MANDATORY)" + geometry rules + the new validator entry. - SKILL.md option 2 — references the mandatory procedure. - README.md — describes the spec validator, archcenter_pattern_lookup and description fetcher, and updates the KB-health table. Tooling that backs the procedure (cumulative across recent sessions): tools/archcenter_case_runner.py, archcenter_batch_driver.py, archcenter_zip_downloader.py, drawio_visual_validator.py, drawio_fidelity_eval.py, harvest_drawio_icon.py, import_oci_library.py, oci_pptx_diagram_gen.py, oci_pptx_render.py, refresh_pptx_icon_index.py. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
169
tests/test_oci_pptx_native_diagram.py
Normal file
169
tests/test_oci_pptx_native_diagram.py
Normal file
@@ -0,0 +1,169 @@
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
TOOLS_DIR = PROJECT_ROOT / "tools"
|
||||
|
||||
if str(TOOLS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_DIR))
|
||||
|
||||
from oci_deck_gen import OCIDeckGenerator
|
||||
from oci_pptx_diagram_gen import NativePPTXDiagramRenderer
|
||||
|
||||
|
||||
def test_native_pptx_architecture_slide_renders_into_saved_deck(tmp_path):
|
||||
spec = {
|
||||
"metadata": {
|
||||
"customer": "TestCo",
|
||||
"project": "Native Diagram",
|
||||
"subtitle": "Smoke test",
|
||||
},
|
||||
"summary": {
|
||||
"why": "Test native rendering",
|
||||
"current_state": ["Legacy DB"],
|
||||
"target_state": "OCI target",
|
||||
"timeline": "Q2",
|
||||
},
|
||||
"architecture": {
|
||||
"description": "Two-region native PPTX test",
|
||||
"visual": {
|
||||
"render_mode": "native_pptx",
|
||||
"on_prem": {"name": "On-Premises", "connection": "FastConnect"},
|
||||
"regions": [
|
||||
{
|
||||
"name": "Ashburn",
|
||||
"label": "PRIMARY",
|
||||
"availability_domains": [
|
||||
{
|
||||
"name": "Availability Domain 1",
|
||||
"vcn": {
|
||||
"name": "VCN",
|
||||
"cidr": "10.10.0.0/16",
|
||||
"subnets": [
|
||||
{
|
||||
"name": "App Subnet",
|
||||
"cidr": "10.10.10.0/24",
|
||||
"services": [
|
||||
{"id": "lb", "name": "Load Balancer", "type": "load_balancer"},
|
||||
{"id": "vm1", "name": "Virtual Machine", "type": "virtual_machine"},
|
||||
{"id": "sgw", "name": "Service Gateway", "type": "service_gateway"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Data Subnet",
|
||||
"cidr": "10.10.20.0/24",
|
||||
"services": [
|
||||
{"id": "db", "name": "ADB-D", "type": "adb_d"},
|
||||
{"id": "safe", "name": "Data Safe", "type": "data_safe"},
|
||||
{"id": "obj", "name": "Object Storage", "type": "object_storage"},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Availability Domain 2",
|
||||
"vcn": {
|
||||
"name": "VCN",
|
||||
"cidr": "10.10.0.0/16",
|
||||
"subnets": [
|
||||
{
|
||||
"name": "Standby Subnet",
|
||||
"cidr": "10.10.30.0/24",
|
||||
"services": [
|
||||
{"id": "dg", "name": "Data Guard", "type": "data_guard"},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Montreal",
|
||||
"label": "DR STANDBY",
|
||||
"services": [
|
||||
{"id": "drdb", "name": "ADB-D", "type": "adb_d"},
|
||||
{"id": "drdg", "name": "Data Guard", "type": "data_guard"},
|
||||
],
|
||||
"details": "Cross-region DR",
|
||||
},
|
||||
],
|
||||
"connections": [
|
||||
{"from": "lb", "to": "vm1", "label": "HTTPS"},
|
||||
{"from": "vm1", "to": "db", "label": "SQL"},
|
||||
{"from": "db", "to": "dg", "label": "ADG"},
|
||||
{"from": "db", "to": "drdb", "label": "DR", "style": "dashed"},
|
||||
],
|
||||
"security_footer": "OCI-native smoke test footer",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
output = tmp_path / "native-smoke-test.pptx"
|
||||
gen = OCIDeckGenerator.from_spec(spec)
|
||||
gen.save(str(output))
|
||||
|
||||
assert output.is_file()
|
||||
with zipfile.ZipFile(output) as archive:
|
||||
slide_xml = b"".join(
|
||||
archive.read(name)
|
||||
for name in archive.namelist()
|
||||
if name.startswith("ppt/slides/slide") and name.endswith(".xml")
|
||||
).decode("utf-8", errors="ignore")
|
||||
rels_xml = b"".join(
|
||||
archive.read(name)
|
||||
for name in archive.namelist()
|
||||
if name.startswith("ppt/slides/_rels/slide") and name.endswith(".rels")
|
||||
).decode("utf-8", errors="ignore")
|
||||
media_files = [
|
||||
name for name in archive.namelist()
|
||||
if name.startswith("ppt/media/")
|
||||
]
|
||||
|
||||
assert "Availability Domain 1" in slide_xml
|
||||
assert "FastConnect" in slide_xml
|
||||
assert "OCI-native smoke test footer" in slide_xml
|
||||
assert "Load" in slide_xml
|
||||
assert "relationships/image" in rels_xml
|
||||
assert media_files
|
||||
|
||||
|
||||
def test_native_pptx_icon_resolution_accepts_common_aliases():
|
||||
renderer = NativePPTXDiagramRenderer()
|
||||
|
||||
compute_ref = renderer._resolve_icon_ref(
|
||||
{"name": "Virtual Machine app tier", "type": "compute"}
|
||||
)
|
||||
lb_ref = renderer._resolve_icon_ref(
|
||||
{"name": "Ingress", "type": "public_load_balancer"}
|
||||
)
|
||||
storage_ref = renderer._resolve_icon_ref(
|
||||
{"name": "Object Storage (DR)", "type": "storage"}
|
||||
)
|
||||
|
||||
assert compute_ref is not None
|
||||
assert compute_ref["display_number"] in {29, 30, 32, 34}
|
||||
assert lb_ref is not None
|
||||
assert "load" in lb_ref["text"].lower()
|
||||
assert storage_ref is not None
|
||||
assert "object" in storage_ref["text"].lower()
|
||||
|
||||
|
||||
def test_native_pptx_icon_resolution_prefers_compact_refs_for_problem_icons():
|
||||
renderer = NativePPTXDiagramRenderer()
|
||||
|
||||
api_ref = renderer._resolve_icon_ref({"name": "OCI API Gateway", "type": "api_gateway"})
|
||||
notify_ref = renderer._resolve_icon_ref({"name": "Notifications", "type": "notifications"})
|
||||
oke_ref = renderer._resolve_icon_ref({"name": "OKE cluster", "type": "oke"})
|
||||
vpn_ref = renderer._resolve_icon_ref({"name": "Site-to-Site VPN", "type": "vpn"})
|
||||
|
||||
assert api_ref is not None
|
||||
assert notify_ref is not None
|
||||
assert oke_ref is not None
|
||||
assert vpn_ref is not None
|
||||
assert int(api_ref["bbox"]["cx"]) < 2_500_000
|
||||
assert int(notify_ref["bbox"]["cx"]) < 2_500_000
|
||||
assert int(oke_ref["bbox"]["cx"]) < 2_500_000
|
||||
Reference in New Issue
Block a user