Fix path traversal, temp file leak, cross-browser speech, and add tests
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import io
|
||||
import sys
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
# Mock whisper before importing server
|
||||
mock_whisper = MagicMock()
|
||||
mock_whisper.load_model.return_value = MagicMock()
|
||||
sys.modules['whisper'] = mock_whisper
|
||||
|
||||
from server import app
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
app.config['TESTING'] = True
|
||||
with app.test_client() as c:
|
||||
yield c
|
||||
|
||||
# --- Static file serving ---
|
||||
|
||||
def test_index(client):
|
||||
resp = client.get('/')
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_allowed_static_file(client):
|
||||
resp = client.get('/app.js')
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_blocked_static_file(client):
|
||||
resp = client.get('/server.py')
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_path_traversal_blocked(client):
|
||||
resp = client.get('/../requirements.txt')
|
||||
assert resp.status_code == 404
|
||||
|
||||
# --- COOP/COEP headers ---
|
||||
|
||||
def test_coop_coep_headers(client):
|
||||
resp = client.get('/')
|
||||
assert resp.headers['Cross-Origin-Opener-Policy'] == 'same-origin'
|
||||
assert resp.headers['Cross-Origin-Embedder-Policy'] == 'require-corp'
|
||||
|
||||
# --- /transcribe endpoint ---
|
||||
|
||||
def test_transcribe_no_file(client):
|
||||
resp = client.post('/transcribe')
|
||||
assert resp.status_code == 400
|
||||
assert 'No file provided' in resp.get_json()['error']
|
||||
|
||||
def test_transcribe_empty_filename(client):
|
||||
data = {'file': (io.BytesIO(b'data'), '')}
|
||||
resp = client.post('/transcribe', data=data, content_type='multipart/form-data')
|
||||
assert resp.status_code == 400
|
||||
assert 'No file selected' in resp.get_json()['error']
|
||||
|
||||
def test_transcribe_video_rejected(client):
|
||||
for ext in ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.webm']:
|
||||
data = {'file': (io.BytesIO(b'data'), f'video{ext}')}
|
||||
resp = client.post('/transcribe', data=data, content_type='multipart/form-data')
|
||||
assert resp.status_code == 400
|
||||
assert 'Video files not allowed' in resp.get_json()['error']
|
||||
|
||||
@patch('server.model')
|
||||
def test_transcribe_success(mock_model, client):
|
||||
mock_model.transcribe.return_value = {'text': 'hello world'}
|
||||
data = {'file': (io.BytesIO(b'audio data'), 'test.mp3')}
|
||||
resp = client.post('/transcribe', data=data, content_type='multipart/form-data')
|
||||
assert resp.status_code == 200
|
||||
assert resp.get_json()['text'] == 'hello world'
|
||||
|
||||
@patch('server.model')
|
||||
def test_transcribe_with_language(mock_model, client):
|
||||
mock_model.transcribe.return_value = {'text': 'hola'}
|
||||
data = {'file': (io.BytesIO(b'audio'), 'test.mp3'), 'language': 'es-ES'}
|
||||
resp = client.post('/transcribe', data=data, content_type='multipart/form-data')
|
||||
assert resp.status_code == 200
|
||||
mock_model.transcribe.assert_called_once()
|
||||
assert mock_model.transcribe.call_args[1]['language'] == 'es'
|
||||
|
||||
@patch('server.model')
|
||||
def test_transcribe_cleans_up_temp_file_on_error(mock_model, client):
|
||||
mock_model.transcribe.side_effect = RuntimeError('model failed')
|
||||
data = {'file': (io.BytesIO(b'audio'), 'test.mp3')}
|
||||
resp = client.post('/transcribe', data=data, content_type='multipart/form-data')
|
||||
assert resp.status_code == 500
|
||||
assert 'model failed' in resp.get_json()['error']
|
||||
Reference in New Issue
Block a user