2ND
This commit is contained in:
266
tests/test_files_api.py
Normal file
266
tests/test_files_api.py
Normal file
@@ -0,0 +1,266 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
檔案管理 API 測試
|
||||
|
||||
Author: PANJIT IT Team
|
||||
Created: 2024-01-28
|
||||
Modified: 2024-01-28
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import io
|
||||
import json
|
||||
from unittest.mock import patch, MagicMock
|
||||
from app.models.job import TranslationJob
|
||||
|
||||
|
||||
class TestFilesAPI:
|
||||
"""檔案管理 API 測試類別"""
|
||||
|
||||
def test_upload_file_success(self, authenticated_client, auth_user):
|
||||
"""測試成功上傳檔案"""
|
||||
# 建立測試檔案
|
||||
file_data = b'Mock DOCX file content'
|
||||
file_obj = (io.BytesIO(file_data), 'test.docx')
|
||||
|
||||
with patch('app.utils.helpers.save_uploaded_file') as mock_save:
|
||||
mock_save.return_value = {
|
||||
'success': True,
|
||||
'filename': 'original_test_12345678.docx',
|
||||
'file_path': '/tmp/test_job_uuid/original_test_12345678.docx',
|
||||
'file_size': len(file_data)
|
||||
}
|
||||
|
||||
response = authenticated_client.post('/api/v1/files/upload', data={
|
||||
'file': file_obj,
|
||||
'source_language': 'auto',
|
||||
'target_languages': json.dumps(['en', 'vi'])
|
||||
})
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['success'] is True
|
||||
assert 'job_uuid' in data['data']
|
||||
assert data['data']['original_filename'] == 'test.docx'
|
||||
|
||||
def test_upload_file_no_file(self, authenticated_client):
|
||||
"""測試未選擇檔案"""
|
||||
response = authenticated_client.post('/api/v1/files/upload', data={
|
||||
'source_language': 'auto',
|
||||
'target_languages': json.dumps(['en'])
|
||||
})
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'NO_FILE'
|
||||
|
||||
def test_upload_file_invalid_type(self, authenticated_client):
|
||||
"""測試上傳無效檔案類型"""
|
||||
file_data = b'Mock text file content'
|
||||
file_obj = (io.BytesIO(file_data), 'test.txt')
|
||||
|
||||
response = authenticated_client.post('/api/v1/files/upload', data={
|
||||
'file': file_obj,
|
||||
'source_language': 'auto',
|
||||
'target_languages': json.dumps(['en'])
|
||||
})
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'INVALID_FILE_TYPE'
|
||||
|
||||
def test_upload_file_too_large(self, authenticated_client, app):
|
||||
"""測試上傳過大檔案"""
|
||||
# 建立超過限制的檔案(26MB+)
|
||||
large_file_data = b'x' * (26 * 1024 * 1024 + 1)
|
||||
file_obj = (io.BytesIO(large_file_data), 'large.docx')
|
||||
|
||||
response = authenticated_client.post('/api/v1/files/upload', data={
|
||||
'file': file_obj,
|
||||
'source_language': 'auto',
|
||||
'target_languages': json.dumps(['en'])
|
||||
})
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'FILE_TOO_LARGE'
|
||||
|
||||
def test_upload_file_invalid_target_languages(self, authenticated_client):
|
||||
"""測試無效的目標語言"""
|
||||
file_data = b'Mock DOCX file content'
|
||||
file_obj = (io.BytesIO(file_data), 'test.docx')
|
||||
|
||||
response = authenticated_client.post('/api/v1/files/upload', data={
|
||||
'file': file_obj,
|
||||
'source_language': 'auto',
|
||||
'target_languages': 'invalid_json'
|
||||
})
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'INVALID_TARGET_LANGUAGES'
|
||||
|
||||
def test_upload_file_empty_target_languages(self, authenticated_client):
|
||||
"""測試空的目標語言"""
|
||||
file_data = b'Mock DOCX file content'
|
||||
file_obj = (io.BytesIO(file_data), 'test.docx')
|
||||
|
||||
response = authenticated_client.post('/api/v1/files/upload', data={
|
||||
'file': file_obj,
|
||||
'source_language': 'auto',
|
||||
'target_languages': json.dumps([])
|
||||
})
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'NO_TARGET_LANGUAGES'
|
||||
|
||||
def test_upload_file_without_auth(self, client):
|
||||
"""測試未認證上傳檔案"""
|
||||
file_data = b'Mock DOCX file content'
|
||||
file_obj = (io.BytesIO(file_data), 'test.docx')
|
||||
|
||||
response = client.post('/api/v1/files/upload', data={
|
||||
'file': file_obj,
|
||||
'source_language': 'auto',
|
||||
'target_languages': json.dumps(['en'])
|
||||
})
|
||||
|
||||
assert response.status_code == 401
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'AUTHENTICATION_REQUIRED'
|
||||
|
||||
def test_download_translated_file_success(self, authenticated_client, sample_job, auth_user):
|
||||
"""測試成功下載翻譯檔案"""
|
||||
# 設定任務為已完成
|
||||
sample_job.update_status('COMPLETED')
|
||||
|
||||
# 添加翻譯檔案記錄
|
||||
sample_job.add_translated_file(
|
||||
language_code='en',
|
||||
filename='test_en_translated.docx',
|
||||
file_path='/tmp/test_en_translated.docx',
|
||||
file_size=1024
|
||||
)
|
||||
|
||||
with patch('pathlib.Path.exists') as mock_exists, \
|
||||
patch('flask.send_file') as mock_send_file:
|
||||
|
||||
mock_exists.return_value = True
|
||||
mock_send_file.return_value = 'file_content'
|
||||
|
||||
response = authenticated_client.get(f'/api/v1/files/{sample_job.job_uuid}/download/en')
|
||||
|
||||
# send_file 被呼叫表示成功
|
||||
mock_send_file.assert_called_once()
|
||||
|
||||
def test_download_file_not_found(self, authenticated_client, sample_job):
|
||||
"""測試下載不存在的檔案"""
|
||||
response = authenticated_client.get(f'/api/v1/files/nonexistent-uuid/download/en')
|
||||
|
||||
assert response.status_code == 404
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'JOB_NOT_FOUND'
|
||||
|
||||
def test_download_file_permission_denied(self, authenticated_client, sample_job, app):
|
||||
"""測試下載他人檔案"""
|
||||
# 建立另一個使用者的任務
|
||||
from app.models.user import User
|
||||
from app import db
|
||||
|
||||
with app.app_context():
|
||||
other_user = User(
|
||||
username='otheruser',
|
||||
display_name='Other User',
|
||||
email='other@panjit.com.tw',
|
||||
department='IT',
|
||||
is_admin=False
|
||||
)
|
||||
db.session.add(other_user)
|
||||
db.session.commit()
|
||||
|
||||
other_job = TranslationJob(
|
||||
user_id=other_user.id,
|
||||
original_filename='other.docx',
|
||||
file_extension='.docx',
|
||||
file_size=1024,
|
||||
file_path='/tmp/other.docx',
|
||||
source_language='auto',
|
||||
target_languages=['en'],
|
||||
status='COMPLETED'
|
||||
)
|
||||
db.session.add(other_job)
|
||||
db.session.commit()
|
||||
|
||||
response = authenticated_client.get(f'/api/v1/files/{other_job.job_uuid}/download/en')
|
||||
|
||||
assert response.status_code == 403
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'PERMISSION_DENIED'
|
||||
|
||||
def test_download_file_not_completed(self, authenticated_client, sample_job):
|
||||
"""測試下載未完成任務的檔案"""
|
||||
response = authenticated_client.get(f'/api/v1/files/{sample_job.job_uuid}/download/en')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.get_json()
|
||||
assert data['success'] is False
|
||||
assert data['error'] == 'JOB_NOT_COMPLETED'
|
||||
|
||||
def test_download_original_file_success(self, authenticated_client, sample_job):
|
||||
"""測試下載原始檔案"""
|
||||
# 添加原始檔案記錄
|
||||
sample_job.add_original_file(
|
||||
filename='original_test.docx',
|
||||
file_path='/tmp/original_test.docx',
|
||||
file_size=1024
|
||||
)
|
||||
|
||||
with patch('pathlib.Path.exists') as mock_exists, \
|
||||
patch('flask.send_file') as mock_send_file:
|
||||
|
||||
mock_exists.return_value = True
|
||||
mock_send_file.return_value = 'file_content'
|
||||
|
||||
response = authenticated_client.get(f'/api/v1/files/{sample_job.job_uuid}/download/original')
|
||||
|
||||
mock_send_file.assert_called_once()
|
||||
|
||||
def test_get_supported_formats(self, client):
|
||||
"""測試取得支援的檔案格式"""
|
||||
response = client.get('/api/v1/files/supported-formats')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['success'] is True
|
||||
assert 'supported_formats' in data['data']
|
||||
assert 'max_file_size' in data['data']
|
||||
|
||||
# 檢查是否包含基本格式
|
||||
formats = data['data']['supported_formats']
|
||||
assert '.docx' in formats
|
||||
assert '.pdf' in formats
|
||||
|
||||
def test_get_supported_languages(self, client):
|
||||
"""測試取得支援的語言"""
|
||||
response = client.get('/api/v1/files/supported-languages')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.get_json()
|
||||
assert data['success'] is True
|
||||
assert 'supported_languages' in data['data']
|
||||
|
||||
# 檢查是否包含基本語言
|
||||
languages = data['data']['supported_languages']
|
||||
assert 'en' in languages
|
||||
assert 'zh-TW' in languages
|
||||
assert 'auto' in languages
|
Reference in New Issue
Block a user