Feature: Remove unused tests and add tests for DRF-api

This commit is contained in:
winkidney
2019-02-22 15:26:15 +08:00
parent d9b5a78b36
commit ef05e4ad8e
7 changed files with 128 additions and 349 deletions

View File

@@ -1,18 +0,0 @@
from django import forms
from django_images.models import Image
FIELD_NAME_MAPPING = {
'image': 'qqfile',
}
class ImageForm(forms.ModelForm):
def add_prefix(self, field_name):
field_name = FIELD_NAME_MAPPING.get(field_name, field_name)
return super(ImageForm, self).add_prefix(field_name)
class Meta:
model = Image
fields = ('image',)

View File

@@ -107,16 +107,15 @@ class PinSerializer(serializers.HyperlinkedModelSerializer):
required=False, required=False,
) )
def validate(self, attrs): def create(self, validated_data):
if 'url' not in attrs and 'image_by_id' not in attrs: if 'url' not in validated_data and\
'image_by_id' not in validated_data:
raise ValidationError( raise ValidationError(
detail={ detail={
"url-or-image": "Either url or image_by_id is required." "url-or-image": "Either url or image_by_id is required."
}, },
) )
return attrs
def create(self, validated_data):
submitter = self.context['request'].user submitter = self.context['request'].user
if 'url' in validated_data and validated_data['url']: if 'url' in validated_data and validated_data['url']:
url = validated_data['url'] url = validated_data['url']
@@ -133,9 +132,9 @@ class PinSerializer(serializers.HyperlinkedModelSerializer):
return pin return pin
def update(self, instance, validated_data): def update(self, instance, validated_data):
tags = validated_data.pop('tag_list') tags = validated_data.pop('tag_list', None)
if tags: if tags:
instance.tags.set(*tags) instance.tags.set(*tags)
# change for image-id is not allowed # change for image-id or image is not allowed
validated_data.pop('image_by_id', None) validated_data.pop('image_by_id', None)
return super(PinSerializer, self).update(instance, validated_data) return super(PinSerializer, self).update(instance, validated_data)

View File

@@ -1,5 +1,3 @@
from .api import * from .api import *
from .forms import *
from .helpers import PinFactoryTest
from .views import * from .views import *

View File

