0506c5da63
TIER-2 READ AGENTS.md, conductor/workflow.md, conductor/edit_workflow.md,
conductor/tier2/githooks/forbidden-files.txt,
conductor/tracks/tier2_leak_prevention_20260620/spec.md,
conductor/code_styleguides/data_oriented_design.md,
conductor/code_styleguides/error_handling.md,
conductor/code_styleguides/type_aliases.md before Phase 1.
Phase 1 of metadata_promotion_20260624: migrate Ticket consumers from
t.get('key', default) / t['key'] to direct field access (t.id, t.status, etc.).
Changes:
- self.active_tickets: list[Metadata] -> list[models.Ticket]
- _deserialize_active_track_result populates self.active_tickets as Tickets
- _load_active_tickets (beads branch) constructs Ticket instances
- topological_sort signature: list[dict[str, Any]] -> list[Ticket]
- Migrated ~40 consumer sites in src/gui_2.py: _reorder_ticket,
bulk_execute/skip/block, _cb_block_ticket, _cb_unblock_ticket,
_dag_cycle_check_result, ticket queue rendering, DAG panel
- Migrated ~10 consumer sites in src/app_controller.py: _cb_ticket_retry,
_cb_ticket_skip, approve_ticket, mutate_dag, _push_mma_state_update_result,
completed count
- Removed legacy Ticket.get() compat method (Task 1.5)
- Added tests/test_metadata_promotion_phase1.py with 15 regression-guard tests
- Updated existing tests to construct Ticket instances instead of dicts
Verified: 1885 of 1910 unit tests pass (25 pre-existing failures unrelated
to Ticket migration; many are live_gui/sim tests that need a running GUI).
110 lines
3.8 KiB
Python
110 lines
3.8 KiB
Python
import pytest
|
|
from unittest.mock import patch
|
|
from src.models import Ticket
|
|
|
|
def test_ticket_priority_default():
|
|
ticket = Ticket(id="T1", description="Test ticket")
|
|
assert ticket.priority == "medium"
|
|
|
|
def test_ticket_priority_custom():
|
|
ticket_high = Ticket(id="T2", description="High priority", priority="high")
|
|
assert ticket_high.priority == "high"
|
|
|
|
ticket_low = Ticket(id="T3", description="Low priority", priority="low")
|
|
assert ticket_low.priority == "low"
|
|
|
|
def test_ticket_to_dict_priority():
|
|
ticket = Ticket(id="T4", description="To dict test", priority="high")
|
|
d = ticket.to_dict()
|
|
assert "priority" in d
|
|
assert d["priority"] == "high"
|
|
|
|
def test_ticket_from_dict_priority():
|
|
data = {
|
|
"id": "T5",
|
|
"description": "From dict test",
|
|
"priority": "low",
|
|
"status": "todo"
|
|
}
|
|
ticket = Ticket.from_dict(data)
|
|
assert ticket.priority == "low"
|
|
|
|
def test_ticket_from_dict_default_priority():
|
|
data = {
|
|
"id": "T6",
|
|
"description": "No priority in dict"
|
|
}
|
|
ticket = Ticket.from_dict(data)
|
|
assert ticket.priority == "medium"
|
|
|
|
class TestBulkOperations:
|
|
def test_bulk_execute(self, mock_app):
|
|
mock_app.active_tickets = [
|
|
Ticket(id="T1", description="T1", status="todo"),
|
|
Ticket(id="T2", description="T2", status="todo"),
|
|
Ticket(id="T3", description="T3", status="todo")
|
|
]
|
|
mock_app.ui_selected_tickets = {"T1", "T3"}
|
|
|
|
with patch.object(mock_app.controller, "_push_mma_state_update") as mock_push:
|
|
mock_app.bulk_execute()
|
|
assert mock_app.active_tickets[0].status == "in_progress"
|
|
assert mock_app.active_tickets[1].status == "todo"
|
|
assert mock_app.active_tickets[2].status == "in_progress"
|
|
mock_push.assert_called_once()
|
|
|
|
def test_bulk_skip(self, mock_app):
|
|
mock_app.active_tickets = [
|
|
Ticket(id="T1", description="T1", status="todo"),
|
|
Ticket(id="T2", description="T2", status="todo")
|
|
]
|
|
mock_app.ui_selected_tickets = {"T1"}
|
|
|
|
with patch.object(mock_app.controller, "_push_mma_state_update") as mock_push:
|
|
mock_app.bulk_skip()
|
|
assert mock_app.active_tickets[0].status == "completed"
|
|
assert mock_app.active_tickets[1].status == "todo"
|
|
mock_push.assert_called_once()
|
|
|
|
def test_bulk_block(self, mock_app):
|
|
mock_app.active_tickets = [
|
|
Ticket(id="T1", description="T1", status="todo"),
|
|
Ticket(id="T2", description="T2", status="todo")
|
|
]
|
|
mock_app.ui_selected_tickets = {"T1", "T2"}
|
|
|
|
with patch.object(mock_app.controller, "_push_mma_state_update") as mock_push:
|
|
mock_app.bulk_block()
|
|
assert mock_app.active_tickets[0].status == "blocked"
|
|
assert mock_app.active_tickets[1].status == "blocked"
|
|
mock_push.assert_called_once()
|
|
|
|
class TestReorder:
|
|
def test_reorder_ticket_valid(self, mock_app):
|
|
mock_app.active_tickets = [
|
|
Ticket(id="T1", description="T1", depends_on=[]),
|
|
Ticket(id="T2", description="T2", depends_on=[]),
|
|
Ticket(id="T3", description="T3", depends_on=["T1"])
|
|
]
|
|
with patch.object(mock_app.controller, "_push_mma_state_update") as mock_push:
|
|
# Move T1 to index 1: [T2, T1, T3]. T3 depends on T1. T1 index 1 < T3 index 2. VALID.
|
|
mock_app._reorder_ticket(0, 1)
|
|
assert mock_app.active_tickets[0].id == "T2"
|
|
assert mock_app.active_tickets[1].id == "T1"
|
|
assert mock_app.active_tickets[2].id == "T3"
|
|
mock_push.assert_called_once()
|
|
|
|
def test_reorder_ticket_invalid(self, mock_app):
|
|
mock_app.active_tickets = [
|
|
Ticket(id="T1", description="T1", depends_on=[]),
|
|
Ticket(id="T2", description="T2", depends_on=["T1"])
|
|
]
|
|
with patch.object(mock_app.controller, "_push_mma_state_update") as mock_push:
|
|
# Move T1 after T2: [T2, T1]. T2 depends on T1, but T1 is now at index 1 while T2 is at index 0.
|
|
# Violation: dependency T1 (index 1) is not before T2 (index 0).
|
|
mock_app._reorder_ticket(0, 1)
|
|
# Should NOT change
|
|
assert mock_app.active_tickets[0].id == "T1"
|
|
assert mock_app.active_tickets[1].id == "T2"
|
|
mock_push.assert_not_called()
|