class TestBulkAPIView(TestCase): def setUp(self): super(TestBulkAPIView, self).setUp() self.view = SimpleBulkAPIView.as_view() self.request = RequestFactory() def test_get(self): """ Test that GET request is successful on bulk view. """ response = self.view(self.request.get('')) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_post_single(self): """ Test that POST request with single resource only creates a single resource. """ response = self.view( self.request.post( '', json.dumps({ 'contents': 'hello world', 'number': 1 }), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(SimpleModel.objects.count(), 1) self.assertEqual(SimpleModel.objects.get().contents, 'hello world') def test_post_bulk(self): """ Test that POST request with multiple resources creates all posted resources. """ response = self.view( self.request.post( '', json.dumps([ { 'contents': 'hello world', 'number': 1 }, { 'contents': 'hello mars', 'number': 2 }, ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual( list(SimpleModel.objects.all().values_list('contents', flat=True)), [ 'hello world', 'hello mars', ]) def test_put(self): """ Test that PUT request updates all submitted resources. """ obj1 = SimpleModel.objects.create(contents='hello world', number=1) obj2 = SimpleModel.objects.create(contents='hello mars', number=2) response = self.view( self.request.put( '', json.dumps([ { 'contents': 'foo', 'number': 3, 'id': obj1.pk }, { 'contents': 'bar', 'number': 4, 'id': obj2.pk }, ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual( list(SimpleModel.objects.all().values_list('id', 'contents', 'number')), [ (obj1.pk, 'foo', 3), (obj2.pk, 'bar', 4), ]) def test_put_without_update_key(self): """ Test that PUT request updates all submitted resources. """ response = self.view( self.request.put( '', json.dumps([ { 'contents': 'foo', 'number': 3 }, { 'contents': 'rainbows', 'number': 4 }, # multiple objects without id { 'contents': 'bar', 'number': 4, 'id': 555 }, # non-existing id ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_patch(self): """ Test that PATCH request partially updates all submitted resources. """ obj1 = SimpleModel.objects.create(contents='hello world', number=1) obj2 = SimpleModel.objects.create(contents='hello mars', number=2) response = self.view( self.request.patch( '', json.dumps([ { 'contents': 'foo', 'id': obj1.pk }, { 'contents': 'bar', 'id': obj2.pk }, ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual( list(SimpleModel.objects.all().values_list('id', 'contents', 'number')), [ (obj1.pk, 'foo', 1), (obj2.pk, 'bar', 2), ]) def test_delete_not_filtered(self): """ Test that DELETE is not allowed when results are not filtered. """ SimpleModel.objects.create(contents='hello world', number=1) SimpleModel.objects.create(contents='hello mars', number=10) response = self.view(self.request.delete('')) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_delete_filtered(self): """ Test that DELETE removes all filtered resources. """ SimpleModel.objects.create(contents='hello world', number=1) SimpleModel.objects.create(contents='hello mars', number=10) response = FilteredBulkAPIView.as_view()(self.request.delete('')) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(SimpleModel.objects.count(), 1) self.assertEqual(SimpleModel.objects.get().contents, 'hello world') def test_options(self): """ Test that OPTIONS request is successful on bulk view. """ response = self.view(self.request.options('')) self.assertEqual(response.status_code, status.HTTP_200_OK)
class BulkUpdateTestCase(TestCase): def setUp(self): self.fixture = create_fixture() self.rf = RequestFactory() self.view = DogViewSet.as_view({'patch': 'partial_update'}) def test_bulk_update_default_style(self): ''' Test that PATCH request partially updates all submitted resources. ''' data = [{'id': 1, 'fur': 'grey'}, {'id': 2, 'fur': 'grey'}] request = self.rf.patch( '/dogs/', json.dumps(data), content_type='application/json' ) response = self.view(request) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue('dogs' in response.data) self.assertTrue(2, len(response.data['dogs'])) self.assertTrue( all([Dog.objects.get(id=pk).fur_color == 'grey' for pk in (1, 2)]) ) def test_bulk_update_drest_style(self): data = {'dogs': [{'id': 1, 'fur': 'grey'}, {'id': 2, 'fur': 'grey'}]} request = self.rf.patch( '/dogs/', json.dumps(data), content_type='application/json' ) response = self.view(request) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue('dogs' in response.data) def test_bulk_update_with_filter(self): ''' Test that you can patch inside of the filtered queryset. ''' data = [{'id': 3, 'fur': 'gold'}] request = self.rf.patch( '/dogs/?filter{fur.contains}=brown', json.dumps(data), content_type='application/json' ) response = self.view(request) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue(Dog.objects.get(id=3).fur_color == 'gold') def test_bulk_update_fail_without_lookup_attribute(self): ''' Test that PATCH request will fail if lookup attribute wasn't provided. ''' data = [{'fur': 'grey'}] request = self.rf.patch( '/dogs/?filter{fur.contains}=brown', json.dumps(data), content_type='application/json' ) response = self.view(request) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class DRYRestPermissionsTests(TestCase): def setUp(self): self.action_set = [ 'retrieve', 'list', 'create', 'destroy', 'update', 'partial_update', 'custom_action1', 'custom_action2' ] self.factory = RequestFactory() self.request_retrieve = Request(self.factory.get('/dummy/1')) self.request_list = Request(self.factory.get('/dummy')) self.request_create = Request(self.factory.post('/dummy'), {}) self.request_destroy = Request(self.factory.delete('/dummy/1')) self.request_update = Request(self.factory.put('/dummy/1', {})) self.request_partial_update = Request( self.factory.patch('/dummy/1', {})) self.request_custom_action1 = Request( self.factory.get('/dummy/custom_action1')) self.request_custom_action2 = Request( self.factory.post('/dummy/custom_action2', {})) def _run_permission_checks(self, view, obj, assert_value): for action in self.action_set: view.action = action request_name = "request_{action}".format(action=action) result = view.dummy_check_permission(getattr(self, request_name), obj) self.assertEqual(result, assert_value) def _run_dry_permission_field_checks(self, view, obj, assert_specific, assert_base): serializer = view.get_serializer_class()() # dummy request serializer.context['request'] = self.request_retrieve representation = serializer.to_representation(obj) for action in [ action for action in self.action_set if action not in ['partial_update', 'list'] ]: has_permission = representation['permissions'].get(action, None) self.assertEqual( has_permission, assert_specific, "Action '%s' %s != %s" % (action, has_permission, assert_specific)) for action in ['read', 'write']: has_permission = representation['permissions'].get(action, None) self.assertEqual( has_permission, assert_base, "Action '%s' %s != %s" % (action, has_permission, assert_base)) def test_true_base_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), None, True) def test_false_base_object_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin): base_object_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), None, False) def test_false_base_global_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin): base_global_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), None, False) def test_true_specific_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): base_global_allowed = False base_object_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, False) def test_true_base_not_defined_permissions(self): class TestModel(DummyModel, SpecificObjectMixin, SpecificGlobalMixin): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, None) def test_false_specific_object_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): specific_object_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), False, True) def test_false_specific_global_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): specific_global_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), False, True) def test_true_no_global_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): base_global_allowed = False specific_global_allowed = False class TestSerializer(DummySerializer): permissions = DRYPermissionsField( object_only=True, additional_actions=['custom_action1', 'custom_action2']) class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer permission_classes = (DRYObjectPermissions, ) view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, True) def test_true_no_object_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): base_object_allowed = False specific_object_allowed = False class TestSerializer(DummySerializer): permissions = DRYPermissionsField( global_only=True, additional_actions=['custom_action1', 'custom_action2']) class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer permission_classes = (DRYGlobalPermissions, ) view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, True) def test_list_filter_backend(self): class DummyFilter(object): pass class TestModel(DummyModel): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestFilterBackend(DRYPermissionFiltersBase): def filter_list_queryset(self, request, queryset, view): return DummyFilter() class TestViewSet(DummyViewSet): serializer_class = TestSerializer queryset = TestModel.objects.all() filter_backends = (TestFilterBackend, ) view = TestViewSet() view.request = self.request_list view.action = 'list' view.kwargs = [] query_set = view.filter_queryset(view.get_queryset()) self.assertEqual(query_set.__class__, DummyFilter) def test_action_filter_backend(self): class DummyFilter(object): pass class TestModel(DummyModel): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestFilterBackend(DRYPermissionFiltersBase): action_routing = True def filter_list_queryset(self, request, queryset, view): return None def filter_custom_action1_queryset(self, request, queryset, view): return DummyFilter() class TestViewSet(DummyViewSet): serializer_class = TestSerializer queryset = TestModel.objects.all() filter_backends = (TestFilterBackend, ) view = TestViewSet() view.request = self.request_custom_action1 view.action = 'custom_action1' view.kwargs = [] query_set = view.filter_queryset(view.get_queryset()) self.assertEqual(query_set.__class__, DummyFilter)
class DRYRestPermissionsTests(TestCase): def setUp(self): self.action_set = ['retrieve', 'list', 'create', 'destroy', 'update', 'partial_update', 'custom_action1', 'custom_action2'] self.factory = RequestFactory() self.request_retrieve = Request(self.factory.get('/dummy/1')) self.request_list = Request(self.factory.get('/dummy')) self.request_create = Request(self.factory.post('/dummy'), {}) self.request_destroy = Request(self.factory.delete('/dummy/1')) self.request_update = Request(self.factory.put('/dummy/1', {})) self.request_partial_update = Request(self.factory.patch('/dummy/1', {})) self.request_custom_action1 = Request(self.factory.get('/dummy/custom_action1')) self.request_custom_action2 = Request(self.factory.post('/dummy/custom_action2', {})) def _run_permission_checks(self, view, obj, assert_value): for action in self.action_set: view.action = action request_name = "request_{action}".format(action=action) result = view.dummy_check_permission(getattr(self, request_name), obj) self.assertEqual(result, assert_value) def _run_dry_permission_field_checks(self, view, obj, assert_specific, assert_base): serializer = view.get_serializer_class()() # dummy request serializer.context['request'] = self.request_retrieve representation = serializer.to_representation(obj) for action in [action for action in self.action_set if action not in ['partial_update', 'list']]: has_permission = representation['permissions'].get(action, None) self.assertEqual(has_permission, assert_specific, "Action '%s' %s != %s" % (action, has_permission, assert_specific)) for action in ['read', 'write']: has_permission = representation['permissions'].get(action, None) self.assertEqual(has_permission, assert_base, "Action '%s' %s != %s" % (action, has_permission, assert_base)) def test_true_base_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), None, True) def test_false_base_object_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin): base_object_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), None, False) def test_false_base_global_permissions(self): class TestModel(DummyModel, BaseObjectMixin, BaseGlobalMixin): base_global_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), None, False) def test_true_specific_permissions(self): class TestModel( DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): base_global_allowed = False base_object_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, False) def test_true_base_not_defined_permissions(self): class TestModel(DummyModel, SpecificObjectMixin, SpecificGlobalMixin): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, None) def test_false_specific_object_permissions(self): class TestModel( DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): specific_object_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), False, True) def test_false_specific_global_permissions(self): class TestModel( DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): specific_global_allowed = False class TestSerializer(DummySerializer): class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer view = TestViewSet() self._run_permission_checks(view, TestModel(), False) self._run_dry_permission_field_checks(view, TestModel(), False, True) def test_true_no_global_permissions(self): class TestModel( DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): base_global_allowed = False specific_global_allowed = False class TestSerializer(DummySerializer): permissions = DRYPermissionsField(object_only=True, additional_actions=['custom_action1', 'custom_action2']) class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer permission_classes = (DRYObjectPermissions, ) view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, True) def test_true_no_object_permissions(self): class TestModel( DummyModel, BaseObjectMixin, BaseGlobalMixin, SpecificObjectMixin, SpecificGlobalMixin): base_object_allowed = False specific_object_allowed = False class TestSerializer(DummySerializer): permissions = DRYPermissionsField(global_only=True, additional_actions=['custom_action1', 'custom_action2']) class Meta: model = TestModel class TestViewSet(DummyViewSet): serializer_class = TestSerializer permission_classes = (DRYGlobalPermissions, ) view = TestViewSet() self._run_permission_checks(view, TestModel(), True) self._run_dry_permission_field_checks(view, TestModel(), True, True) def test_list_filter_backend(self): class DummyFilter(object): pass class TestModel(DummyModel): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestFilterBackend(DRYPermissionFiltersBase): def filter_list_queryset(self, request, queryset, view): return DummyFilter() class TestViewSet(DummyViewSet): serializer_class = TestSerializer queryset = TestModel.objects.all() filter_backends = (TestFilterBackend,) view = TestViewSet() view.request = self.request_list view.action = 'list' view.kwargs = [] query_set = view.filter_queryset(view.get_queryset()) self.assertEqual(query_set.__class__, DummyFilter) def test_action_filter_backend(self): class DummyFilter(object): pass class TestModel(DummyModel): pass class TestSerializer(DummySerializer): class Meta: model = TestModel class TestFilterBackend(DRYPermissionFiltersBase): action_routing = True def filter_list_queryset(self, request, queryset, view): return None def filter_custom_action1_queryset(self, request, queryset, view): return DummyFilter() class TestViewSet(DummyViewSet): serializer_class = TestSerializer queryset = TestModel.objects.all() filter_backends = (TestFilterBackend,) view = TestViewSet() view.request = self.request_custom_action1 view.action = 'custom_action1' view.kwargs = [] query_set = view.filter_queryset(view.get_queryset()) self.assertEqual(query_set.__class__, DummyFilter)
class TestPlaceTagInstanceView (APITestMixin, TestCase): def setUp(self): self.owner = User.objects.create_user(username='******', password='******', email='*****@*****.**') self.submitter = User.objects.create_user(username='******', password='******', email='*****@*****.**') self.dataset = DataSet.objects.create(slug='ds', owner=self.owner) self.place = Place.objects.create( dataset=self.dataset, geometry='POINT(2 3)', submitter=self.submitter, data=json.dumps({ 'type': 'ATM', 'name': 'K-Mart', 'private-secrets': 42 }), ) self.tags = [ Tag.objects.create( name="status", dataset=self.dataset, ), ] self.tags.extend([ Tag.objects.create( name="approved", dataset=self.dataset, parent=self.tags[0] ), Tag.objects.create( name="rejected", dataset=self.dataset, parent=self.tags[0] ) ]) self.place_tag = PlaceTag.objects.create( place=self.place, submitter=self.submitter, tag=self.tags[1], note="I approve this place!" ) self.origin = Origin.objects.create(pattern='def', dataset=self.dataset) Origin.objects.create(pattern='def2', dataset=self.dataset) self.unauthorized_user = User.objects.create_user( username='******', password='******' ) self.authorized_user = User.objects.create_user( username='******', password='******' ) group = Group.objects.create( dataset=self.dataset, name='mygroup' ) group.submitters.add(self.authorized_user) GroupPermission.objects.create( group=group, # TODO: rename this to 'resource': submission_set='tags', can_destroy=True, can_update=True ) unauthorized_group = Group.objects.create( dataset=self.dataset, name='badgroup' ) unauthorized_group.submitters.add(self.unauthorized_user) unauthorized_group.submitters.add(self.authorized_user) GroupPermission.objects.create( group=unauthorized_group, # TODO: rename this to 'resource': submission_set='tags', ) self.request_kwargs = { 'owner_username': self.owner.username, 'dataset_slug': self.dataset.slug, 'place_id': self.place.id, 'place_tag_id': self.place_tag.id } self.factory = RequestFactory() self.path = reverse('place-tag-detail', kwargs=self.request_kwargs) self.view = PlaceTagInstanceView.as_view() cache_buffer.reset() django_cache.clear() def tearDown(self): User.objects.all().delete() DataSet.objects.all().delete() Place.objects.all().delete() # this should delete all of the PlaceTags as well, (via cascade) Tag.objects.all().delete() # this should delete all of the PlaceTags as well, (via cascade) # TODO: ensure that there are no more Tag or PlaceTag 's left # PlaceTag.objects.all().delete() cache_buffer.reset() django_cache.clear() def test_GET_response(self): request = self.factory.get(self.path) response = self.view(request, **self.request_kwargs) data = json.loads(response.rendered_content) # Check that the request was successful self.assertStatusCode(response, 200) # Check that the data attributes have been incorporated into the # properties self.assertEqual(data.get('note'), "I approve this place!") # Check that the appropriate attributes are in the properties self.assertIn('url', data) self.assertIn('submitter', data) self.assertIn('place', data) self.assertIn('tag', data) # Check that the URL is right self.assertEqual( data['url'], 'http://testserver' + reverse('place-tag-detail', args=[ self.owner.username, self.dataset.slug, self.place.id, self.place_tag.id]) ) def test_GET_invalid_url(self): # Make sure that we respond with 404 if a place_id is supplied, but for # the wrong dataset or owner. request_kwargs = { 'owner_username': '******', 'dataset_slug': self.dataset.slug, 'place_id': self.place.id, 'place_tag_id': self.place_tag.id } path = reverse('place-tag-detail', kwargs=request_kwargs) request = self.factory.get(path) response = self.view(request, **request_kwargs) self.assertStatusCode(response, 404) # TODO: implement this when caching is re-enabled: # def test_GET_from_cache(self): # path = reverse('submission-detail', kwargs=self.request_kwargs) # request = self.factory.get(path) # # Check that we make a finite number of queries # # # # ---- Checking data access permissions: # # # # - SELECT requested dataset and owner # # - SELECT dataset permissions # # - SELECT keys # # - SELECT key permissions # # - SELECT origins # # - SELECT origin permissions # # # # ---- Build the data # # # # - SELECT * FROM sa_api_submission AS s # # JOIN sa_api_submittedthing AS st ON (s.submittedthing_ptr_id = st.id) # # JOIN sa_api_dataset AS ds ON (st.dataset_id = ds.id) # # JOIN sa_api_submissionset AS ss ON (s.parent_id = ss.id) # # JOIN sa_api_place AS p ON (ss.place_id = p.submittedthing_ptr_id) # # JOIN sa_api_submittedthing AS pt ON (p.submittedthing_ptr_id = pt.id) # # WHERE st.id = <self.submission.id>; # # # # - SELECT * FROM sa_api_attachment AS a # # WHERE a.thing_id IN (<self.submission.id>); # # # with self.assertNumQueries(13): # response = self.view(request, **self.request_kwargs) # self.assertStatusCode(response, 200) # path = reverse('submission-detail', kwargs=self.request_kwargs) # request = self.factory.get(path) # # Check that this performs no more queries than required for auth, # # since the data's all cached # with self.assertNumQueries(0): # response = self.view(request, **self.request_kwargs) # self.assertStatusCode(response, 200) def test_DELETE_response(self): # # View should 401 when trying to delete when not authenticated # request = self.factory.delete(self.path) response = self.view(request, **self.request_kwargs) self.assertStatusCode(response, 401) # # View should 403 the place when user is unauthorized # request = self.factory.delete(self.path) request.user = self.unauthorized_user response = self.view(request, **self.request_kwargs) self.assertStatusCode(response, 403) # # View should delete the place when owner is authenticated # request = self.factory.delete(self.path) request.user = self.authorized_user response = self.view(request, **self.request_kwargs) # Check that the request was successful self.assertStatusCode(response, 204) # Check that no data was returned self.assertIsNone(response.data) def test_PUT_response(self): submission_data = json.dumps({ 'note': 'Revised comment', }) # TODO: get json from django model, merge with submission data to fix PUT # import ipdb # ipdb.set_trace() # # View should 401 when trying to update when not authenticated # request = self.factory.put(self.path, data=submission_data, content_type='application/json') response = self.view(request, **self.request_kwargs) self.assertStatusCode(response, 401) # # View should 403 when trying to update when not authorized # # user = User.objects.create_user(username='******', # password='******') request = self.factory.put(self.path, data=submission_data, content_type='application/json') request.user = self.unauthorized_user request.META['HTTP_ORIGIN'] = self.origin.pattern response = self.view(request, **self.request_kwargs) self.assertStatusCode(response, 403) # # # # View should 200 when trying to update when authorized # # # request = self.factory.put(self.path, data=submission_data, content_type='application/json') # request.user = self.authorized_user # request.META['HTTP_ORIGIN'] = self.origin.pattern # response = self.view(request, **self.request_kwargs) # self.assertStatusCode(response, 403) def test_PATCH_response(self): submission_data = json.dumps({ 'note': 'Revised comment', }) # # View should update the place when user is authenticated # request = self.factory.patch(self.path, data=submission_data, content_type='application/json') request.user = self.authorized_user request.META['HTTP_ORIGIN'] = self.origin.pattern response = self.view(request, **self.request_kwargs) # # Check that the request was successful self.assertStatusCode(response, 200) data = json.loads(response.rendered_content) # Check that the data attributes have been incorporated into the # properties self.assertEqual(data.get('note'), 'Revised comment')
class ProductResourceTestCase(TestCase): def setUp(self): self.factory = RequestFactory() self.product_resource = ProductResource() def test_GET_list_return_objects_and_count(self): """Should get a list of products with meta data""" product = ProductFactory.create() # Preconditions self.assertEqual(Product.objects.all().count(), 1) request = self.factory.get("/api/v1/product/") response = self.product_resource.dispatch_list(request) self.assertEqual(response.status_code, 200) self.assertEqual(response._charset, 'utf-8') content = json.loads(response.content.decode(response._charset)) self.assertTrue('meta' in content) self.assertTrue('total_count' in content['meta']) self.assertEqual(content['meta']['total_count'], 1) self.assertTrue('objects' in content) objects = content['objects'] self.assertEqual(len(objects), 1) obj1 = objects[0] self.assertEqual(obj1['name'], product.name) def test_GET_individual_product(self): """Should get an individual product by ID""" product = ProductFactory.create() ProductFactory.create() # Preconditions self.assertEqual(Product.objects.all().count(), 2) url = "/api/v1/product/{}/".format(product.id) request = self.factory.get(url) response = self.product_resource.dispatch_detail( request, pk=product.id) self.assertEqual(response.status_code, 200) self.assertEqual(response._charset, 'utf-8') content = json.loads(response.content.decode(response._charset)) self.assertEqual(content['name'], product.name) self.assertEqual(content['id'], product.id) def test_POST_a_product(self): """Should POST and create an individual product""" # Preconditions self.assertEqual(Product.objects.all().count(), 0) url = "/api/v1/product/" request = self.factory.post(url, data=json.dumps({ 'name': 'Test Product', 'description': 'Test description', 'inventory_count': 3 }), content_type="application/json") response = self.product_resource.dispatch_list(request) self.assertEqual(response.status_code, 201) self.assertEqual(Product.objects.all().count(), 1) def test_POST_an_invalid_inventory_product(self): """Should reject a product with invalid inventory count""" # Preconditions self.assertEqual(Product.objects.all().count(), 0) url = "/api/v1/product/" request = self.factory.post(url, data=json.dumps({ 'name': 'Test Product', 'description': 'Test description', 'inventory_count': 1000 # Too much! }), content_type="application/json") with self.assertRaises(ImmediateHttpResponse): self.product_resource.dispatch_list(request) def test_DELETE_a_product(self): """Should delete a product by ID""" product = ProductFactory.create() # Preconditions self.assertEqual(Product.objects.all().count(), 1) request = self.factory.delete("/api/v1/product/{}/".format(product.id)) response = self.product_resource.dispatch_list(request) self.assertEqual(response.status_code, 204) def test_update_a_product_inventory_count(self): """Should update the inventory count of a product through PATCH""" product = ProductFactory.create(inventory_count=3) # Preconditions self.assertEqual(Product.objects.all().count(), 1) self.assertEqual(product.inventory_count, 3) url = "/api/v1/product/{}/".format(product.id) request = self.factory.patch(url, data=json.dumps({ 'inventory_count': 7 }), content_type="application/json") response = self.product_resource.dispatch_detail( request, pk=product.id) self.assertEqual(response.status_code, 202)
class TestBulkAPIView(TestCase): def setUp(self): super(TestBulkAPIView, self).setUp() self.view = SimpleBulkAPIView.as_view() self.request = RequestFactory() def test_get(self): """ Test that GET request is successful on bulk view. """ response = self.view(self.request.get('')) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_post_single(self): """ Test that POST request with single resource only creates a single resource. """ response = self.view(self.request.post( '', json.dumps({'contents': 'hello world', 'number': 1}), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(SimpleModel.objects.count(), 1) self.assertEqual(SimpleModel.objects.get().contents, 'hello world') def test_post_bulk(self): """ Test that POST request with multiple resources creates all posted resources. """ response = self.view(self.request.post( '', json.dumps([ {'contents': 'hello world', 'number': 1}, {'contents': 'hello mars', 'number': 2}, ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual(list(SimpleModel.objects.all().values_list('contents', flat=True)), [ 'hello world', 'hello mars', ]) def test_put(self): """ Test that PUT request updates all submitted resources. """ obj1 = SimpleModel.objects.create(contents='hello world', number=1) obj2 = SimpleModel.objects.create(contents='hello mars', number=2) response = self.view(self.request.put( '', json.dumps([ {'contents': 'foo', 'number': 3, 'id': obj1.pk}, {'contents': 'bar', 'number': 4, 'id': obj2.pk}, ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual( list(SimpleModel.objects.all().values_list('id', 'contents', 'number')), [ (obj1.pk, 'foo', 3), (obj2.pk, 'bar', 4), ] ) def test_put_without_update_key(self): """ Test that PUT request updates all submitted resources. """ response = self.view(self.request.put( '', json.dumps([ {'contents': 'foo', 'number': 3}, {'contents': 'rainbows', 'number': 4}, # multiple objects without id {'contents': 'bar', 'number': 4, 'id': 555}, # non-existing id ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_patch(self): """ Test that PATCH request partially updates all submitted resources. """ obj1 = SimpleModel.objects.create(contents='hello world', number=1) obj2 = SimpleModel.objects.create(contents='hello mars', number=2) response = self.view(self.request.patch( '', json.dumps([ {'contents': 'foo', 'id': obj1.pk}, {'contents': 'bar', 'id': obj2.pk}, ]), content_type='application/json', )) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual( list(SimpleModel.objects.all().values_list('id', 'contents', 'number')), [ (obj1.pk, 'foo', 1), (obj2.pk, 'bar', 2), ] ) def test_delete_not_filtered(self): """ Test that DELETE is not allowed when results are not filtered. """ SimpleModel.objects.create(contents='hello world', number=1) SimpleModel.objects.create(contents='hello mars', number=10) response = self.view(self.request.delete('')) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_delete_filtered(self): """ Test that DELETE removes all filtered resources. """ SimpleModel.objects.create(contents='hello world', number=1) SimpleModel.objects.create(contents='hello mars', number=10) response = FilteredBulkAPIView.as_view()(self.request.delete('')) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(SimpleModel.objects.count(), 1) self.assertEqual(SimpleModel.objects.get().contents, 'hello world') def test_options(self): """ Test that OPTIONS request is successful on bulk view. """ response = self.view(self.request.options('')) self.assertEqual(response.status_code, status.HTTP_200_OK)
class DecoratorTestCase(TestCase): def setUp(self): self.factory = RequestFactory() def _finalize_response(self, request, response, *args, **kwargs): response.request = request return APIView.finalize_response(self, request, response, *args, **kwargs) def test_wrap_view(self): @api_view(['GET']) def view(request): return Response({}) self.assertTrue(isinstance(view.cls_instance, APIView)) def test_calling_method(self): @api_view(['GET']) def view(request): return Response({}) request = self.factory.get('/') response = view(request) self.assertEqual(response.status_code, 200) request = self.factory.post('/') response = view(request) self.assertEqual(response.status_code, 405) def test_calling_put_method(self): @api_view(['GET', 'PUT']) def view(request): return Response({}) request = self.factory.put('/') response = view(request) self.assertEqual(response.status_code, 200) request = self.factory.post('/') response = view(request) self.assertEqual(response.status_code, 405) def test_calling_patch_method(self): @api_view(['GET', 'PATCH']) def view(request): return Response({}) request = self.factory.patch('/') response = view(request) self.assertEqual(response.status_code, 200) request = self.factory.post('/') response = view(request) self.assertEqual(response.status_code, 405) def test_renderer_classes(self): @api_view(['GET']) @renderer_classes([JSONRenderer]) def view(request): return Response({}) request = self.factory.get('/') response = view(request) self.assertTrue(isinstance(response.accepted_renderer, JSONRenderer)) def test_parser_classes(self): @api_view(['GET']) @parser_classes([JSONParser]) def view(request): self.assertEqual(len(request.parsers), 1) self.assertTrue(isinstance(request.parsers[0], JSONParser)) return Response({}) request = self.factory.get('/') view(request) def test_authentication_classes(self): @api_view(['GET']) @authentication_classes([BasicAuthentication]) def view(request): self.assertEqual(len(request.authenticators), 1) self.assertTrue(isinstance(request.authenticators[0], BasicAuthentication)) return Response({}) request = self.factory.get('/') view(request) def test_permission_classes(self): @api_view(['GET']) @permission_classes([IsAuthenticated]) def view(request): return Response({}) request = self.factory.get('/') response = view(request) self.assertEquals(response.status_code, status.HTTP_403_FORBIDDEN) def test_throttle_classes(self): class OncePerDayUserThrottle(UserRateThrottle): rate = '1/day' @api_view(['GET']) @throttle_classes([OncePerDayUserThrottle]) def view(request): return Response({}) request = self.factory.get('/') response = view(request) self.assertEquals(response.status_code, status.HTTP_200_OK) response = view(request) self.assertEquals(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS)