feat: Built the Oracle Tab (#14)
This commit is contained in:
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)
|
||||
Reference in New Issue
Block a user