Spaces:
Sleeping
Sleeping
File size: 6,001 Bytes
d77abf8 | 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | """
Comprehensive tests for /api/export endpoint
=============================================
Tests cover:
- Export format options (Excel, CSV)
- Empty data handling
- Authentication requirements
- File generation
"""
import pytest
import io
from unittest.mock import patch, MagicMock
class TestExportEndpoint:
"""Tests for /api/export endpoint"""
def test_export_unauthorized(self, client):
"""Test that export requires authentication"""
response = client.post("/api/export", json={
"format": "excel",
"data": []
})
assert response.status_code == 401
def test_export_empty_data(self, client, auth_headers):
"""Test export with empty data"""
response = client.post("/api/export", json={
"format": "excel",
"data": []
}, headers=auth_headers)
# Should handle empty data gracefully
assert response.status_code in [200, 400, 422]
def test_export_excel_format(self, client, auth_headers):
"""Test Excel export format"""
# First create some comparison data
compare_response = client.post("/api/comparisons/compare", json={
"hotel_ids": [1, 2],
"check_in": "2026-02-01",
"check_out": "2026-02-03",
"occupancy": "couple"
}, headers=auth_headers)
# Now try to export
response = client.post("/api/export", json={
"format": "excel",
"comparison_id": 1
}, headers=auth_headers)
# Check response
if response.status_code == 200:
# Should return binary Excel data
content_type = response.headers.get("content-type", "")
assert "application" in content_type or "octet-stream" in content_type
def test_export_csv_format(self, client, auth_headers):
"""Test CSV export format"""
response = client.post("/api/export", json={
"format": "csv",
"data": [
{"hotel": "Test Hotel", "price": 450},
{"hotel": "Another Hotel", "price": 500}
]
}, headers=auth_headers)
if response.status_code == 200:
content_type = response.headers.get("content-type", "")
# CSV should be text/csv or similar
assert "csv" in content_type.lower() or "text" in content_type.lower() or response.status_code == 200
def test_export_invalid_format(self, client, auth_headers):
"""Test export with invalid format"""
response = client.post("/api/export", json={
"format": "invalid_format",
"data": [{"test": "data"}]
}, headers=auth_headers)
# Should reject invalid format
assert response.status_code in [400, 422]
def test_export_missing_format(self, client, auth_headers):
"""Test export with missing format field"""
response = client.post("/api/export", json={
"data": [{"test": "data"}]
}, headers=auth_headers)
# Should require format
assert response.status_code in [200, 400, 422] # May have default
def test_export_sql_injection_in_data(self, client, auth_headers):
"""Test that SQL injection in export data is safe"""
response = client.post("/api/export", json={
"format": "excel",
"data": [
{"hotel": "'; DROP TABLE hotels; --", "price": 450},
{"hotel": "Test<script>alert(1)</script>", "price": 500}
]
}, headers=auth_headers)
# Should NOT crash
assert response.status_code != 500
def test_export_large_dataset(self, client, auth_headers):
"""Test export with large dataset"""
large_data = [
{"hotel": f"Hotel {i}", "price": 400 + i, "rating": 8.0 + (i % 10) / 10}
for i in range(100)
]
response = client.post("/api/export", json={
"format": "excel",
"data": large_data
}, headers=auth_headers)
# Should handle large data
assert response.status_code in [200, 413, 422] # 413 = payload too large
def test_export_special_characters(self, client, auth_headers):
"""Test export with Hebrew and special characters"""
response = client.post("/api/export", json={
"format": "excel",
"data": [
{"hotel": "מלון ישראלי", "price": 450, "location": "תל אביב"},
{"hotel": "Hotel with émojis 🏨", "price": 500, "location": "Jerusalem"}
]
}, headers=auth_headers)
# Should handle Unicode properly
assert response.status_code != 500
class TestExportDownload:
"""Tests for export download endpoint"""
def test_download_unauthorized(self, client):
"""Test that download requires authentication"""
response = client.get("/api/export/download/some-file-id")
assert response.status_code in [401, 404]
def test_download_nonexistent_file(self, client, auth_headers):
"""Test download of non-existent file"""
response = client.get("/api/export/download/nonexistent-file", headers=auth_headers)
assert response.status_code in [404, 400]
def test_download_path_traversal(self, client, auth_headers):
"""Test that path traversal attacks are blocked"""
malicious_paths = [
"../../../etc/passwd",
"..\\..\\..\\windows\\system32\\config\\sam",
"/etc/passwd",
"....//....//....//etc/passwd",
]
for path in malicious_paths:
response = client.get(f"/api/export/download/{path}", headers=auth_headers)
# Should NOT return a 200 with actual file content
assert response.status_code in [400, 404, 422]
|