Example #1
0
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)
Example #2
0
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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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)