Spiritual_Health_Project / tests /prompt_optimization /test_session_prompt_adoption.py
DocUA's picture
feat: Complete prompt optimization system implementation
24214fc
"""
Test suite for session prompt adoption workflow.
This module tests the session prompt adoption workflow including:
- Promoting session overrides to permanent files
- Validation before adoption
- Backup and rollback capabilities
- Error handling for adoption process
**Feature: prompt-optimization, Task 11.5: Add session prompt adoption workflow**
**Validates: Requirements 9.5**
"""
import pytest
import sys
import tempfile
import os
from pathlib import Path
from unittest.mock import patch, mock_open, MagicMock
from datetime import datetime
# Add src to path for imports
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'src'))
from config.prompt_management.prompt_controller import PromptController
class TestSessionPromptAdoption:
"""Test session prompt adoption workflow functionality."""
def setup_method(self):
"""Set up test environment."""
self.controller = PromptController()
# Clear any existing state
self.controller._prompt_cache.clear()
self.controller._session_overrides.clear()
def test_promote_session_to_file_success(self):
"""Test successful promotion of session override to file."""
agent_type = 'spiritual_monitor'
session_id = 'test_promotion_session'
override_content = """
<system_role>
Updated spiritual monitor prompt for testing promotion workflow.
This content should be promoted to the permanent file.
</system_role>
<output_format>
Respond with JSON: {"state": "green|yellow|red", "confidence": 0.0-1.0}
</output_format>
"""
# Set session override
success = self.controller.set_session_override(agent_type, override_content, session_id)
assert success, "Session override should be set successfully"
# Mock file operations to avoid actual file changes
with patch('pathlib.Path.exists', return_value=True), \
patch('pathlib.Path.rename') as mock_rename, \
patch('builtins.open', mock_open()) as mock_file:
# Promote session to file
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should succeed
assert result, "Promotion should succeed"
# Verify backup was created
mock_rename.assert_called_once()
# Verify file was written
mock_file.assert_called_once()
handle = mock_file()
handle.write.assert_called_once_with(override_content)
def test_promote_session_to_file_with_backup(self):
"""Test that promotion creates proper backup of existing file."""
agent_type = 'triage_question'
session_id = 'backup_test_session'
override_content = "New triage question prompt content"
# Set session override
self.controller.set_session_override(agent_type, override_content, session_id)
# Mock file operations - test that backup logic is invoked
with patch('pathlib.Path.exists', return_value=True), \
patch('pathlib.Path.rename') as mock_rename, \
patch('pathlib.Path.with_suffix') as mock_with_suffix, \
patch('builtins.open', mock_open()):
# Setup mock backup path
mock_backup_path = MagicMock()
mock_with_suffix.return_value = mock_backup_path
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should succeed
assert result, "Promotion with backup should succeed"
# Verify backup path was created with timestamp
assert mock_with_suffix.called, "Backup path should be created"
if mock_with_suffix.called:
backup_call_args = str(mock_with_suffix.call_args[0][0])
assert '.backup.' in backup_call_args
assert datetime.now().strftime('%Y%m%d') in backup_call_args
def test_promote_session_to_file_no_override(self):
"""Test promotion when no session override exists."""
agent_type = 'spiritual_monitor'
session_id = 'no_override_session'
# Try to promote without setting override
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should fail gracefully
assert not result, "Promotion should fail when no override exists"
def test_promote_session_to_file_clears_override(self):
"""Test that promotion clears the session override."""
agent_type = 'triage_evaluator'
session_id = 'clear_override_session'
override_content = "Content to be promoted and cleared"
# Set session override
self.controller.set_session_override(agent_type, override_content, session_id)
# Verify override exists
assert self.controller._has_session_override(agent_type, session_id)
# Mock file operations
with patch('pathlib.Path.exists', return_value=False), \
patch('builtins.open', mock_open()):
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should succeed
assert result, "Promotion should succeed"
# Verify override was cleared
assert not self.controller._has_session_override(agent_type, session_id)
def test_promote_session_to_file_clears_cache(self):
"""Test that promotion clears the prompt cache."""
agent_type = 'spiritual_monitor'
session_id = 'cache_clear_session'
override_content = "Content for cache clearing test"
# Set session override and load config to populate cache
self.controller.set_session_override(agent_type, override_content, session_id)
config = self.controller.get_prompt(agent_type, session_id=session_id)
# Verify cache is populated
cache_key = f"{agent_type}_{session_id}"
assert cache_key in self.controller._prompt_cache
# Mock file operations
with patch('pathlib.Path.exists', return_value=False), \
patch('builtins.open', mock_open()):
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should succeed
assert result, "Promotion should succeed"
# Verify cache was cleared
assert len(self.controller._prompt_cache) == 0
def test_promote_session_to_file_error_handling(self):
"""Test error handling during promotion process."""
agent_type = 'spiritual_monitor'
session_id = 'error_test_session'
override_content = "Content for error testing"
# Set session override
self.controller.set_session_override(agent_type, override_content, session_id)
# Mock file operation that raises exception
with patch('pathlib.Path.exists', return_value=True), \
patch('pathlib.Path.rename', side_effect=OSError("Permission denied")):
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should fail gracefully
assert not result, "Promotion should fail gracefully on file errors"
# Session override should still exist (not cleared on failure)
assert self.controller._has_session_override(agent_type, session_id)
def test_promote_session_validation_before_adoption(self):
"""Test validation of session content before promotion."""
agent_type = 'spiritual_monitor'
session_id = 'validation_test_session'
# Test with empty content (should still work but might be flagged)
empty_content = ""
self.controller.set_session_override(agent_type, empty_content, session_id)
with patch('pathlib.Path.exists', return_value=False), \
patch('builtins.open', mock_open()):
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should still succeed (validation is informational, not blocking)
assert result, "Promotion should succeed even with empty content"
def test_promote_session_with_placeholders(self):
"""Test promotion of session content containing placeholders."""
agent_type = 'spiritual_monitor'
session_id = 'placeholder_test_session'
override_content = """
<system_role>
You are a spiritual distress classifier.
Use these indicators:
{{SHARED_INDICATORS}}
Apply these rules:
{{SHARED_RULES}}
</system_role>
"""
# Set session override with placeholders
self.controller.set_session_override(agent_type, override_content, session_id)
# Mock file operations
with patch('pathlib.Path.exists', return_value=False), \
patch('builtins.open', mock_open()) as mock_file:
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should succeed
assert result, "Promotion should succeed with placeholder content"
# Verify original content (with placeholders) was written to file
handle = mock_file()
written_content = handle.write.call_args[0][0]
assert "{{SHARED_INDICATORS}}" in written_content
assert "{{SHARED_RULES}}" in written_content
def test_multiple_session_promotions(self):
"""Test promoting multiple different sessions."""
sessions_data = [
('spiritual_monitor', 'session_1', 'Content for session 1'),
('triage_question', 'session_2', 'Content for session 2'),
('triage_evaluator', 'session_3', 'Content for session 3')
]
# Set all session overrides
for agent_type, session_id, content in sessions_data:
success = self.controller.set_session_override(agent_type, content, session_id)
assert success, f"Should set override for {agent_type} session {session_id}"
# Promote all sessions
with patch('pathlib.Path.exists', return_value=False), \
patch('builtins.open', mock_open()):
for agent_type, session_id, content in sessions_data:
result = self.controller.promote_session_to_file(agent_type, session_id)
assert result, f"Should promote {agent_type} session {session_id}"
# Verify override was cleared
assert not self.controller._has_session_override(agent_type, session_id)
def test_promote_session_rollback_capability(self):
"""Test that backup files enable rollback capability."""
agent_type = 'spiritual_monitor'
session_id = 'rollback_test_session'
override_content = "New content that might need rollback"
# Set session override
self.controller.set_session_override(agent_type, override_content, session_id)
# Mock file operations to test backup creation
with patch('pathlib.Path.exists', return_value=True), \
patch('pathlib.Path.rename') as mock_rename, \
patch('pathlib.Path.with_suffix') as mock_with_suffix, \
patch('builtins.open', mock_open()):
# Setup mock backup path
mock_backup_path = MagicMock()
mock_with_suffix.return_value = mock_backup_path
result = self.controller.promote_session_to_file(agent_type, session_id)
# Should succeed
assert result, "Promotion should succeed"
# Verify backup operations were called
assert mock_with_suffix.called, "Backup path should be created"
assert mock_rename.called, "File should be renamed for backup"
# Verify backup path has correct format
if mock_with_suffix.called:
backup_call_args = str(mock_with_suffix.call_args[0][0])
assert '.backup.' in backup_call_args, "Backup should have .backup. in filename"
class TestSessionPromptAdoptionIntegration:
"""Test integration aspects of session prompt adoption."""
def setup_method(self):
"""Set up test environment."""
self.controller = PromptController()
self.controller._prompt_cache.clear()
self.controller._session_overrides.clear()
def test_adoption_workflow_end_to_end(self):
"""Test complete adoption workflow from session to file."""
agent_type = 'spiritual_monitor'
session_id = 'end_to_end_session'
# Step 1: Get original prompt
original_config = self.controller.get_prompt(agent_type)
original_content = original_config.base_prompt
# Step 2: Set session override
override_content = "Modified prompt content for end-to-end test"
success = self.controller.set_session_override(agent_type, override_content, session_id)
assert success
# Step 3: Verify session override is active
session_config = self.controller.get_prompt(agent_type, session_id=session_id)
assert override_content in session_config.base_prompt
# Step 4: Promote to file
with patch('pathlib.Path.exists', return_value=True), \
patch('pathlib.Path.rename'), \
patch('builtins.open', mock_open()):
promotion_result = self.controller.promote_session_to_file(agent_type, session_id)
assert promotion_result
# Step 5: Verify session override was cleared
assert not self.controller._has_session_override(agent_type, session_id)
# Step 6: Verify cache was cleared
assert len(self.controller._prompt_cache) == 0
def test_adoption_preserves_shared_components(self):
"""Test that adoption preserves shared component integration."""
agent_type = 'spiritual_monitor'
session_id = 'shared_components_session'
# Create override with shared component placeholders
override_content = """
<system_role>
Enhanced spiritual monitor with shared components:
{{SHARED_INDICATORS}}
{{SHARED_RULES}}
</system_role>
"""
# Set session override
self.controller.set_session_override(agent_type, override_content, session_id)
# Get session config to verify placeholder replacement works
session_config = self.controller.get_prompt(agent_type, session_id=session_id)
assert '{{SHARED_INDICATORS}}' not in session_config.base_prompt
assert '{{SHARED_RULES}}' not in session_config.base_prompt
# Promote to file (should preserve original placeholders)
with patch('pathlib.Path.exists', return_value=False), \
patch('builtins.open', mock_open()) as mock_file:
result = self.controller.promote_session_to_file(agent_type, session_id)
assert result
# Verify original content with placeholders was written
written_content = mock_file().write.call_args[0][0]
assert '{{SHARED_INDICATORS}}' in written_content
assert '{{SHARED_RULES}}' in written_content
if __name__ == '__main__':
pytest.main([__file__, '-v'])