Fix: Rename directory to remove & character causing shell issues
Renamed ebook_backend&admin_panel to ebook_backend_admin_panel The & character was being interpreted by shell as background process operator, causing 'Dockerfile not found' errors in Coolify.
This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
import pytest
|
||||
import os
|
||||
import tempfile
|
||||
from unittest.mock import patch, MagicMock, mock_open
|
||||
from fastapi import HTTPException
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
class TestTranslationRoutes:
|
||||
"""Test cases for translation file management routes"""
|
||||
|
||||
def test_upload_translation_unauthorized(self, client):
|
||||
"""Test uploading translation file without authentication"""
|
||||
# Create a mock file
|
||||
mock_file = MagicMock()
|
||||
mock_file.filename = "test.xlsx"
|
||||
mock_file.read.return_value = b"test content"
|
||||
|
||||
response = client.post("/upload-translations", files={"file": ("test.xlsx", b"test content", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")})
|
||||
assert response.status_code == 401
|
||||
data = response.json()
|
||||
assert data["detail"] == "Unauthorized"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('routes.auth.os.makedirs')
|
||||
@patch('builtins.open', new_callable=mock_open)
|
||||
def test_upload_translation_success(self, mock_file, mock_makedirs, mock_exists, client, auth_headers, temp_translation_dir):
|
||||
"""Test successful translation file upload"""
|
||||
# Mock that file doesn't exist initially
|
||||
mock_exists.return_value = False
|
||||
|
||||
# Create a mock file content
|
||||
file_content = b"test excel content"
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("test_translation.xlsx", file_content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["message"] == "Translation file uploaded successfully"
|
||||
assert data["filename"] == "test_translation.xlsx"
|
||||
|
||||
# Verify directory creation was attempted
|
||||
mock_makedirs.assert_called_once()
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
def test_upload_translation_file_already_exists(self, mock_exists, client, auth_headers):
|
||||
"""Test uploading translation file when one already exists"""
|
||||
# Mock that file already exists
|
||||
mock_exists.return_value = True
|
||||
|
||||
file_content = b"test excel content"
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("test_translation.xlsx", file_content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
data = response.json()
|
||||
assert data["detail"] == "A translation file already exists. Please delete it first."
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('routes.auth.os.makedirs')
|
||||
@patch('builtins.open', side_effect=Exception("File write error"))
|
||||
def test_upload_translation_write_error(self, mock_file, mock_makedirs, mock_exists, client, auth_headers):
|
||||
"""Test translation upload with file write error"""
|
||||
mock_exists.return_value = False
|
||||
|
||||
file_content = b"test excel content"
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("test_translation.xlsx", file_content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 500
|
||||
data = response.json()
|
||||
assert "Upload failed" in data["detail"]
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('routes.auth.os.makedirs')
|
||||
@patch('builtins.open', new_callable=mock_open)
|
||||
@patch('routes.auth.os.remove')
|
||||
def test_upload_translation_cleanup_on_error(self, mock_remove, mock_file, mock_makedirs, mock_exists, client, auth_headers):
|
||||
"""Test cleanup when translation upload fails"""
|
||||
# Mock that files don't exist initially
|
||||
mock_exists.return_value = False
|
||||
|
||||
# Mock file write to succeed but metadata write to fail
|
||||
mock_file.side_effect = [
|
||||
MagicMock(), # Translation file write succeeds
|
||||
Exception("Metadata write error") # Metadata write fails
|
||||
]
|
||||
|
||||
file_content = b"test excel content"
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("test_translation.xlsx", file_content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 500
|
||||
# The cleanup should happen in the exception handler, but since we're mocking os.path.exists
|
||||
# to return False, the cleanup won't be called. This test verifies the error handling works.
|
||||
|
||||
def test_delete_translation_unauthorized(self, client):
|
||||
"""Test deleting translation file without authentication"""
|
||||
response = client.delete("/delete-translation")
|
||||
assert response.status_code == 401
|
||||
data = response.json()
|
||||
assert data["detail"] == "Unauthorized"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('routes.auth.os.remove')
|
||||
@patch('routes.auth.os.listdir')
|
||||
@patch('routes.auth.os.rmdir')
|
||||
def test_delete_translation_success(self, mock_rmdir, mock_listdir, mock_remove, mock_exists, client, auth_headers):
|
||||
"""Test successful translation file deletion"""
|
||||
# Mock that files exist
|
||||
mock_exists.side_effect = lambda path: "translation.xlsx" in path or "metadata.txt" in path
|
||||
|
||||
# Mock empty directory after deletion
|
||||
mock_listdir.return_value = []
|
||||
|
||||
response = client.delete("/delete-translation", headers=auth_headers)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["message"] == "Translation file deleted successfully"
|
||||
|
||||
# Verify files were deleted
|
||||
assert mock_remove.call_count == 2 # Translation file and metadata
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
def test_delete_translation_not_found(self, mock_exists, client, auth_headers):
|
||||
"""Test deleting translation file when none exists"""
|
||||
# Mock that no files exist
|
||||
mock_exists.return_value = False
|
||||
|
||||
response = client.delete("/delete-translation", headers=auth_headers)
|
||||
assert response.status_code == 404
|
||||
data = response.json()
|
||||
assert data["detail"] == "No translation file found"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('routes.auth.os.remove')
|
||||
@patch('routes.auth.os.listdir')
|
||||
def test_delete_translation_directory_not_empty(self, mock_listdir, mock_remove, mock_exists, client, auth_headers):
|
||||
"""Test deletion when directory is not empty after file removal"""
|
||||
# Mock that files exist
|
||||
mock_exists.side_effect = lambda path: "translation.xlsx" in path or "metadata.txt" in path
|
||||
|
||||
# Mock non-empty directory after deletion
|
||||
mock_listdir.return_value = ["other_file.txt"]
|
||||
|
||||
response = client.delete("/delete-translation", headers=auth_headers)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["message"] == "Translation file deleted successfully"
|
||||
|
||||
# Directory should not be removed since it's not empty
|
||||
assert mock_remove.call_count == 2 # Only files, not directory
|
||||
|
||||
def test_download_translation_unauthorized(self, client):
|
||||
"""Test downloading translation file without authentication"""
|
||||
response = client.get("/download-translation")
|
||||
assert response.status_code == 401
|
||||
data = response.json()
|
||||
assert data["detail"] == "Unauthorized"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('builtins.open', new_callable=mock_open, read_data=b"test content")
|
||||
def test_download_translation_success(self, mock_file, mock_exists, client, auth_headers):
|
||||
"""Test successful translation file download"""
|
||||
# Mock that file exists
|
||||
mock_exists.return_value = True
|
||||
|
||||
response = client.get("/download-translation", headers=auth_headers)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Check response headers
|
||||
assert response.headers["content-type"] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
assert "attachment" in response.headers["content-disposition"]
|
||||
# The filename should be in the content disposition header
|
||||
content_disposition = response.headers["content-disposition"]
|
||||
assert "filename" in content_disposition
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('builtins.open', new_callable=mock_open, read_data=b"test content")
|
||||
def test_download_translation_with_metadata(self, mock_file, mock_exists, client, auth_headers):
|
||||
"""Test translation download with metadata filename"""
|
||||
# Mock that files exist
|
||||
mock_exists.side_effect = lambda path: True
|
||||
|
||||
response = client.get("/download-translation", headers=auth_headers)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Check that we get a valid response with proper headers
|
||||
assert response.headers["content-type"] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
assert "attachment" in response.headers["content-disposition"]
|
||||
assert "filename" in response.headers["content-disposition"]
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
def test_download_translation_not_found(self, mock_exists, client, auth_headers):
|
||||
"""Test downloading translation file when none exists"""
|
||||
# Mock that file doesn't exist
|
||||
mock_exists.return_value = False
|
||||
|
||||
response = client.get("/download-translation", headers=auth_headers)
|
||||
assert response.status_code == 404
|
||||
data = response.json()
|
||||
assert data["detail"] == "No translation file found"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('builtins.open', side_effect=Exception("File read error"))
|
||||
def test_download_translation_read_error(self, mock_file, mock_exists, client, auth_headers):
|
||||
"""Test translation download with file read error"""
|
||||
mock_exists.return_value = True
|
||||
|
||||
# Should raise an exception when file read fails
|
||||
with pytest.raises(Exception, match="File read error"):
|
||||
client.get("/download-translation", headers=auth_headers)
|
||||
|
||||
def test_check_translation_status_no_file(self, client):
|
||||
"""Test translation status check when no file exists"""
|
||||
with patch('routes.auth.os.path.exists') as mock_exists:
|
||||
mock_exists.return_value = False
|
||||
|
||||
response = client.get("/translations/status")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
assert data["file_exists"] is False
|
||||
assert data["file_name"] is None
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('builtins.open', new_callable=mock_open, read_data=b"custom_filename.xlsx")
|
||||
def test_check_translation_status_with_file(self, mock_file, mock_exists, client):
|
||||
"""Test translation status check when file exists"""
|
||||
# Mock that files exist
|
||||
mock_exists.side_effect = lambda path: True
|
||||
|
||||
response = client.get("/translations/status")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
assert data["file_exists"] is True
|
||||
assert data["file_name"] == "custom_filename.xlsx"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('builtins.open', side_effect=Exception("Metadata read error"))
|
||||
def test_check_translation_status_metadata_error(self, mock_file, mock_exists, client):
|
||||
"""Test translation status check with metadata read error"""
|
||||
# Mock that files exist
|
||||
mock_exists.side_effect = lambda path: True
|
||||
|
||||
response = client.get("/translations/status")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
# Should fall back to default filename
|
||||
assert data["file_exists"] is True
|
||||
assert data["file_name"] == "translation.xlsx"
|
||||
|
||||
def test_get_latest_translation_no_file(self, client):
|
||||
"""Test latest translation endpoint when no file exists"""
|
||||
with patch('routes.auth.os.path.exists') as mock_exists:
|
||||
mock_exists.return_value = False
|
||||
|
||||
response = client.get("/translations/latest")
|
||||
assert response.status_code == 404
|
||||
data = response.json()
|
||||
assert data["detail"] == "No translation file found"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('builtins.open', new_callable=mock_open, read_data=b"test content")
|
||||
def test_get_latest_translation_success(self, mock_file, mock_exists, client):
|
||||
"""Test successful latest translation download"""
|
||||
# Mock that files exist
|
||||
mock_exists.side_effect = lambda path: True
|
||||
|
||||
response = client.get("/translations/latest")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Check response headers
|
||||
assert response.headers["content-type"] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
assert "attachment" in response.headers["content-disposition"]
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('builtins.open', new_callable=mock_open, read_data=b"test content")
|
||||
def test_get_latest_translation_with_metadata(self, mock_file, mock_exists, client):
|
||||
"""Test latest translation download with metadata filename"""
|
||||
# Mock that files exist
|
||||
mock_exists.side_effect = lambda path: True
|
||||
|
||||
response = client.get("/translations/latest")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Check that we get a valid response with proper headers
|
||||
assert response.headers["content-type"] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
assert "attachment" in response.headers["content-disposition"]
|
||||
assert "filename" in response.headers["content-disposition"]
|
||||
|
||||
def test_upload_translation_invalid_file_type(self, client, auth_headers):
|
||||
"""Test uploading non-Excel file"""
|
||||
file_content = b"not an excel file"
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("test.txt", file_content, "text/plain")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
# Should still accept the file since validation is not strict
|
||||
assert response.status_code in [200, 400] # Depends on implementation
|
||||
|
||||
def test_upload_translation_empty_file(self, client, auth_headers):
|
||||
"""Test uploading empty file"""
|
||||
with patch('routes.auth.os.path.exists') as mock_exists:
|
||||
mock_exists.return_value = False
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("empty.xlsx", b"", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["message"] == "Translation file uploaded successfully"
|
||||
|
||||
def test_upload_translation_large_file(self, client, auth_headers):
|
||||
"""Test uploading large file"""
|
||||
with patch('routes.auth.os.path.exists') as mock_exists:
|
||||
mock_exists.return_value = False
|
||||
|
||||
# Create a large file content (1MB)
|
||||
large_content = b"x" * (1024 * 1024)
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("large.xlsx", large_content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["message"] == "Translation file uploaded successfully"
|
||||
|
||||
@patch('routes.auth.os.path.exists')
|
||||
@patch('routes.auth.os.makedirs')
|
||||
@patch('builtins.open', new_callable=mock_open)
|
||||
def test_upload_translation_no_filename(self, mock_file, mock_makedirs, mock_exists, client, auth_headers):
|
||||
"""Test uploading file with minimal filename"""
|
||||
mock_exists.return_value = False
|
||||
|
||||
file_content = b"test content"
|
||||
|
||||
response = client.post(
|
||||
"/upload-translations",
|
||||
files={"file": ("test.xlsx", file_content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
# Should handle the upload successfully
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["filename"] == "test.xlsx"
|
||||
Reference in New Issue
Block a user