Fix integration test failures
- Fix test_activity_processing.py: Import activity module and use activity.* functions - Fix test_app_activity_functions.py: Import activity module, use activity.* functions, initialize activity module with app's socketio and db - Fix test_activity_integration.py: Update YAML format to match current specification - Change buckets from objects to simple string lists - Use next_section_and_step instead of separate next_section_id/next_step_id - Add required title fields and tokens_for_ai - Replace type field with content_blocks for info steps
This commit is contained in:
parent
9003240762
commit
f9ddc4ec03
3 changed files with 66 additions and 48 deletions
|
|
@ -116,37 +116,42 @@ class TestActivityIntegration(unittest.TestCase):
|
|||
# Create minimal activity content
|
||||
activity_content = """
|
||||
default_max_attempts_per_step: 3
|
||||
tokens_for_ai_rubric: "Test rubric"
|
||||
|
||||
sections:
|
||||
- section_id: "section_1"
|
||||
title: "Test Section"
|
||||
steps:
|
||||
- step_id: "step_1"
|
||||
type: "question"
|
||||
title: "Question 1"
|
||||
question: "What is 2+2?"
|
||||
tokens_for_ai: "Categorize as 'correct' if answer is 4 or four, otherwise 'incorrect'"
|
||||
buckets:
|
||||
- bucket_name: "correct"
|
||||
bucket_criteria: "Answer is 4"
|
||||
- bucket_name: "incorrect"
|
||||
bucket_criteria: "Wrong answer"
|
||||
- correct
|
||||
- incorrect
|
||||
transitions:
|
||||
correct:
|
||||
ai_feedback:
|
||||
tokens_for_ai: "Provide encouragement"
|
||||
next_section_id: "section_1"
|
||||
next_step_id: "step_2"
|
||||
content_blocks:
|
||||
- "Great job!"
|
||||
next_section_and_step: "section_1:step_2"
|
||||
incorrect:
|
||||
ai_feedback:
|
||||
tokens_for_ai: "Try again"
|
||||
next_section_id: "section_1"
|
||||
next_step_id: "step_1"
|
||||
content_blocks:
|
||||
- "Try again!"
|
||||
counts_as_attempt: true
|
||||
next_section_and_step: "section_1:step_1"
|
||||
- step_id: "step_2"
|
||||
type: "question"
|
||||
title: "Question 2"
|
||||
question: "What is 3+3?"
|
||||
tokens_for_ai: "Categorize as 'correct' if answer is 6 or six, otherwise 'incorrect'"
|
||||
buckets:
|
||||
- bucket_name: "correct"
|
||||
bucket_criteria: "Answer is 6"
|
||||
- correct
|
||||
- incorrect
|
||||
transitions:
|
||||
correct:
|
||||
content_blocks:
|
||||
- "Excellent!"
|
||||
incorrect:
|
||||
content_blocks:
|
||||
- "Not quite!"
|
||||
"""
|
||||
# Write to research directory
|
||||
with tempfile.NamedTemporaryFile(
|
||||
|
|
@ -364,24 +369,32 @@ script_result = metadata['counter']
|
|||
from models import ActivityState
|
||||
import activity
|
||||
|
||||
# Create activity with multiple info steps before question
|
||||
# Create activity with multiple content-only steps before question
|
||||
activity_content = """
|
||||
default_max_attempts_per_step: 3
|
||||
|
||||
sections:
|
||||
- section_id: "intro"
|
||||
title: "Introduction"
|
||||
steps:
|
||||
- step_id: "info_1"
|
||||
type: "info"
|
||||
display_text: "Welcome!"
|
||||
title: "Welcome"
|
||||
content_blocks:
|
||||
- "Welcome!"
|
||||
- step_id: "info_2"
|
||||
type: "info"
|
||||
display_text: "Let's begin"
|
||||
title: "Let's Begin"
|
||||
content_blocks:
|
||||
- "Let's begin"
|
||||
- step_id: "question_1"
|
||||
type: "question"
|
||||
title: "Question"
|
||||
question: "Ready?"
|
||||
tokens_for_ai: "Categorize as 'yes' for any response"
|
||||
buckets:
|
||||
- bucket_name: "yes"
|
||||
- yes
|
||||
transitions:
|
||||
yes:
|
||||
content_blocks:
|
||||
- "Great!"
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".yaml", dir="research", delete=False
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ with patch.dict(
|
|||
},
|
||||
):
|
||||
import app
|
||||
import activity
|
||||
|
||||
|
||||
class MockActivityState:
|
||||
|
|
@ -178,7 +179,7 @@ script_result = {
|
|||
|
||||
# Execute the processing script
|
||||
if transition.get("run_processing_script", False):
|
||||
result = app.execute_processing_script(
|
||||
result = activity.execute_processing_script(
|
||||
activity_state.dict_metadata, script_step["processing_script"]
|
||||
)
|
||||
|
||||
|
|
@ -236,7 +237,7 @@ script_result = {
|
|||
temp_metadata["user_response"] = user_response
|
||||
|
||||
# Execute pre-script
|
||||
pre_result = app.execute_processing_script(
|
||||
pre_result = activity.execute_processing_script(
|
||||
temp_metadata, pre_script_step["pre_script"]
|
||||
)
|
||||
|
||||
|
|
@ -334,7 +335,7 @@ script_result = {
|
|||
navigation_path = []
|
||||
|
||||
for _ in range(10): # Prevent infinite loop
|
||||
next_section, next_step = app.get_next_step(
|
||||
next_section, next_step = activity.get_next_step(
|
||||
multi_section_activity, current_section, current_step
|
||||
)
|
||||
|
||||
|
|
@ -371,9 +372,9 @@ script_result = {
|
|||
)
|
||||
|
||||
with patch.object(
|
||||
app, "provide_feedback", return_value=mock_feedback
|
||||
activity, "provide_feedback", return_value=mock_feedback
|
||||
) as mock_func:
|
||||
result = app.provide_feedback(
|
||||
result = activity.provide_feedback(
|
||||
transition_with_feedback,
|
||||
"correct",
|
||||
"What is 2+2?",
|
||||
|
|
@ -403,7 +404,7 @@ if True
|
|||
|
||||
# Should handle syntax errors gracefully
|
||||
with self.assertRaises(SyntaxError):
|
||||
app.execute_processing_script(metadata, invalid_script)
|
||||
activity.execute_processing_script(metadata, invalid_script)
|
||||
|
||||
def test_processing_script_runtime_error(self):
|
||||
"""Test handling of runtime errors in processing scripts"""
|
||||
|
|
@ -416,15 +417,15 @@ script_result = {'status': 'error'}
|
|||
|
||||
# Should handle runtime errors gracefully
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
app.execute_processing_script(metadata, runtime_error_script)
|
||||
activity.execute_processing_script(metadata, runtime_error_script)
|
||||
|
||||
def test_missing_activity_content(self):
|
||||
"""Test handling of missing activity content"""
|
||||
with patch.object(app, "get_activity_content") as mock_get_content:
|
||||
with patch.object(activity, "get_activity_content") as mock_get_content:
|
||||
mock_get_content.side_effect = FileNotFoundError("Activity file not found")
|
||||
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
app.get_activity_content("nonexistent_activity.yaml")
|
||||
activity.get_activity_content("nonexistent_activity.yaml")
|
||||
|
||||
mock_get_content.assert_called_once_with("nonexistent_activity.yaml")
|
||||
|
||||
|
|
@ -448,7 +449,7 @@ script_result = {'status': 'error'}
|
|||
f.write(malformed_yaml)
|
||||
|
||||
with self.assertRaises(yaml.YAMLError): # YAML parsing error
|
||||
app.get_activity_content("research/malformed.yaml")
|
||||
activity.get_activity_content("research/malformed.yaml")
|
||||
|
||||
finally:
|
||||
os.unlink(temp_file)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from flask_socketio import SocketIO
|
|||
|
||||
# Import the main application
|
||||
import app
|
||||
import activity
|
||||
from models import db, Room, ActivityState, Message
|
||||
|
||||
|
||||
|
|
@ -60,6 +61,9 @@ class TestFlaskAppActivityFunctions(unittest.TestCase):
|
|||
# Store original socketio for cleanup
|
||||
self.original_socketio = app.socketio
|
||||
|
||||
# Initialize activity module with app's socketio and db
|
||||
activity.init_activity_module(app.socketio, db)
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up test environment"""
|
||||
db.session.remove()
|
||||
|
|
@ -116,7 +120,7 @@ sections:
|
|||
|
||||
try:
|
||||
# Test the actual get_activity_content function
|
||||
result = app.get_activity_content(f"research/{activity_file}")
|
||||
result = activity.get_activity_content(f"research/{activity_file}")
|
||||
|
||||
# Verify structure
|
||||
self.assertEqual(result["title"], "Test Activity")
|
||||
|
|
@ -169,7 +173,7 @@ sections:
|
|||
)()
|
||||
|
||||
# Test start_activity function
|
||||
app.start_activity("test_room", f"research/{activity_file}", "testuser")
|
||||
activity.start_activity("test_room", f"research/{activity_file}", "testuser")
|
||||
|
||||
# Verify activity state was created in database
|
||||
activity_state = ActivityState.query.filter_by(
|
||||
|
|
@ -244,7 +248,7 @@ sections:
|
|||
db.session.commit()
|
||||
|
||||
# Test handling a correct response
|
||||
app.handle_activity_response("test_room", "10", "testuser")
|
||||
activity.handle_activity_response("test_room", "10", "testuser")
|
||||
|
||||
# Refresh activity state from database
|
||||
db.session.refresh(activity_state)
|
||||
|
|
@ -305,7 +309,7 @@ sections:
|
|||
db.session.commit()
|
||||
|
||||
# Test display_activity_metadata function
|
||||
app.display_activity_metadata("test_room", "testuser")
|
||||
activity.display_activity_metadata("test_room", "testuser")
|
||||
|
||||
# Verify that a message was emitted
|
||||
self.assertTrue(len(emitted_messages) > 0)
|
||||
|
|
@ -367,7 +371,7 @@ sections:
|
|||
)
|
||||
|
||||
# Test cancel_activity function
|
||||
app.cancel_activity("test_room", "testuser")
|
||||
activity.cancel_activity("test_room", "testuser")
|
||||
|
||||
# Verify activity was deleted from database
|
||||
self.assertIsNone(
|
||||
|
|
@ -421,7 +425,7 @@ script_result = {
|
|||
}
|
||||
|
||||
# Test the actual execute_processing_script function
|
||||
result = app.execute_processing_script(metadata, script)
|
||||
result = activity.execute_processing_script(metadata, script)
|
||||
|
||||
# Verify script execution results
|
||||
self.assertEqual(result["status"], "success")
|
||||
|
|
@ -459,21 +463,21 @@ script_result = {
|
|||
}
|
||||
|
||||
# Test navigation within section
|
||||
next_section, next_step = app.get_next_step(
|
||||
next_section, next_step = activity.get_next_step(
|
||||
activity_content, "section_1", "step_1"
|
||||
)
|
||||
self.assertEqual(next_section["section_id"], "section_1")
|
||||
self.assertEqual(next_step["step_id"], "step_2")
|
||||
|
||||
# Test navigation across sections
|
||||
next_section, next_step = app.get_next_step(
|
||||
next_section, next_step = activity.get_next_step(
|
||||
activity_content, "section_1", "step_3"
|
||||
)
|
||||
self.assertEqual(next_section["section_id"], "section_2")
|
||||
self.assertEqual(next_step["step_id"], "step_1")
|
||||
|
||||
# Test at end of activity
|
||||
next_section, next_step = app.get_next_step(
|
||||
next_section, next_step = activity.get_next_step(
|
||||
activity_content, "section_2", "step_2"
|
||||
)
|
||||
self.assertIsNone(next_section)
|
||||
|
|
@ -490,7 +494,7 @@ script_result = {
|
|||
)
|
||||
|
||||
# Test the actual categorization function
|
||||
result = app.categorize_response(question, response, buckets, tokens_for_ai)
|
||||
result = activity.categorize_response(question, response, buckets, tokens_for_ai)
|
||||
|
||||
# Result should be either "correct", "incorrect", or an error message
|
||||
self.assertIsInstance(result, str)
|
||||
|
|
@ -502,19 +506,19 @@ script_result = {
|
|||
"""Test text translation functionality"""
|
||||
# Test English bypass
|
||||
english_text = "Hello, world!"
|
||||
result = app.translate_text(english_text, "English")
|
||||
result = activity.translate_text(english_text, "English")
|
||||
self.assertEqual(result, english_text)
|
||||
|
||||
# Test case insensitive
|
||||
result = app.translate_text(english_text, "english")
|
||||
result = activity.translate_text(english_text, "english")
|
||||
self.assertEqual(result, english_text)
|
||||
|
||||
# Test with compound language
|
||||
result = app.translate_text(english_text, "English please")
|
||||
result = activity.translate_text(english_text, "English please")
|
||||
self.assertEqual(result, english_text)
|
||||
|
||||
# Test other language (will use AI endpoint if available)
|
||||
result = app.translate_text("Hello", "Spanish")
|
||||
result = activity.translate_text("Hello", "Spanish")
|
||||
self.assertIsInstance(result, str) # Should return some string result
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue