97 lines
3.8 KiB
Python
97 lines
3.8 KiB
Python
import json
|
|||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from django.conf import settings
|
||
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||
|
|
from django.test import TestCase, override_settings
|
||
|
|
from django.urls import reverse
|
||
|
|
|
||
|
|
from menu.models import Dish, DishCategory, Order
|
||
|
|
|
||
|
|
|
||
|
|
TEST_MEDIA_ROOT = Path(settings.BASE_DIR) / 'test_media'
|
||
|
|
|
||
|
|
|
||
|
|
@override_settings(MEDIA_ROOT=TEST_MEDIA_ROOT)
|
||
|
|
class UploadImageTests(TestCase):
|
||
|
|
def tearDown(self):
|
||
|
|
if TEST_MEDIA_ROOT.exists():
|
||
|
|
for path in sorted(TEST_MEDIA_ROOT.rglob('*'), reverse=True):
|
||
|
|
if path.is_file():
|
||
|
|
path.unlink()
|
||
|
|
elif path.is_dir():
|
||
|
|
path.rmdir()
|
||
|
|
|
||
|
|
def test_upload_rejects_invalid_extension(self):
|
||
|
|
image = SimpleUploadedFile('bad.txt', b'file-content', content_type='image/png')
|
||
|
|
|
||
|
|
response = self.client.post(reverse('upload'), {'image': image})
|
||
|
|
|
||
|
|
self.assertEqual(response.status_code, 400)
|
||
|
|
self.assertEqual(response.json()['error'], 'Unsupported image extension')
|
||
|
|
|
||
|
|
def test_upload_rejects_invalid_content_type(self):
|
||
|
|
image = SimpleUploadedFile('dish.png', b'file-content', content_type='text/plain')
|
||
|
|
|
||
|
|
response = self.client.post(reverse('upload'), {'image': image})
|
||
|
|
|
||
|
|
self.assertEqual(response.status_code, 400)
|
||
|
|
self.assertEqual(response.json()['error'], 'Unsupported image content type')
|
||
|
|
|
||
|
|
@override_settings(MAX_UPLOAD_IMAGE_SIZE=4)
|
||
|
|
def test_upload_rejects_oversized_file(self):
|
||
|
|
image = SimpleUploadedFile('dish.png', b'12345', content_type='image/png')
|
||
|
|
|
||
|
|
response = self.client.post(reverse('upload'), {'image': image})
|
||
|
|
|
||
|
|
self.assertEqual(response.status_code, 400)
|
||
|
|
self.assertEqual(response.json()['error'], 'Image file too large')
|
||
|
|
|
||
|
|
def test_upload_returns_absolute_media_url(self):
|
||
|
|
image = SimpleUploadedFile('dish.png', b'png-bytes', content_type='image/png')
|
||
|
|
|
||
|
|
response = self.client.post(reverse('upload'), {'image': image}, secure=True)
|
||
|
|
|
||
|
|
self.assertEqual(response.status_code, 200)
|
||
|
|
data = response.json()
|
||
|
|
self.assertTrue(data['url'].startswith('https://testserver/media/dishes/'))
|
||
|
|
|
||
|
|
|
||
|
|
class ParseUrlTests(TestCase):
|
||
|
|
def test_parse_url_rejects_non_allowlisted_host(self):
|
||
|
|
response = self.client.post(
|
||
|
|
'/api/parse-url/',
|
||
|
|
data=json.dumps({'url': 'http://127.0.0.1/internal'}),
|
||
|
|
content_type='application/json',
|
||
|
|
)
|
||
|
|
|
||
|
|
self.assertEqual(response.status_code, 400)
|
||
|
|
self.assertEqual(response.json()['error'], '该站点不在允许的解析范围内')
|
||
|
|
|
||
|
|
|
||
|
|
class OrderApiTests(TestCase):
|
||
|
|
def setUp(self):
|
||
|
|
category = DishCategory.objects.create(name='热菜')
|
||
|
|
self.dish1 = Dish.objects.create(name='宫保鸡丁', category=category, ingredients=[{'name': '鸡肉', 'amount': '300g'}])
|
||
|
|
self.dish2 = Dish.objects.create(name='鱼香肉丝', category=category, ingredients=[{'name': '猪肉', 'amount': '200g'}])
|
||
|
|
|
||
|
|
def test_create_order_binds_dish_ids_and_returns_saved_object(self):
|
||
|
|
payload = {
|
||
|
|
'name': '周末聚会',
|
||
|
|
'dish_ids': [self.dish1.id, self.dish2.id],
|
||
|
|
'participants': ['张三', '李四'],
|
||
|
|
'party_date': '2026-03-10T12:30:00Z',
|
||
|
|
}
|
||
|
|
|
||
|
|
response = self.client.post('/api/orders/', payload, content_type='application/json')
|
||
|
|
|
||
|
|
self.assertEqual(response.status_code, 201)
|
||
|
|
data = response.json()
|
||
|
|
self.assertEqual(data['name'], '周末聚会')
|
||
|
|
self.assertEqual(sorted(d['id'] for d in data['dishes_detail']), sorted([self.dish1.id, self.dish2.id]))
|
||
|
|
self.assertEqual(data['participants'], ['张三', '李四'])
|
||
|
|
|
||
|
|
order = Order.objects.get(pk=data['id'])
|
||
|
|
self.assertEqual(order.dishes.count(), 2)
|
||
|
|
self.assertEqual(sorted(order.dishes.values_list('id', flat=True)), sorted([self.dish1.id, self.dish2.id]))
|