DocUA's picture
✅ Enhanced Verification Modes - Production Ready
7bbd836
# test_feedback_handler.py
"""
Tests for verification feedback handler.
Tests feedback collection, validation, and storage functionality.
"""
import pytest
from datetime import datetime
from src.core.verification_feedback_handler import (
VerificationFeedbackHandler,
FeedbackValidationError,
)
from src.core.verification_models import (
VerificationRecord,
VerificationSession,
TestMessage,
)
from src.core.verification_store import JSONVerificationStore
from src.core.message_queue_manager import MessageQueueManager
class TestCorrectFeedbackHandling:
"""Tests for handling 'Correct' feedback."""
def test_handle_correct_feedback_saves_record(
self, sample_verification_session, temp_storage_dir
):
"""Verify correct feedback saves verification record."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="I'm feeling anxious",
pre_classified_label="yellow",
),
TestMessage(
message_id="msg_002",
text="I'm feeling great",
pre_classified_label="green",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Handle correct feedback
result = handler.handle_correct_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
)
assert result is True
# Verify record was saved
loaded_session = store.load_session(sample_verification_session.session_id)
assert len(loaded_session.verifications) == 1
assert loaded_session.verifications[0].message_id == "msg_001"
assert loaded_session.verifications[0].is_correct is True
def test_handle_correct_feedback_marks_as_correct(
self, sample_verification_session, temp_storage_dir
):
"""Verify correct feedback marks record as correct."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="I'm feeling anxious",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
handler.handle_correct_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
)
loaded_session = store.load_session(sample_verification_session.session_id)
record = loaded_session.verifications[0]
assert record.is_correct is True
assert record.ground_truth_label == "yellow"
assert record.classifier_decision == "yellow"
def test_handle_correct_feedback_advances_queue(
self, sample_verification_session, temp_storage_dir
):
"""Verify correct feedback advances to next message."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="First message",
pre_classified_label="yellow",
),
TestMessage(
message_id="msg_002",
text="Second message",
pre_classified_label="green",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Initially at first message
assert queue_manager.get_current_message_id() == "msg_001"
# Handle correct feedback
handler.handle_correct_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
)
# Should advance to second message
assert queue_manager.get_current_message_id() == "msg_002"
def test_handle_correct_feedback_stores_all_fields(
self, sample_verification_session, temp_storage_dir
):
"""Verify correct feedback stores all required fields."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Test message",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
handler.handle_correct_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.92,
classifier_indicators=["anxiety", "stress"],
)
loaded_session = store.load_session(sample_verification_session.session_id)
record = loaded_session.verifications[0]
assert record.message_id == "msg_001"
assert record.original_message == "Test message"
assert record.classifier_decision == "yellow"
assert record.classifier_confidence == 0.92
assert record.classifier_indicators == ["anxiety", "stress"]
assert record.ground_truth_label == "yellow"
assert record.verifier_notes == ""
assert record.is_correct is True
assert isinstance(record.timestamp, datetime)
class TestIncorrectFeedbackHandling:
"""Tests for handling 'Incorrect' feedback."""
def test_handle_incorrect_feedback_saves_record(
self, sample_verification_session, temp_storage_dir
):
"""Verify incorrect feedback saves verification record."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="I'm feeling anxious",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Handle incorrect feedback
result = handler.handle_incorrect_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
ground_truth_label="red",
verifier_notes="Missed severe indicators",
)
assert result is True
# Verify record was saved
loaded_session = store.load_session(sample_verification_session.session_id)
assert len(loaded_session.verifications) == 1
assert loaded_session.verifications[0].message_id == "msg_001"
assert loaded_session.verifications[0].is_correct is False
def test_handle_incorrect_feedback_marks_as_incorrect(
self, sample_verification_session, temp_storage_dir
):
"""Verify incorrect feedback marks record as incorrect."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="I'm feeling anxious",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
handler.handle_incorrect_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
ground_truth_label="red",
verifier_notes="",
)
loaded_session = store.load_session(sample_verification_session.session_id)
record = loaded_session.verifications[0]
assert record.is_correct is False
assert record.ground_truth_label == "red"
assert record.classifier_decision == "yellow"
def test_handle_incorrect_feedback_stores_notes(
self, sample_verification_session, temp_storage_dir
):
"""Verify incorrect feedback stores optional notes."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Test message",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
notes = "Missed severe distress indicators"
handler.handle_incorrect_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
ground_truth_label="red",
verifier_notes=notes,
)
loaded_session = store.load_session(sample_verification_session.session_id)
record = loaded_session.verifications[0]
assert record.verifier_notes == notes
def test_handle_incorrect_feedback_advances_queue(
self, sample_verification_session, temp_storage_dir
):
"""Verify incorrect feedback advances to next message."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="First message",
pre_classified_label="yellow",
),
TestMessage(
message_id="msg_002",
text="Second message",
pre_classified_label="green",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Initially at first message
assert queue_manager.get_current_message_id() == "msg_001"
# Handle incorrect feedback
handler.handle_incorrect_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
ground_truth_label="red",
verifier_notes="",
)
# Should advance to second message
assert queue_manager.get_current_message_id() == "msg_002"
def test_handle_incorrect_feedback_requires_correction(
self, sample_verification_session, temp_storage_dir
):
"""Verify incorrect feedback requires correction selection."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Test message",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Try to handle incorrect feedback without correction
with pytest.raises(FeedbackValidationError) as exc_info:
handler.handle_incorrect_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
ground_truth_label="",
verifier_notes="",
)
assert "Please select a correction" in str(exc_info.value)
def test_handle_incorrect_feedback_validates_correction_option(
self, sample_verification_session, temp_storage_dir
):
"""Verify incorrect feedback validates correction is valid option."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Test message",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Try to handle incorrect feedback with invalid correction
with pytest.raises(FeedbackValidationError) as exc_info:
handler.handle_incorrect_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
ground_truth_label="invalid",
verifier_notes="",
)
assert "Invalid correction option" in str(exc_info.value)
def test_handle_incorrect_feedback_accepts_all_valid_corrections(
self, sample_verification_session, temp_storage_dir
):
"""Verify incorrect feedback accepts all valid correction options."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
# Test each correction option with a different classifier decision
# to ensure the correction is actually different from the classifier's decision
test_cases = [
("green", "yellow"), # classifier says yellow, correction is green
("yellow", "red"), # classifier says red, correction is yellow
("red", "green"), # classifier says green, correction is red
]
for correction, classifier_decision in test_cases:
session = VerificationSession(
session_id=f"session_{correction}",
verifier_name="Test Verifier",
dataset_id="dataset_001",
dataset_name="Test Dataset",
)
store.save_session(session)
queue_manager = MessageQueueManager(session)
messages = [
TestMessage(
message_id=f"msg_{correction}",
text="Test message",
pre_classified_label=classifier_decision,
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(session, store, queue_manager)
# Should not raise exception - correction is different from classifier decision
result = handler.handle_incorrect_feedback(
message=messages[0],
classifier_decision=classifier_decision,
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
ground_truth_label=correction,
verifier_notes="",
)
assert result is True
class TestFeedbackValidation:
"""Tests for feedback validation."""
def test_validate_feedback_input_correct_is_valid(
self, sample_verification_session, temp_storage_dir
):
"""Verify validation passes for correct feedback."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
is_valid, error_msg = handler.validate_feedback_input(is_correct=True)
assert is_valid is True
assert error_msg is None
def test_validate_feedback_input_incorrect_requires_correction(
self, sample_verification_session, temp_storage_dir
):
"""Verify validation fails for incorrect without correction."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
is_valid, error_msg = handler.validate_feedback_input(
is_correct=False, ground_truth_label=""
)
assert is_valid is False
assert "Correction Required" in error_msg or "select" in error_msg.lower()
def test_validate_feedback_input_incorrect_with_valid_correction(
self, sample_verification_session, temp_storage_dir
):
"""Verify validation passes for incorrect with valid correction."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
is_valid, error_msg = handler.validate_feedback_input(
is_correct=False, ground_truth_label="red"
)
assert is_valid is True
assert error_msg is None
def test_validate_notes_field_accepts_empty_notes(
self, sample_verification_session, temp_storage_dir
):
"""Verify validation accepts empty notes."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
is_valid, error_msg = handler.validate_notes_field("")
assert is_valid is True
assert error_msg is None
def test_validate_notes_field_accepts_valid_notes(
self, sample_verification_session, temp_storage_dir
):
"""Verify validation accepts valid notes."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
notes = "This is a valid note explaining the correction"
is_valid, error_msg = handler.validate_notes_field(notes)
assert is_valid is True
assert error_msg is None
def test_validate_notes_field_rejects_excessive_length(
self, sample_verification_session, temp_storage_dir
):
"""Verify validation rejects notes exceeding 500 characters."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
notes = "x" * 501
is_valid, error_msg = handler.validate_notes_field(notes)
assert is_valid is False
assert "500 characters" in error_msg
class TestSessionStatistics:
"""Tests for session statistics retrieval."""
def test_get_session_statistics_after_feedback(
self, sample_verification_session, temp_storage_dir
):
"""Verify session statistics are updated after feedback."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Message 1",
pre_classified_label="yellow",
),
TestMessage(
message_id="msg_002",
text="Message 2",
pre_classified_label="green",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Add correct feedback
handler.handle_correct_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
)
stats = handler.get_session_statistics()
assert stats["verified_count"] == 1
assert stats["correct_count"] == 1
assert stats["incorrect_count"] == 0
def test_is_session_complete_false_when_messages_remain(
self, sample_verification_session, temp_storage_dir
):
"""Verify session is not complete when messages remain."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Message 1",
pre_classified_label="yellow",
),
TestMessage(
message_id="msg_002",
text="Message 2",
pre_classified_label="green",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
assert handler.is_session_complete() is False
def test_is_session_complete_true_when_all_verified(
self, sample_verification_session, temp_storage_dir
):
"""Verify session is complete when all messages verified."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Message 1",
pre_classified_label="yellow",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
# Verify the only message
handler.handle_correct_feedback(
message=messages[0],
classifier_decision="yellow",
classifier_confidence=0.85,
classifier_indicators=["anxiety"],
)
assert handler.is_session_complete() is True
def test_get_queue_position(
self, sample_verification_session, temp_storage_dir
):
"""Verify queue position is returned correctly."""
store = JSONVerificationStore(storage_dir=temp_storage_dir)
store.save_session(sample_verification_session)
queue_manager = MessageQueueManager(sample_verification_session)
messages = [
TestMessage(
message_id="msg_001",
text="Message 1",
pre_classified_label="yellow",
),
TestMessage(
message_id="msg_002",
text="Message 2",
pre_classified_label="green",
),
TestMessage(
message_id="msg_003",
text="Message 3",
pre_classified_label="red",
),
]
queue_manager.initialize_queue(messages)
handler = VerificationFeedbackHandler(
sample_verification_session, store, queue_manager
)
current_pos, total = handler.get_queue_position()
assert current_pos == 1
assert total == 3