Spaces:
Sleeping
Sleeping
File size: 3,311 Bytes
210db8d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | import pytest
import os
import json
from unittest.mock import patch, MagicMock
def test_api_feedback_unauthorized(client):
"""Test feedback endpoint requires session authentication or API key."""
response = client.post('/api/feedback', json={'image_path': 'test.jpg', 'label': 'morph'})
assert response.status_code == 401
def test_api_feedback_missing_payload(client):
"""Test feedback endpoint rejects missing parameters."""
with client.session_transaction() as sess:
sess['logged_in'] = True
sess['role'] = 'admin'
response = client.post('/api/feedback', json={})
assert response.status_code == 400
assert 'Missing image_path or label' in response.get_json()['error']
def test_api_feedback_persistence_and_threshold_trigger(client, tmp_path):
"""Test feedback persists entries and triggers background training when reaching threshold."""
with client.session_transaction() as sess:
sess['logged_in'] = True
sess['role'] = 'admin'
test_feedback_file = str(tmp_path / "test_feedback.json")
# Mock FEEDBACK_FILE in training route
with patch('src.routes.training.log_model_interaction'), \
patch('src.routes.training.Thread') as mock_thread, \
patch('os.path.exists', return_value=False), \
patch('builtins.open', create=True) as mock_open:
# Test single feedback submission
response = client.post(
'/api/feedback',
json={
'image_path': 'static/uploads/sample_morph.jpg',
'label': 'morph',
'prediction': 'real'
}
)
assert response.status_code == 200
json_data = response.get_json()
assert json_data['status'] == 'flagged'
assert json_data['feedback_status'] == 'feedback_received'
assert json_data['count'] == 1
def test_api_feedback_triggers_retrain_at_threshold(client):
"""Test background training thread is spawned when count reaches RETRAIN_FLAG_THRESHOLD (10)."""
with client.session_transaction() as sess:
sess['logged_in'] = True
sess['role'] = 'admin'
# Pre-populate 9 feedbacks
existing_feedbacks = [
{'timestamp': '2026-08-30T00:00:00', 'image_path': f'img_{i}.jpg', 'user_label': 'morph'}
for i in range(9)
]
with patch('src.routes.training.log_model_interaction'), \
patch('os.path.exists', return_value=True), \
patch('builtins.open') as mock_file, \
patch('json.load', return_value=existing_feedbacks), \
patch('json.dump'), \
patch('src.routes.training.Thread') as mock_thread:
mock_instance = MagicMock()
mock_thread.return_value = mock_instance
# 10th feedback submission reaches threshold
response = client.post(
'/api/feedback',
json={
'image_path': 'img_9.jpg',
'label': 'morph'
}
)
assert response.status_code == 200
json_data = response.get_json()
assert json_data['count'] == 10
# Verify background daemon thread was started
mock_thread.assert_called_once()
assert mock_thread.call_args.kwargs['daemon'] is True
mock_instance.start.assert_called_once()
|