@@ -1,16 +1,15 @@
import json
from django.urls import reverse
import mock import mock
from rest_framework import status
from rest_framework.test import APITestCase
from django_images.models import Thumbnail from django_images.models import Thumbnail
from taggit.models import Tag from taggit.models import Tag
from tastypie.exceptions import Unauthorized
from tastypie.test import ResourceTestCase
from .helpers import ImageFactory, PinFactory, UserFactory from .helpers import create_image, create_user, create_pin
from core.models import Pin, Image from core.models import Pin, Image
from users.models import User
__all__ = ['ImageResourceTest', 'PinResourceTest']
def filter_generator_for(size): def filter_generator_for(size):
@@ -19,265 +18,123 @@ def filter_generator_for(size):
return wrapped_func return wrapped_func
def mock_requests_get(url): def mock_requests_get(url, **kwargs):
response = mock.Mock(content=open('logo.png', 'rb').read()) response = mock.Mock(content=open('logo.png', 'rb').read())
return response return response
class ImageResourceTest(ResourceTestCase): class ImageTests(APITestCase):
def test_post_create_unsupported(self): def test_post_create_unsupported(self):
"""Make sure that new images can't be created using API""" url = reverse("image-list")
response = self.api_client.post('/api/v1/image/', format='json', data={}) data = {}
self.assertHttpUnauthorized(response) response = self.client.post(
url,
def test_list_detail(self): data=data,
image = ImageFactory() format='json',
thumbnail = filter_generator_for('thumbnail')(image) )
standard = filter_generator_for('standard')(image) self.assertEqual(response.status_code, 403, response.data)
square = filter_generator_for('square')(image)
response = self.api_client.get('/api/v1/image/', format='json')
self.assertDictEqual(self.deserialize(response)['objects'][0], {
u'image': unicode(image.image.url),
u'height': image.height,
u'width': image.width,
u'standard': {
u'image': unicode(standard.image.url),
u'width': standard.width,
u'height': standard.height,
},
u'thumbnail': {
u'image': unicode(thumbnail.image.url),
u'width': thumbnail.width,
u'height': thumbnail.height,
},
u'square': {
u'image': unicode(square.image.url),
u'width': square.width,
u'height': square.height,
},
})
class PinResourceTest(ResourceTestCase): class PinTests(APITestCase):
_JSON_TYPE = "application/json"
def setUp(self): def setUp(self):
super(PinResourceTest, self).setUp() super(PinTests, self).setUp()
self.user = UserFactory(password='password') self.user = create_user("default")
self.api_client.client.login(username=self.user.username, password='password') self.client.login(username=self.user.username, password='password')
def tearDown(self):
Pin.objects.all().delete()
Image.objects.all().delete()
Tag.objects.all().delete()
@mock.patch('requests.get', mock_requests_get) @mock.patch('requests.get', mock_requests_get)
def test_post_create_url(self): def test_should_create_pin(self):
url = 'http://testserver/mocked/logo.png' url = 'http://testserver.com/mocked/logo-01.png'
referer = 'http://testserver/' create_url = reverse("pin-list")
referer = 'http://testserver.com/'
post_data = { post_data = {
'submitter': '/api/v1/user/{}/'.format(self.user.pk),
'url': url, 'url': url,
'referer': referer, 'referer': referer,
'description': 'That\'s an Apple!' 'description': 'That\'s an Apple!'
} }
response = self.api_client.post('/api/v1/pin/', data=post_data) response = self.client.post(create_url, data=post_data, format="json")
self.assertHttpCreated(response) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Pin.objects.count(), 1) pin = Pin.objects.get(url=url)
self.assertEqual(Image.objects.count(), 1) self.assertIsNotNone(pin.image.image)
# submitter is optional, current user will be used by default
post_data = {
'url': url,
'description': 'That\'s an Apple!',
'origin': None
}
response = self.api_client.post('/api/v1/pin/', data=post_data)
self.assertHttpCreated(response)
@mock.patch('requests.get', mock_requests_get) @mock.patch('requests.get', mock_requests_get)
def test_post_create_url_with_empty_tags(self): def test_post_create_url_with_empty_tags(self):
url = 'http://testserver/mocked/logo.png' url = 'http://testserver.com/mocked/logo-02.png'
referer = 'http://testserver/' create_url = reverse("pin-list")
referer = 'http://testserver.com/'
post_data = { post_data = {
'submitter': '/api/v1/user/{}/'.format(self.user.pk),
'url': url, 'url': url,
'referer': referer, 'referer': referer,
'description': 'That\'s an Apple!', 'description': 'That\'s an Apple!',
'tags': [] 'tags': []
} }
response = self.api_client.post('/api/v1/pin/', data=post_data) response = self.client.post(create_url, data=post_data, format="json")
self.assertHttpCreated(response) self.assertEqual(
self.assertEqual(Pin.objects.count(), 1) response.status_code, status.HTTP_201_CREATED, response.json()
)
self.assertEqual(Image.objects.count(), 1) self.assertEqual(Image.objects.count(), 1)
pin = Pin.objects.get(url=url) pin = Pin.objects.get(url=url)
self.assertIsNotNone(pin.image.image)
self.assertEqual(pin.tags.count(), 0) self.assertEqual(pin.tags.count(), 0)
@mock.patch('requests.get', mock_requests_get) def test_should_post_create_pin_with_existed_image(self):
def test_post_create_url_unauthorized(self): image = create_image()
url = 'http://testserver/mocked/logo.png' create_pin(self.user, image=image, tags=[])
referer = 'http://testserver/' create_url = reverse("pin-list")
referer = 'http://testserver.com/'
post_data = { post_data = {
'submitter': '/api/v1/user/2/',
'url': url,
'referer': referer, 'referer': referer,
'description': 'That\'s an Apple!', 'image_by_id': image.pk,
'tags': []
}
with self.assertRaises(Unauthorized):
response = self.api_client.post('/api/v1/pin/', data=post_data)
self.assertEqual(Pin.objects.count(), 0)
self.assertEqual(Image.objects.count(), 0)
@mock.patch('requests.get', mock_requests_get)
def test_post_create_url_with_empty_origin(self):
url = 'http://testserver/mocked/logo.png'
referer = 'http://testserver/'
post_data = {
'submitter': '/api/v1/user/{}/'.format(self.user.pk),
'url': url,
'referer': referer,
'description': 'That\'s an Apple!',
'origin': None
}
response = self.api_client.post('/api/v1/pin/', data=post_data)
self.assertHttpCreated(response)
self.assertEqual(Pin.objects.count(), 1)
self.assertEqual(Image.objects.count(), 1)
self.assertEqual(Pin.objects.get(url=url).origin, None)
@mock.patch('requests.get', mock_requests_get)
def test_post_create_url_with_origin(self):
origin = 'http://testserver/mocked/'
url = origin + 'logo.png'
referer = 'http://testserver/'
post_data = {
'submitter': '/api/v1/user/{}/'.format(self.user.pk),
'url': url,
'referer': referer,
'description': 'That\'s an Apple!',
'origin': origin
}
response = self.api_client.post('/api/v1/pin/', data=post_data)
self.assertHttpCreated(response)
self.assertEqual(Pin.objects.count(), 1)
self.assertEqual(Image.objects.count(), 1)
self.assertEqual(Pin.objects.get(url=url).origin, origin)
def test_post_create_obj(self):
image = ImageFactory()
referer = 'http://testserver/'
post_data = {
'submitter': '/api/v1/user/{}/'.format(self.user.pk),
'referer': referer,
'image': '/api/v1/image/{}/'.format(image.pk),
'description': 'That\'s something else (probably a CC logo)!', 'description': 'That\'s something else (probably a CC logo)!',
'tags': ['random', 'tags'], 'tags': ['random', 'tags'],
} }
response = self.api_client.post('/api/v1/pin/', data=post_data) response = self.client.post(create_url, data=post_data, format="json")
resp_data = response.json()
self.assertEqual(response.status_code, status.HTTP_201_CREATED, resp_data)
self.assertEqual( self.assertEqual(
self.deserialize(response)['description'], resp_data['description'],
'That\'s something else (probably a CC logo)!' 'That\'s something else (probably a CC logo)!',
resp_data
) )
self.assertHttpCreated(response) self.assertEquals(Pin.objects.count(), 2)
# A number of Image objects should stay the same as we are using an existing image
self.assertEqual(Image.objects.count(), 1)
self.assertEqual(Pin.objects.count(), 1)
self.assertEquals(Tag.objects.count(), 2)
def test_put_detail_unauthenticated(self): def test_patch_detail_unauthenticated(self):
self.api_client.client.logout() image = create_image()
uri = '/api/v1/pin/{}/'.format(PinFactory().pk) pin = create_pin(self.user, image, [])
response = self.api_client.put(uri, format='json', data={}) self.client.logout()
self.assertHttpUnauthorized(response) uri = reverse("pin-detail", kwargs={"pk": pin.pk})
response = self.client.patch(uri, format='json', data={})
self.assertEqual(response.status_code, 403)
def test_put_detail_unauthorized(self): def test_patch_detail(self):
uri = '/api/v1/pin/{}/'.format(PinFactory(submitter=self.user).pk) image = create_image()
user = UserFactory(password='password') pin = create_pin(self.user, image, [])
self.api_client.client.login(username=user.username, password='password') uri = reverse("pin-detail", kwargs={"pk": pin.pk})
response = self.api_client.put(uri, format='json', data={})
self.assertHttpUnauthorized(response)
def test_put_detail(self):
pin = PinFactory(submitter=self.user)
uri = '/api/v1/pin/{}/'.format(pin.pk)
new = {'description': 'Updated description'} new = {'description': 'Updated description'}
response = self.api_client.put(uri, format='json', data=new) response = self.client.patch(
self.assertHttpAccepted(response) uri, new, format="json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
self.assertEqual(Pin.objects.count(), 1) self.assertEqual(Pin.objects.count(), 1)
self.assertEqual(Pin.objects.get(pk=pin.pk).description, new['description']) self.assertEqual(Pin.objects.get(pk=pin.pk).description, new['description'])
def test_delete_detail_unauthenticated(self): def test_delete_detail_unauthenticated(self):
uri = '/api/v1/pin/{}/'.format(PinFactory(submitter=self.user).pk) image = create_image()
self.api_client.client.logout() pin = create_pin(self.user, image, [])
self.assertHttpUnauthorized(self.api_client.delete(uri)) uri = reverse("pin-detail", kwargs={"pk": pin.pk})
self.client.logout()
def test_delete_detail_unauthorized(self): self.assertEqual(self.client.delete(uri).status_code, 403)
uri = '/api/v1/pin/{}/'.format(PinFactory(submitter=self.user).pk)
User.objects.create_user('test', 'test@example.com', 'test')
self.api_client.client.login(username='test', password='test')
self.assertHttpUnauthorized(self.api_client.delete(uri))
def test_delete_detail(self): def test_delete_detail(self):
uri = '/api/v1/pin/{}/'.format(PinFactory(submitter=self.user).pk) image = create_image()
self.assertHttpAccepted(self.api_client.delete(uri)) pin = create_pin(self.user, image, [])
uri = reverse("pin-detail", kwargs={"pk": pin.pk})
self.client.delete(uri)
self.assertEqual(Pin.objects.count(), 0) self.assertEqual(Pin.objects.count(), 0)
def test_get_list_json_ordered(self):
_, pin = PinFactory(), PinFactory()
response = self.api_client.get('/api/v1/pin/', format='json', data={'order_by': '-id'})
self.assertValidJSONResponse(response)
self.assertEqual(self.deserialize(response)['objects'][0]['id'], pin.id)
def test_get_list_json_filtered_by_tags(self):
pin = PinFactory()
response = self.api_client.get('/api/v1/pin/', format='json', data={'tag': pin.tags.all()[0]})
self.assertValidJSONResponse(response)
self.assertEqual(self.deserialize(response)['objects'][0]['id'], pin.pk)
def test_get_list_json_filtered_by_submitter(self):
pin = PinFactory(submitter=self.user)
response = self.api_client.get('/api/v1/pin/', format='json', data={'submitter__username': self.user.username})
self.assertValidJSONResponse(response)
self.assertEqual(self.deserialize(response)['objects'][0]['id'], pin.pk)
def test_get_list_json(self):
image = ImageFactory()
pin = PinFactory(**{
'submitter': self.user,
'image': image,
'referer': 'http://testserver/mocked/',
'url': 'http://testserver/mocked/logo.png',
'description': u'Mocked Description',
'origin': None
})
standard = filter_generator_for('standard')(image)
thumbnail = filter_generator_for('thumbnail')(image)
square = filter_generator_for('square')(image)
response = self.api_client.get('/api/v1/pin/', format='json')
self.assertValidJSONResponse(response)
self.assertDictEqual(self.deserialize(response)['objects'][0], {
u'id': pin.id,
u'submitter': {
u'username': unicode(self.user.username),
u'gravatar': unicode(self.user.gravatar)
},
u'image': {
u'image': unicode(image.image.url),
u'width': image.width,
u'height': image.height,
u'standard': {
u'image': unicode(standard.image.url),
u'width': standard.width,
u'height': standard.height,
},
u'thumbnail': {
u'image': unicode(thumbnail.image.url),
u'width': thumbnail.width,
u'height': thumbnail.height,
},
u'square': {
u'image': unicode(square.image.url),
u'width': square.width,
u'height': square.height,
},
},
u'url': pin.url,
u'origin': pin.origin,
u'description': pin.description,
u'tags': [tag.name for tag in pin.tags.all()]
})

View File

@@ -1,11 +0,0 @@
from django.test import TestCase
from ..forms import ImageForm
__all__ = ['ImageFormTest']
class ImageFormTest(TestCase):
def test_image_field_prefix(self):
"""Assert that the image field has a proper name"""
form = ImageForm()
self.assertInHTML("<input id='id_qqfile' name='qqfile' type='file' />", str(form))

View File

@@ -1,11 +1,7 @@
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Permission
from django.core.files.images import ImageFile from django.core.files.images import ImageFile
from django.db.models.query import QuerySet
from django.test import TestCase
from django_images.models import Thumbnail from django_images.models import Thumbnail
import factory
from taggit.models import Tag from taggit.models import Tag
from core.models import Pin, Image from core.models import Pin, Image
@@ -15,78 +11,33 @@ from users.models import User
TEST_IMAGE_PATH = 'logo.png' TEST_IMAGE_PATH = 'logo.png'
class UserFactory(factory.Factory): def create_user(username):
FACTORY_FOR = User user, _ = User.objects.get_or_create(
username='user_{}'.format(username),
username = factory.Sequence(lambda n: 'user_{}'.format(n)) defaults={
email = factory.Sequence(lambda n: 'user_{}@example.com'.format(n)) "email": 'user_{}@example.com'.format(username)
}
@factory.post_generation(extract_prefix='password') )
def set_password(self, create, extracted, **kwargs): user.set_password("password")
self.set_password(extracted) user.save()
self.save() return user
@factory.post_generation(extract_prefix='user_permissions')
def set_user_permissions(self, create, extracted, **kwargs):
self.user_permissions = Permission.objects.filter(codename__in=['add_pin', 'add_image'])
class TagFactory(factory.Factory): def create_tag(name):
FACTORY_FOR = Tag return Tag.objects.get_or_create(
name='tag_{}'.format(name),
name = factory.Sequence(lambda n: 'tag_{}'.format(n)) slug='tag_{}'.format(name),
)
class ImageFactory(factory.Factory): def create_image():
FACTORY_FOR = Image image = Image.objects.create(image=ImageFile(open(TEST_IMAGE_PATH, 'rb')))
for size in settings.IMAGE_SIZES.keys():
image = factory.LazyAttribute(lambda a: ImageFile(open(TEST_IMAGE_PATH, 'rb'))) Thumbnail.objects.get_or_create_at_size(image.pk, size)
return image
@factory.post_generation()
def create_thumbnails(self, create, extracted, **kwargs):
for size in settings.IMAGE_SIZES.keys():
Thumbnail.objects.get_or_create_at_size(self.pk, size)
class PinFactory(factory.Factory): def create_pin(user, image, tags):
FACTORY_FOR = Pin pin = Pin.objects.create(submitter=user, image=image)
pin.tags.set(*tags)
submitter = factory.SubFactory(UserFactory) return pin
image = factory.SubFactory(ImageFactory)
@factory.post_generation(extract_prefix='tags')
def add_tags(self, create, extracted, **kwargs):
if isinstance(extracted, Tag):
self.tags.add(extracted)
elif isinstance(extracted, list):
self.tags.add(*extracted)
elif isinstance(extracted, QuerySet):
self.tags = extracted
else:
self.tags.add(TagFactory())
class PinFactoryTest(TestCase):
def test_default_tags(self):
tags = PinFactory.create().tags.all()
self.assertTrue(all([tag.name.startswith('tag_') for tag in tags]))
self.assertEqual(tags.count(), 1)
def test_custom_tag(self):
custom = 'custom_tag'
self.assertEqual(PinFactory(tags=Tag.objects.create(name=custom)).tags.get(pk=1).name, custom)
def test_custom_tags_list(self):
tags = TagFactory.create_batch(2)
PinFactory(tags=tags)
self.assertEqual(Tag.objects.count(), 2)
def test_custom_tags_queryset(self):
TagFactory.create_batch(2)
tags = Tag.objects.all()
PinFactory(tags=tags)
self.assertEqual(Tag.objects.count(), 2)
def test_empty_tags(self):
PinFactory(tags=[])
self.assertEqual(Tag.objects.count(), 0)

View File

@@ -3,8 +3,9 @@ from django.core.urlresolvers import reverse
from django.template import TemplateDoesNotExist from django.template import TemplateDoesNotExist
from django.test import TestCase from django.test import TestCase
from .api import UserFactory
from core.models import Image from core.models import Image
from core.tests import create_user
from users.models import User
__all__ = ['CreateImageTest'] __all__ = ['CreateImageTest']
@@ -12,25 +13,27 @@ __all__ = ['CreateImageTest']
class CreateImageTest(TestCase): class CreateImageTest(TestCase):
def setUp(self): def setUp(self):
self.user = UserFactory(password='password') self.user = create_user("default")
self.client.login(username=self.user.username, password='password') self.client.login(username=self.user.username, password='password')
def test_get_browser(self): def tearDown(self):
response = self.client.get(reverse('core:create-image')) User.objects.all().delete()
self.assertRedirects(response, reverse('core:recent-pins')) Image.objects.all().delete()
def test_get_xml_http_request(self):
with self.assertRaises(TemplateDoesNotExist):
self.client.get(reverse('core:create-image'), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
def test_post(self): def test_post(self):
with open(settings.SITE_ROOT + 'logo.png', mode='rb') as image: with open('logo.png', mode='rb') as image:
response = self.client.post(reverse('core:create-image'), {'qqfile': image}) response = self.client.post(reverse('image-list'), {'image': image})
image = Image.objects.latest('pk') image = Image.objects.latest('pk')
self.assertJSONEqual(response.content, {'success': {'id': image.pk}}) self.assertEqual(response.json()['id'], image.pk)
def test_post_error(self): def test_post_error(self):
response = self.client.post(reverse('core:create-image'), {'qqfile': None}) response = self.client.post(reverse('image-list'), {'image': None})
self.assertJSONEqual(response.content, { self.assertJSONEqual(
'error': {'image': ['This field is required.']} response.content,
}) {
'image': [
'The submitted data was not a file. '
'Check the encoding type on the form.'
]
}
)