fix: update remaining tests and session_to_tree for title field rename
- test_tree_validation.py: replace "action"/"solution" content fields with "title" - test_procedural_flows.py: update solution node fixtures to use "title" - test_save_session_as_tree.py: update fixtures and assertions for "title" field - session_to_tree.py: generate "title" instead of "action"/"solution" on converted nodes; fall back to legacy field names when reading from old tree snapshots for compatibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,7 @@ def convert_session_to_tree(
|
|||||||
return {
|
return {
|
||||||
"id": str(uuid.uuid4()),
|
"id": str(uuid.uuid4()),
|
||||||
"type": "solution",
|
"type": "solution",
|
||||||
"solution": "Session had no recorded path",
|
"title": "Session had no recorded path",
|
||||||
"children": []
|
"children": []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ def convert_session_to_tree(
|
|||||||
new_node = {
|
new_node = {
|
||||||
"id": node_id,
|
"id": node_id,
|
||||||
"type": "action",
|
"type": "action",
|
||||||
"action": f"Step from original tree (node {node_id})",
|
"title": f"Step from original tree (node {node_id})",
|
||||||
"children": []
|
"children": []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,15 +130,15 @@ def _create_node_from_original(
|
|||||||
if decision and decision.get("answer"):
|
if decision and decision.get("answer"):
|
||||||
new_node["question"] += f"\n\nAnswer: {decision['answer']}"
|
new_node["question"] += f"\n\nAnswer: {decision['answer']}"
|
||||||
elif node_type == "action":
|
elif node_type == "action":
|
||||||
new_node["action"] = original_node.get("action", "")
|
new_node["title"] = original_node.get("title", original_node.get("action", ""))
|
||||||
if decision and decision.get("action_performed"):
|
if decision and decision.get("action_performed"):
|
||||||
new_node["action"] = decision["action_performed"]
|
new_node["title"] = decision["action_performed"]
|
||||||
if decision and decision.get("command_output"):
|
if decision and decision.get("command_output"):
|
||||||
output = decision["command_output"].strip()
|
output = decision["command_output"].strip()
|
||||||
if output:
|
if output:
|
||||||
new_node["action"] += f"\n\nCommand Output:\n{output}"
|
new_node["title"] += f"\n\nCommand Output:\n{output}"
|
||||||
elif node_type == "solution":
|
elif node_type == "solution":
|
||||||
new_node["solution"] = original_node.get("solution", "")
|
new_node["title"] = original_node.get("title", original_node.get("solution", ""))
|
||||||
|
|
||||||
return new_node
|
return new_node
|
||||||
|
|
||||||
@@ -169,18 +169,18 @@ def _create_node_from_custom_step(
|
|||||||
if step_type == "decision":
|
if step_type == "decision":
|
||||||
new_node["question"] = content
|
new_node["question"] = content
|
||||||
elif step_type == "action":
|
elif step_type == "action":
|
||||||
new_node["action"] = content
|
new_node["title"] = content
|
||||||
elif step_type == "solution":
|
elif step_type == "solution":
|
||||||
new_node["solution"] = content
|
new_node["title"] = content
|
||||||
|
|
||||||
# Add notes if present
|
# Add notes if present
|
||||||
if custom_step.get("notes"):
|
if custom_step.get("notes"):
|
||||||
if step_type == "decision":
|
if step_type == "decision":
|
||||||
new_node["question"] += f"\n\nNotes: {custom_step['notes']}"
|
new_node["question"] += f"\n\nNotes: {custom_step['notes']}"
|
||||||
elif step_type == "action":
|
elif step_type == "action":
|
||||||
new_node["action"] += f"\n\nNotes: {custom_step['notes']}"
|
new_node["title"] += f"\n\nNotes: {custom_step['notes']}"
|
||||||
elif step_type == "solution":
|
elif step_type == "solution":
|
||||||
new_node["solution"] += f"\n\nNotes: {custom_step['notes']}"
|
new_node["title"] += f"\n\nNotes: {custom_step['notes']}"
|
||||||
|
|
||||||
return new_node
|
return new_node
|
||||||
|
|
||||||
|
|||||||
@@ -228,8 +228,8 @@ class TestCanPublishTreeDispatch:
|
|||||||
"type": "decision",
|
"type": "decision",
|
||||||
"question": "Test?",
|
"question": "Test?",
|
||||||
"children": [
|
"children": [
|
||||||
{"id": "y", "type": "solution", "solution": "Yes"},
|
{"id": "y", "type": "solution", "title": "Yes"},
|
||||||
{"id": "n", "type": "solution", "solution": "No"},
|
{"id": "n", "type": "solution", "title": "No"},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
can, errors = can_publish_tree(structure, "My Tree", tree_type="troubleshooting")
|
can, errors = can_publish_tree(structure, "My Tree", tree_type="troubleshooting")
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class TestSessionToTreeConversion:
|
|||||||
"""Test converting a session with no path."""
|
"""Test converting a session with no path."""
|
||||||
tree_structure = convert_session_to_tree([], {}, [], [])
|
tree_structure = convert_session_to_tree([], {}, [], [])
|
||||||
assert tree_structure["type"] == "solution"
|
assert tree_structure["type"] == "solution"
|
||||||
assert "no recorded path" in tree_structure["solution"].lower()
|
assert "no recorded path" in tree_structure["title"].lower()
|
||||||
|
|
||||||
def test_convert_simple_linear_path(self):
|
def test_convert_simple_linear_path(self):
|
||||||
"""Test converting a simple linear path."""
|
"""Test converting a simple linear path."""
|
||||||
@@ -29,8 +29,8 @@ class TestSessionToTreeConversion:
|
|||||||
"type": "decision",
|
"type": "decision",
|
||||||
"question": "Is it working?",
|
"question": "Is it working?",
|
||||||
"children": [
|
"children": [
|
||||||
{"id": "yes", "type": "solution", "solution": "Great!"},
|
{"id": "yes", "type": "solution", "title": "Great!"},
|
||||||
{"id": "no", "type": "action", "action": "Fix it"}
|
{"id": "no", "type": "action", "title": "Fix it"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path_taken = ["root", "no"]
|
path_taken = ["root", "no"]
|
||||||
@@ -51,7 +51,7 @@ class TestSessionToTreeConversion:
|
|||||||
tree_snapshot = {
|
tree_snapshot = {
|
||||||
"id": "root",
|
"id": "root",
|
||||||
"type": "solution",
|
"type": "solution",
|
||||||
"solution": "Done"
|
"title": "Done"
|
||||||
}
|
}
|
||||||
custom_step_id = "custom-123"
|
custom_step_id = "custom-123"
|
||||||
path_taken = ["root", custom_step_id]
|
path_taken = ["root", custom_step_id]
|
||||||
@@ -70,7 +70,7 @@ class TestSessionToTreeConversion:
|
|||||||
assert len(result["children"]) == 1
|
assert len(result["children"]) == 1
|
||||||
custom_node = result["children"][0]
|
custom_node = result["children"][0]
|
||||||
assert custom_node["type"] == "action"
|
assert custom_node["type"] == "action"
|
||||||
assert "Custom troubleshooting step" in custom_node["action"]
|
assert "Custom troubleshooting step" in custom_node["title"]
|
||||||
|
|
||||||
def test_find_node_in_tree(self):
|
def test_find_node_in_tree(self):
|
||||||
"""Test finding a node in nested tree structure."""
|
"""Test finding a node in nested tree structure."""
|
||||||
@@ -142,7 +142,7 @@ class TestSaveSessionAsTreeAPI:
|
|||||||
tree = Tree(
|
tree = Tree(
|
||||||
name="Test Tree",
|
name="Test Tree",
|
||||||
description="Test",
|
description="Test",
|
||||||
tree_structure={"id": "root", "type": "solution", "solution": "Fix"},
|
tree_structure={"id": "root", "type": "solution", "title": "Fix"},
|
||||||
author_id=UUID(test_user["user_data"]["id"]),
|
author_id=UUID(test_user["user_data"]["id"]),
|
||||||
account_id=UUID(test_user["user_data"]["account_id"]),
|
account_id=UUID(test_user["user_data"]["account_id"]),
|
||||||
status='published'
|
status='published'
|
||||||
@@ -187,7 +187,7 @@ class TestSaveSessionAsTreeAPI:
|
|||||||
|
|
||||||
tree = Tree(
|
tree = Tree(
|
||||||
name="Original Tree",
|
name="Original Tree",
|
||||||
tree_structure={"id": "root", "type": "solution", "solution": "Fix"},
|
tree_structure={"id": "root", "type": "solution", "title": "Fix"},
|
||||||
author_id=UUID(test_user["user_data"]["id"]),
|
author_id=UUID(test_user["user_data"]["id"]),
|
||||||
account_id=UUID(test_user["user_data"]["account_id"]),
|
account_id=UUID(test_user["user_data"]["account_id"]),
|
||||||
status='published'
|
status='published'
|
||||||
@@ -227,7 +227,7 @@ class TestSaveSessionAsTreeAPI:
|
|||||||
# Create a simple tree with just a solution (will convert to valid linear tree)
|
# Create a simple tree with just a solution (will convert to valid linear tree)
|
||||||
tree = Tree(
|
tree = Tree(
|
||||||
name="Test Tree",
|
name="Test Tree",
|
||||||
tree_structure={"id": "root", "type": "solution", "solution": "Fixed"},
|
tree_structure={"id": "root", "type": "solution", "title": "Fixed"},
|
||||||
author_id=UUID(test_user["user_data"]["id"]),
|
author_id=UUID(test_user["user_data"]["id"]),
|
||||||
account_id=UUID(test_user["user_data"]["account_id"]),
|
account_id=UUID(test_user["user_data"]["account_id"]),
|
||||||
status='published'
|
status='published'
|
||||||
@@ -267,7 +267,7 @@ class TestSaveSessionAsTreeAPI:
|
|||||||
|
|
||||||
tree = Tree(
|
tree = Tree(
|
||||||
name="Original Tree",
|
name="Original Tree",
|
||||||
tree_structure={"id": "root", "type": "solution", "solution": "Fix"},
|
tree_structure={"id": "root", "type": "solution", "title": "Fix"},
|
||||||
author_id=UUID(test_user["user_data"]["id"]),
|
author_id=UUID(test_user["user_data"]["id"]),
|
||||||
account_id=UUID(test_user["user_data"]["account_id"]),
|
account_id=UUID(test_user["user_data"]["account_id"]),
|
||||||
status='published'
|
status='published'
|
||||||
@@ -326,7 +326,7 @@ class TestSaveSessionAsTreeAPI:
|
|||||||
# Create a tree
|
# Create a tree
|
||||||
tree = Tree(
|
tree = Tree(
|
||||||
name="Test Tree",
|
name="Test Tree",
|
||||||
tree_structure={"id": "root", "type": "solution", "solution": "Fix"},
|
tree_structure={"id": "root", "type": "solution", "title": "Fix"},
|
||||||
author_id=UUID(test_user["user_data"]["id"]),
|
author_id=UUID(test_user["user_data"]["id"]),
|
||||||
account_id=UUID(test_user["user_data"]["account_id"]),
|
account_id=UUID(test_user["user_data"]["account_id"]),
|
||||||
status='published'
|
status='published'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class TestValidateTreeStructure:
|
|||||||
|
|
||||||
def test_valid_solution_tree(self):
|
def test_valid_solution_tree(self):
|
||||||
valid, errors = validate_tree_structure({
|
valid, errors = validate_tree_structure({
|
||||||
"id": "root", "type": "solution", "solution": "Done"
|
"id": "root", "type": "solution", "title": "Done"
|
||||||
})
|
})
|
||||||
assert valid
|
assert valid
|
||||||
assert errors == []
|
assert errors == []
|
||||||
@@ -26,8 +26,8 @@ class TestValidateTreeStructure:
|
|||||||
"type": "decision",
|
"type": "decision",
|
||||||
"question": "Is it on?",
|
"question": "Is it on?",
|
||||||
"children": [
|
"children": [
|
||||||
{"id": "yes", "type": "solution", "solution": "Great"},
|
{"id": "yes", "type": "solution", "title": "Great"},
|
||||||
{"id": "no", "type": "action", "action": "Turn it on"},
|
{"id": "no", "type": "action", "title": "Turn it on"},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
assert valid
|
assert valid
|
||||||
@@ -39,7 +39,7 @@ class TestValidateTreeStructure:
|
|||||||
assert any("empty" in e["message"].lower() for e in errors)
|
assert any("empty" in e["message"].lower() for e in errors)
|
||||||
|
|
||||||
def test_missing_id_on_root(self):
|
def test_missing_id_on_root(self):
|
||||||
valid, errors = validate_tree_structure({"type": "solution", "solution": "X"})
|
valid, errors = validate_tree_structure({"type": "solution", "title": "X"})
|
||||||
assert not valid
|
assert not valid
|
||||||
assert any("id" in e["field"] for e in errors)
|
assert any("id" in e["field"] for e in errors)
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class TestValidateTreeStructure:
|
|||||||
"type": "decision",
|
"type": "decision",
|
||||||
"question": "Q?",
|
"question": "Q?",
|
||||||
"children": [
|
"children": [
|
||||||
{"id": "only", "type": "solution", "solution": "S"},
|
{"id": "only", "type": "solution", "title": "S"},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
@@ -80,29 +80,29 @@ class TestValidateTreeStructure:
|
|||||||
})
|
})
|
||||||
assert valid
|
assert valid
|
||||||
|
|
||||||
def test_action_missing_action_field(self):
|
def test_action_missing_title_field(self):
|
||||||
valid, errors = validate_tree_structure({
|
valid, errors = validate_tree_structure({
|
||||||
"id": "root", "type": "action"
|
"id": "root", "type": "action"
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
assert any("action" in e["message"].lower() for e in errors)
|
assert any("title" in e["message"].lower() for e in errors)
|
||||||
|
|
||||||
def test_action_with_empty_action(self):
|
def test_action_with_empty_title(self):
|
||||||
valid, errors = validate_tree_structure({
|
valid, errors = validate_tree_structure({
|
||||||
"id": "root", "type": "action", "action": ""
|
"id": "root", "type": "action", "title": ""
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
|
|
||||||
def test_solution_missing_solution_field(self):
|
def test_solution_missing_title_field(self):
|
||||||
valid, errors = validate_tree_structure({
|
valid, errors = validate_tree_structure({
|
||||||
"id": "root", "type": "solution"
|
"id": "root", "type": "solution"
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
assert any("solution" in e["message"].lower() for e in errors)
|
assert any("title" in e["message"].lower() for e in errors)
|
||||||
|
|
||||||
def test_solution_with_empty_solution(self):
|
def test_solution_with_empty_title(self):
|
||||||
valid, errors = validate_tree_structure({
|
valid, errors = validate_tree_structure({
|
||||||
"id": "root", "type": "solution", "solution": ""
|
"id": "root", "type": "solution", "title": ""
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
|
|
||||||
@@ -119,8 +119,8 @@ class TestValidateTreeStructure:
|
|||||||
"type": "decision",
|
"type": "decision",
|
||||||
"question": "Q?",
|
"question": "Q?",
|
||||||
"children": [
|
"children": [
|
||||||
{"type": "solution", "solution": "S1"},
|
{"type": "solution", "title": "S1"},
|
||||||
{"id": "c2", "type": "solution", "solution": "S2"},
|
{"id": "c2", "type": "solution", "title": "S2"},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
@@ -133,7 +133,7 @@ class TestValidateTreeStructure:
|
|||||||
"question": "Q?",
|
"question": "Q?",
|
||||||
"children": [
|
"children": [
|
||||||
{"id": "c1"},
|
{"id": "c1"},
|
||||||
{"id": "c2", "type": "solution", "solution": "S2"},
|
{"id": "c2", "type": "solution", "title": "S2"},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
@@ -151,11 +151,11 @@ class TestValidateTreeStructure:
|
|||||||
"type": "decision",
|
"type": "decision",
|
||||||
"question": "Level 2?",
|
"question": "Level 2?",
|
||||||
"children": [
|
"children": [
|
||||||
{"id": "l3a", "type": "solution", "solution": "Deep"},
|
{"id": "l3a", "type": "solution", "title": "Deep"},
|
||||||
{"id": "l3b", "type": "solution"}, # Missing solution
|
{"id": "l3b", "type": "solution"}, # Missing title
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{"id": "l2b", "type": "solution", "solution": "Shallow"},
|
{"id": "l2b", "type": "solution", "title": "Shallow"},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
@@ -167,8 +167,8 @@ class TestValidateTreeStructure:
|
|||||||
"type": "decision",
|
"type": "decision",
|
||||||
"question": "Q?",
|
"question": "Q?",
|
||||||
"children": [
|
"children": [
|
||||||
{"id": "c1", "type": "solution"}, # missing solution
|
{"id": "c1", "type": "solution"}, # missing title
|
||||||
{"id": "c2", "type": "action"}, # missing action
|
{"id": "c2", "type": "action"}, # missing title
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
assert not valid
|
assert not valid
|
||||||
@@ -179,7 +179,7 @@ class TestCanPublishTree:
|
|||||||
|
|
||||||
def test_valid_tree_can_publish(self):
|
def test_valid_tree_can_publish(self):
|
||||||
can, errors = can_publish_tree(
|
can, errors = can_publish_tree(
|
||||||
{"id": "root", "type": "solution", "solution": "Done"},
|
{"id": "root", "type": "solution", "title": "Done"},
|
||||||
"My Tree"
|
"My Tree"
|
||||||
)
|
)
|
||||||
assert can
|
assert can
|
||||||
@@ -187,7 +187,7 @@ class TestCanPublishTree:
|
|||||||
|
|
||||||
def test_empty_name_cannot_publish(self):
|
def test_empty_name_cannot_publish(self):
|
||||||
can, errors = can_publish_tree(
|
can, errors = can_publish_tree(
|
||||||
{"id": "root", "type": "solution", "solution": "Done"},
|
{"id": "root", "type": "solution", "title": "Done"},
|
||||||
""
|
""
|
||||||
)
|
)
|
||||||
assert not can
|
assert not can
|
||||||
@@ -195,14 +195,14 @@ class TestCanPublishTree:
|
|||||||
|
|
||||||
def test_whitespace_name_cannot_publish(self):
|
def test_whitespace_name_cannot_publish(self):
|
||||||
can, errors = can_publish_tree(
|
can, errors = can_publish_tree(
|
||||||
{"id": "root", "type": "solution", "solution": "Done"},
|
{"id": "root", "type": "solution", "title": "Done"},
|
||||||
" "
|
" "
|
||||||
)
|
)
|
||||||
assert not can
|
assert not can
|
||||||
|
|
||||||
def test_none_name_cannot_publish(self):
|
def test_none_name_cannot_publish(self):
|
||||||
can, errors = can_publish_tree(
|
can, errors = can_publish_tree(
|
||||||
{"id": "root", "type": "solution", "solution": "Done"},
|
{"id": "root", "type": "solution", "title": "Done"},
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
assert not can
|
assert not can
|
||||||
|
|||||||
Reference in New Issue
Block a user