forked from sagnik/Project_Velocity
Built the Oracle Tab (#14)
This commit is contained in:
1
backend/tests/oracle/__init__.py
Normal file
1
backend/tests/oracle/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Tests for Oracle backend services — runs without any live database or model runtime."""
|
||||
133
backend/tests/oracle/test_canvas_service.py
Normal file
133
backend/tests/oracle/test_canvas_service.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
test_canvas_service.py — Unit tests for CanvasService (demo mode in-memory store).
|
||||
"""
|
||||
import asyncio
|
||||
import pytest
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Ensure backend is on path
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
|
||||
from oracle.canvas_service import CanvasService
|
||||
|
||||
TENANT = "tenant_test_001"
|
||||
ACTOR = "user_test_001"
|
||||
|
||||
|
||||
def run(coro):
|
||||
return asyncio.get_event_loop().run_until_complete(coro)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def svc():
|
||||
"""Fresh CanvasService instance with empty demo store per test."""
|
||||
from oracle import canvas_service as _mod
|
||||
_mod._DEMO_PAGES.clear()
|
||||
_mod._DEMO_REVISIONS.clear()
|
||||
_mod._DEMO_COMPONENTS.clear()
|
||||
return CanvasService()
|
||||
|
||||
|
||||
def test_create_page(svc):
|
||||
page = run(svc.create_page(tenant_id=TENANT, owner_id=ACTOR, title="Test Canvas"))
|
||||
assert page["tenantId"] == TENANT
|
||||
assert page["ownerId"] == ACTOR
|
||||
assert page["title"] == "Test Canvas"
|
||||
assert page["headRevision"] == 0
|
||||
assert page["pageType"] == "main"
|
||||
assert page["branchName"] == "main"
|
||||
|
||||
|
||||
def test_get_page_not_found(svc):
|
||||
result = run(svc.get_page("nonexistent_id", TENANT))
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_get_page_returns_page(svc):
|
||||
page = run(svc.create_page(tenant_id=TENANT, owner_id=ACTOR))
|
||||
retrieved = run(svc.get_page(page["pageId"], TENANT))
|
||||
assert retrieved is not None
|
||||
assert retrieved["pageId"] == page["pageId"]
|
||||
|
||||
|
||||
def test_commit_revision_advances_head(svc):
|
||||
page = run(svc.create_page(tenant_id=TENANT, owner_id=ACTOR))
|
||||
comps = [{"componentId": "cmp_001", "type": "barChart", "title": "Test"}]
|
||||
rev = run(svc.commit_revision(
|
||||
page_id=page["pageId"],
|
||||
tenant_id=TENANT,
|
||||
actor_id=ACTOR,
|
||||
commit_kind="prompt",
|
||||
commit_summary="Test prompt",
|
||||
components=comps,
|
||||
idempotency_key="ikey_001",
|
||||
))
|
||||
assert rev["revisionNumber"] == 1
|
||||
updated = run(svc.get_page(page["pageId"], TENANT))
|
||||
assert updated["headRevision"] == 1
|
||||
assert len(updated["components"]) == 1
|
||||
|
||||
|
||||
def test_idempotency_key_prevents_double_commit(svc):
|
||||
page = run(svc.create_page(tenant_id=TENANT, owner_id=ACTOR))
|
||||
comps = [{"componentId": "cmp_001", "type": "barChart", "title": "Test"}]
|
||||
rev1 = run(svc.commit_revision(
|
||||
page_id=page["pageId"], tenant_id=TENANT, actor_id=ACTOR,
|
||||
commit_kind="prompt", commit_summary="First", components=comps,
|
||||
idempotency_key="ikey_idempotent",
|
||||
))
|
||||
rev2 = run(svc.commit_revision(
|
||||
page_id=page["pageId"], tenant_id=TENANT, actor_id=ACTOR,
|
||||
commit_kind="prompt", commit_summary="Duplicate", components=comps,
|
||||
idempotency_key="ikey_idempotent",
|
||||
))
|
||||
assert rev1["revisionId"] == rev2["revisionId"]
|
||||
# Head should still be 1
|
||||
updated = run(svc.get_page(page["pageId"], TENANT))
|
||||
assert updated["headRevision"] == 1
|
||||
|
||||
|
||||
def test_rollback_creates_new_revision(svc):
|
||||
page = run(svc.create_page(tenant_id=TENANT, owner_id=ACTOR))
|
||||
comps_v1 = [{"componentId": "cmp_v1", "type": "barChart", "title": "V1"}]
|
||||
comps_v2 = [{"componentId": "cmp_v2", "type": "lineChart", "title": "V2"}]
|
||||
|
||||
run(svc.commit_revision(
|
||||
page_id=page["pageId"], tenant_id=TENANT, actor_id=ACTOR,
|
||||
commit_kind="prompt", commit_summary="V1", components=comps_v1, idempotency_key="key_v1",
|
||||
))
|
||||
run(svc.commit_revision(
|
||||
page_id=page["pageId"], tenant_id=TENANT, actor_id=ACTOR,
|
||||
commit_kind="prompt", commit_summary="V2", components=comps_v2, idempotency_key="key_v2",
|
||||
))
|
||||
|
||||
# Rollback to revision 1
|
||||
rollback_rev = run(svc.rollback(
|
||||
page_id=page["pageId"], tenant_id=TENANT, actor_id=ACTOR,
|
||||
target_revision=1, idempotency_key="key_rollback",
|
||||
))
|
||||
assert rollback_rev["revisionNumber"] == 3
|
||||
assert rollback_rev["commitKind"] == "rollback"
|
||||
|
||||
revisions = run(svc.list_revisions(page["pageId"], TENANT))
|
||||
assert len(revisions) == 3 # 3 revisions total
|
||||
|
||||
|
||||
def test_list_revisions_returns_newest_first(svc):
|
||||
page = run(svc.create_page(tenant_id=TENANT, owner_id=ACTOR))
|
||||
for i in range(3):
|
||||
run(svc.commit_revision(
|
||||
page_id=page["pageId"], tenant_id=TENANT, actor_id=ACTOR,
|
||||
commit_kind="prompt", commit_summary=f"Rev {i+1}",
|
||||
components=[], idempotency_key=f"key_{i}",
|
||||
))
|
||||
revisions = run(svc.list_revisions(page["pageId"], TENANT))
|
||||
assert revisions[0]["revisionNumber"] > revisions[-1]["revisionNumber"]
|
||||
|
||||
|
||||
def test_tenant_isolation(svc):
|
||||
page = run(svc.create_page(tenant_id=TENANT, owner_id=ACTOR))
|
||||
# Different tenant cannot access the page
|
||||
result = run(svc.get_page(page["pageId"], "tenant_different_999"))
|
||||
assert result is None
|
||||
207
backend/tests/oracle/test_collaboration_service.py
Normal file
207
backend/tests/oracle/test_collaboration_service.py
Normal file
@@ -0,0 +1,207 @@
|
||||
"""
|
||||
test_collaboration_service.py — Unit tests for three-way diff, fork, merge request lifecycle.
|
||||
"""
|
||||
import asyncio
|
||||
import copy
|
||||
import sys
|
||||
import os
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
|
||||
from oracle.collaboration_service import CollaborationService, three_way_diff
|
||||
|
||||
|
||||
def run(coro):
|
||||
return asyncio.get_event_loop().run_until_complete(coro)
|
||||
|
||||
|
||||
def _comp(cid, title="Test", order=100, content="default"):
|
||||
return {
|
||||
"componentId": cid,
|
||||
"type": "barChart",
|
||||
"title": title,
|
||||
"dataSourceDescriptor": {"dataset": "test_ds", "queryTemplate": content},
|
||||
"accessControls": {"allowedRoles": ["sales_director"], "visibilityScope": "private"},
|
||||
"layout": {"orderIndex": order, "sectionId": "sec_test", "widthMode": "full"},
|
||||
}
|
||||
|
||||
|
||||
# ── Three-way diff tests ──────────────────────────────────────────────────────
|
||||
|
||||
def test_safe_append_in_source():
|
||||
base = [_comp("cmp_a")]
|
||||
source = [_comp("cmp_a"), _comp("cmp_b")] # cmp_b added in source
|
||||
target = [_comp("cmp_a")]
|
||||
|
||||
merged, conflicts = three_way_diff(base, source, target)
|
||||
assert any(c["conflictClass"] == "safe_append" and c["componentId"] == "cmp_b" for c in conflicts)
|
||||
assert any(c["componentId"] == "cmp_b" for c in merged)
|
||||
|
||||
|
||||
def test_no_conflict_when_identical():
|
||||
base = [_comp("cmp_a")]
|
||||
source = [_comp("cmp_a")]
|
||||
target = [_comp("cmp_a")]
|
||||
|
||||
merged, conflicts = three_way_diff(base, source, target)
|
||||
assert len(merged) == 1
|
||||
assert all(c["conflictClass"] not in ("component_content_conflict", "query_descriptor_conflict") for c in conflicts)
|
||||
|
||||
|
||||
def test_component_content_conflict():
|
||||
base = [_comp("cmp_a", content="SELECT 1")]
|
||||
source = [_comp("cmp_a", content="SELECT 2")]
|
||||
target = [_comp("cmp_a", content="SELECT 3")]
|
||||
|
||||
merged, conflicts = three_way_diff(base, source, target)
|
||||
# Expect query_descriptor_conflict or component_content_conflict
|
||||
conflict_classes = {c["conflictClass"] for c in conflicts}
|
||||
assert conflict_classes & {"component_content_conflict", "query_descriptor_conflict"}
|
||||
|
||||
|
||||
def test_delete_edit_conflict_source_deletes():
|
||||
base = [_comp("cmp_a"), _comp("cmp_b")]
|
||||
source = [_comp("cmp_a")] # cmp_b deleted in source
|
||||
target = [_comp("cmp_a"), _comp("cmp_b", title="Edited in target")] # cmp_b edited in target
|
||||
|
||||
merged, conflicts = three_way_diff(base, source, target)
|
||||
assert any(c["conflictClass"] == "delete_edit_conflict" and c["componentId"] == "cmp_b" for c in conflicts)
|
||||
# Default: keep target (edited version)
|
||||
assert any(c["componentId"] == "cmp_b" for c in merged)
|
||||
|
||||
|
||||
def test_deleted_in_both_is_removed():
|
||||
base = [_comp("cmp_a"), _comp("cmp_b")]
|
||||
source = [_comp("cmp_a")]
|
||||
target = [_comp("cmp_a")]
|
||||
|
||||
merged, conflicts = three_way_diff(base, source, target)
|
||||
assert not any(c["componentId"] == "cmp_b" for c in merged)
|
||||
|
||||
|
||||
def test_orderindex_normalization():
|
||||
base = []
|
||||
source = [_comp("c1", order=100), _comp("c2", order=200)]
|
||||
target = [_comp("c1", order=100), _comp("c2", order=200)]
|
||||
|
||||
merged, _ = three_way_diff(base, source, target)
|
||||
orders = [c["layout"]["orderIndex"] for c in merged]
|
||||
# Orders should be normalized (multiples of 100, sequential)
|
||||
assert orders == sorted(orders)
|
||||
assert all(o % 100 == 0 for o in orders)
|
||||
|
||||
|
||||
# ── CollaborationService tests ────────────────────────────────────────────────
|
||||
|
||||
@pytest.fixture
|
||||
def collab():
|
||||
from oracle import collaboration_service as _mod
|
||||
_mod._DEMO_FORKS.clear()
|
||||
_mod._DEMO_MRS.clear()
|
||||
return CollaborationService()
|
||||
|
||||
|
||||
def test_create_fork(collab):
|
||||
source_page = {
|
||||
"pageId": "page_src",
|
||||
"branchId": "branch_main",
|
||||
"headRevision": 5,
|
||||
"components": [],
|
||||
}
|
||||
fork = run(collab.create_fork(
|
||||
source_page=source_page,
|
||||
recipient_user_id="user_recipient",
|
||||
created_by="user_src",
|
||||
))
|
||||
assert fork["sourcePageId"] == "page_src"
|
||||
assert fork["sourceRevision"] == 5
|
||||
assert fork["status"] == "active"
|
||||
assert fork["recipientUserId"] == "user_recipient"
|
||||
|
||||
|
||||
def test_merge_request_lifecycle(collab):
|
||||
mr = run(collab.open_merge_request(
|
||||
tenant_id="tenant_test",
|
||||
source_page_id="page_fork",
|
||||
source_branch_id="branch_fork",
|
||||
source_head_revision=2,
|
||||
target_page_id="page_main",
|
||||
target_branch_id="branch_main",
|
||||
target_base_revision=5,
|
||||
title="Test MR",
|
||||
description="My changes",
|
||||
created_by="user_a",
|
||||
source_components=[_comp("cmp_a"), _comp("cmp_new")],
|
||||
target_components=[_comp("cmp_a")],
|
||||
base_components=[_comp("cmp_a")],
|
||||
))
|
||||
assert mr["status"] == "open"
|
||||
assert "mergeRequestId" in mr
|
||||
|
||||
# Approve it
|
||||
reviewed = run(collab.review_merge_request(
|
||||
mr_id=mr["mergeRequestId"],
|
||||
decision="approve",
|
||||
reviewer_id="user_reviewer",
|
||||
))
|
||||
assert reviewed["status"] == "merged"
|
||||
|
||||
|
||||
def test_merge_request_reject(collab):
|
||||
mr = run(collab.open_merge_request(
|
||||
tenant_id="tenant_test",
|
||||
source_page_id="page_fork",
|
||||
source_branch_id="branch_fork",
|
||||
source_head_revision=1,
|
||||
target_page_id="page_main",
|
||||
target_branch_id="branch_main",
|
||||
target_base_revision=1,
|
||||
title="Rejected MR",
|
||||
created_by="user_a",
|
||||
source_components=[],
|
||||
target_components=[],
|
||||
base_components=[],
|
||||
))
|
||||
reviewed = run(collab.review_merge_request(
|
||||
mr_id=mr["mergeRequestId"],
|
||||
decision="reject",
|
||||
reviewer_id="user_reviewer",
|
||||
))
|
||||
assert reviewed["status"] == "closed"
|
||||
|
||||
|
||||
def test_list_merge_requests_filters_by_target(collab):
|
||||
for i in range(3):
|
||||
run(collab.open_merge_request(
|
||||
tenant_id="tenant_t",
|
||||
source_page_id=f"page_fork_{i}",
|
||||
source_branch_id=f"branch_{i}",
|
||||
source_head_revision=1,
|
||||
target_page_id="page_target",
|
||||
target_branch_id="branch_main",
|
||||
target_base_revision=1,
|
||||
title=f"MR {i}",
|
||||
created_by="user_a",
|
||||
source_components=[],
|
||||
target_components=[],
|
||||
base_components=[],
|
||||
))
|
||||
# Different target
|
||||
run(collab.open_merge_request(
|
||||
tenant_id="tenant_t",
|
||||
source_page_id="page_other",
|
||||
source_branch_id="branch_other",
|
||||
source_head_revision=1,
|
||||
target_page_id="page_other_target",
|
||||
target_branch_id="branch_main",
|
||||
target_base_revision=1,
|
||||
title="Different target MR",
|
||||
created_by="user_b",
|
||||
source_components=[],
|
||||
target_components=[],
|
||||
base_components=[],
|
||||
))
|
||||
mrs = run(collab.list_merge_requests("page_target"))
|
||||
assert len(mrs) == 3
|
||||
assert all(mr["targetPageId"] == "page_target" for mr in mrs)
|
||||
142
backend/tests/oracle/test_policy_service.py
Normal file
142
backend/tests/oracle/test_policy_service.py
Normal file
@@ -0,0 +1,142 @@
|
||||
"""
|
||||
test_policy_service.py — Unit tests for Oracle policy engine.
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
|
||||
from oracle.policy_service import PolicyService, PolicyContext
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def svc():
|
||||
return PolicyService()
|
||||
|
||||
|
||||
def _ctx(role: str = "sales_director") -> PolicyContext:
|
||||
return PolicyContext(
|
||||
tenant_id="tenant_test_001",
|
||||
actor_id="user_test_001",
|
||||
actor_role=role,
|
||||
)
|
||||
|
||||
|
||||
# ── Privacy tier tests ────────────────────────────────────────────────────────
|
||||
|
||||
def test_junior_broker_denied_restricted(svc):
|
||||
plan = {"dataset": "lead_contacts", "privacyTier": "restricted", "rowLimit": 50, "joins": []}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("junior_broker"))
|
||||
assert not result.passed
|
||||
assert any("POLICY_PRIVACY_TIER_ESCALATION" in e for e in result.errors)
|
||||
|
||||
|
||||
def test_senior_broker_allowed_restricted_with_redaction(svc):
|
||||
plan = {"dataset": "lead_contacts", "privacyTier": "restricted", "rowLimit": 50, "joins": []}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("senior_broker"))
|
||||
assert result.passed
|
||||
assert result.redaction_policy == "aggregate_only"
|
||||
|
||||
|
||||
def test_junior_broker_denied_sensitive(svc):
|
||||
plan = {"dataset": "pii_records", "privacyTier": "sensitive", "rowLimit": 10, "joins": []}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("junior_broker"))
|
||||
assert not result.passed
|
||||
|
||||
|
||||
def test_data_steward_allowed_sensitive(svc):
|
||||
plan = {"dataset": "pii_records", "privacyTier": "sensitive", "rowLimit": 100, "joins": []}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("data_steward"))
|
||||
assert result.passed
|
||||
|
||||
|
||||
# ── Row limit tests ───────────────────────────────────────────────────────────
|
||||
|
||||
def test_row_limit_capped_for_junior_broker(svc):
|
||||
plan = {"dataset": "leads", "privacyTier": "standard", "rowLimit": 5000, "joins": []}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("junior_broker"))
|
||||
assert result.passed
|
||||
assert result.effective_row_limit == 100
|
||||
assert any("ROW_LIMIT_CAPPED" in w for w in result.warnings)
|
||||
|
||||
|
||||
def test_row_limit_respected_for_admin(svc):
|
||||
plan = {"dataset": "leads", "privacyTier": "standard", "rowLimit": 5000, "joins": []}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("platform_admin"))
|
||||
assert result.passed
|
||||
assert result.effective_row_limit == 5000
|
||||
|
||||
|
||||
# ── Cross-tenant join tests ───────────────────────────────────────────────────
|
||||
|
||||
def test_cross_tenant_join_denied(svc):
|
||||
plan = {
|
||||
"dataset": "global_lead_market",
|
||||
"privacyTier": "standard",
|
||||
"rowLimit": 50,
|
||||
"joins": [],
|
||||
}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("sales_director"))
|
||||
assert not result.passed
|
||||
assert any("POLICY_CROSS_TENANT_JOIN_DENIED" in e for e in result.errors)
|
||||
|
||||
|
||||
def test_explicit_cross_tenant_join_denied(svc):
|
||||
plan = {
|
||||
"dataset": "deals",
|
||||
"privacyTier": "standard",
|
||||
"rowLimit": 50,
|
||||
"joins": [{"tenantId": "tenant_other_999"}],
|
||||
}
|
||||
result = svc.validate_retrieval_plan(plan, _ctx("sales_director"))
|
||||
assert not result.passed
|
||||
|
||||
|
||||
# ── Tenant predicate enforcement ──────────────────────────────────────────────
|
||||
|
||||
def test_enforce_tenant_predicate_overrides(svc):
|
||||
params = {"tenant_id": "attacker_tenant", "limit": 100}
|
||||
ctx = _ctx("sales_director")
|
||||
enforced = svc.enforce_tenant_predicate(params, ctx)
|
||||
assert enforced["tenant_id"] == "tenant_test_001"
|
||||
assert enforced["limit"] == 100
|
||||
|
||||
|
||||
# ── Component access control ──────────────────────────────────────────────────
|
||||
|
||||
def test_component_access_granted_for_allowed_role(svc):
|
||||
ac = {"allowedRoles": ["sales_director", "senior_broker"], "visibilityScope": "private"}
|
||||
assert svc.validate_component_access(ac, _ctx("sales_director")) is True
|
||||
|
||||
|
||||
def test_component_access_denied_for_wrong_role(svc):
|
||||
ac = {"allowedRoles": ["data_steward"], "visibilityScope": "private"}
|
||||
assert svc.validate_component_access(ac, _ctx("junior_broker")) is False
|
||||
|
||||
|
||||
# ── Redaction tests ───────────────────────────────────────────────────────────
|
||||
|
||||
def test_redact_full():
|
||||
svc = PolicyService()
|
||||
rows = [{"name": "Alice", "email": "alice@test.com", "deal": 1000}]
|
||||
redacted = svc.redact(rows, "full_redact")
|
||||
assert redacted == [{"__redacted__": True, "count": 1}]
|
||||
|
||||
|
||||
def test_redact_aggregate_only():
|
||||
svc = PolicyService()
|
||||
rows = [{"name": "Alice", "count": 5, "stage": "Qualified", "email": "alice@test.com"}]
|
||||
redacted = svc.redact(rows, "aggregate_only")
|
||||
assert len(redacted) == 1
|
||||
assert "email" not in redacted[0]
|
||||
assert "name" not in redacted[0]
|
||||
assert redacted[0].get("count") == 5
|
||||
assert redacted[0].get("stage") == "Qualified"
|
||||
|
||||
|
||||
def test_redact_none_passes_through():
|
||||
svc = PolicyService()
|
||||
rows = [{"name": "Alice", "value": 999}]
|
||||
result = svc.redact(rows, "none")
|
||||
assert result == rows
|
||||
143
backend/tests/oracle/test_prompt_orchestrator.py
Normal file
143
backend/tests/oracle/test_prompt_orchestrator.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
test_prompt_orchestrator.py — Unit tests for PromptOrchestrator (demo/fallback mode).
|
||||
"""
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
|
||||
|
||||
def run(coro):
|
||||
return asyncio.get_event_loop().run_until_complete(coro)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_demo_stores():
|
||||
from oracle import canvas_service as _cs
|
||||
from oracle import collaboration_service as _col
|
||||
_cs._DEMO_PAGES.clear()
|
||||
_cs._DEMO_REVISIONS.clear()
|
||||
_cs._DEMO_COMPONENTS.clear()
|
||||
_col._DEMO_MRS.clear()
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def page():
|
||||
"""Create a demo canvas page and return it."""
|
||||
from oracle.canvas_service import canvas_service
|
||||
return run(canvas_service.create_page(
|
||||
tenant_id="tenant_test",
|
||||
owner_id="user_test",
|
||||
title="Test Oracle Page",
|
||||
))
|
||||
|
||||
|
||||
def test_pipeline_prompt_produces_components(page):
|
||||
from oracle.prompt_orchestrator import PromptOrchestrator
|
||||
orch = PromptOrchestrator()
|
||||
result = run(orch.execute(
|
||||
tenant_id="tenant_test",
|
||||
page_id=page["pageId"],
|
||||
branch_id=page["branchId"],
|
||||
actor_id="user_test",
|
||||
actor_role="sales_director",
|
||||
prompt="Show me an active pipeline view by stage",
|
||||
client_request_id="cli_test_001",
|
||||
))
|
||||
assert result["status"] == "completed"
|
||||
assert len(result["componentsCreated"]) > 0
|
||||
assert result["summary"]
|
||||
|
||||
|
||||
def test_geo_map_prompt_produces_geo_component(page):
|
||||
from oracle.prompt_orchestrator import PromptOrchestrator
|
||||
orch = PromptOrchestrator()
|
||||
result = run(orch.execute(
|
||||
tenant_id="tenant_test",
|
||||
page_id=page["pageId"],
|
||||
branch_id=page["branchId"],
|
||||
actor_id="user_test",
|
||||
actor_role="sales_director",
|
||||
prompt="Show me a map of whale leads by Dubai district",
|
||||
client_request_id="cli_test_002",
|
||||
))
|
||||
assert result["status"] == "completed"
|
||||
vp = result.get("visualizationPlan", {}).get("components", [])
|
||||
assert any(c["type"] == "geoMap" for c in vp)
|
||||
|
||||
|
||||
def test_broker_table_prompt(page):
|
||||
from oracle.prompt_orchestrator import PromptOrchestrator
|
||||
orch = PromptOrchestrator()
|
||||
result = run(orch.execute(
|
||||
tenant_id="tenant_test",
|
||||
page_id=page["pageId"],
|
||||
branch_id=page["branchId"],
|
||||
actor_id="user_test",
|
||||
actor_role="sales_director",
|
||||
prompt="Give me a table of brokers ranked by performance",
|
||||
client_request_id="cli_test_003",
|
||||
))
|
||||
assert result["status"] == "completed"
|
||||
vp = result.get("visualizationPlan", {}).get("components", [])
|
||||
assert any(c["type"] == "table" for c in vp)
|
||||
|
||||
|
||||
def test_policy_denial_on_restricted_for_junior_broker(page):
|
||||
"""Junior broker should get warnings/denial on restricted tier dataset."""
|
||||
from oracle.prompt_orchestrator import PromptOrchestrator, _build_demo_retrieval_plan
|
||||
from oracle.policy_service import PolicyService, PolicyContext
|
||||
|
||||
plan = {
|
||||
"components": [{
|
||||
"suggestedType": "table",
|
||||
"dataset": "pii_leads",
|
||||
"privacyTier": "sensitive",
|
||||
"rowLimit": 500,
|
||||
"joins": [],
|
||||
}]
|
||||
}
|
||||
svc = PolicyService()
|
||||
ctx = PolicyContext(tenant_id="tenant_test", actor_id="user_junior", actor_role="junior_broker")
|
||||
for comp_plan in plan["components"]:
|
||||
result = svc.validate_retrieval_plan(comp_plan, ctx)
|
||||
assert not result.passed
|
||||
|
||||
|
||||
def test_idempotency_key_prevents_double_execution(page):
|
||||
from oracle.prompt_orchestrator import PromptOrchestrator
|
||||
orch = PromptOrchestrator()
|
||||
prompt_kwargs = dict(
|
||||
tenant_id="tenant_test",
|
||||
page_id=page["pageId"],
|
||||
branch_id=page["branchId"],
|
||||
actor_id="user_test",
|
||||
actor_role="sales_director",
|
||||
prompt="Pipeline view",
|
||||
client_request_id="cli_idempotent_key",
|
||||
)
|
||||
result1 = run(orch.execute(**prompt_kwargs))
|
||||
result2 = run(orch.execute(**prompt_kwargs))
|
||||
|
||||
# Both should succeed; canvas should not double-create components
|
||||
assert result1["status"] == "completed"
|
||||
assert result2["status"] == "completed"
|
||||
|
||||
|
||||
def test_kpi_prompt_type(page):
|
||||
from oracle.prompt_orchestrator import PromptOrchestrator
|
||||
orch = PromptOrchestrator()
|
||||
result = run(orch.execute(
|
||||
tenant_id="tenant_test",
|
||||
page_id=page["pageId"],
|
||||
branch_id=page["branchId"],
|
||||
actor_id="user_test",
|
||||
actor_role="sales_director",
|
||||
prompt="How many total leads do we have?",
|
||||
client_request_id="cli_test_kpi",
|
||||
))
|
||||
vp = result.get("visualizationPlan", {}).get("components", [])
|
||||
assert any(c["type"] == "kpiTile" for c in vp)
|
||||
Reference in New Issue
Block a user