diff options
Diffstat (limited to 'patchwork/tests/api/test_patch.py')
-rw-r--r-- | patchwork/tests/api/test_patch.py | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/patchwork/tests/api/test_patch.py b/patchwork/tests/api/test_patch.py new file mode 100644 index 0000000..909c1eb --- /dev/null +++ b/patchwork/tests/api/test_patch.py @@ -0,0 +1,208 @@ +# Patchwork - automated patch tracking system +# Copyright (C) 2016 Linaro Corporation +# +# This file is part of the Patchwork package. +# +# Patchwork is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Patchwork is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Patchwork; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from email.utils import make_msgid +import unittest + +from django.conf import settings + +from patchwork.compat import reverse +from patchwork.models import Patch +from patchwork.tests.utils import create_maintainer +from patchwork.tests.utils import create_patch +from patchwork.tests.utils import create_person +from patchwork.tests.utils import create_project +from patchwork.tests.utils import create_state +from patchwork.tests.utils import create_user + +if settings.ENABLE_REST_API: + from rest_framework import status + from rest_framework.test import APITestCase +else: + # stub out APITestCase + from django.test import TestCase + APITestCase = TestCase # noqa + + +@unittest.skipUnless(settings.ENABLE_REST_API, 'requires ENABLE_REST_API') +class TestPatchAPI(APITestCase): + fixtures = ['default_tags'] + + @staticmethod + def api_url(item=None): + if item is None: + return reverse('api-patch-list') + return reverse('api-patch-detail', args=[item]) + + def assertSerialized(self, patch_obj, patch_json): + self.assertEqual(patch_obj.id, patch_json['id']) + self.assertEqual(patch_obj.name, patch_json['name']) + self.assertEqual(patch_obj.msgid, patch_json['msgid']) + self.assertEqual(patch_obj.state.slug, patch_json['state']) + self.assertIn(patch_obj.get_mbox_url(), patch_json['mbox']) + + # nested fields + + self.assertEqual(patch_obj.submitter.id, + patch_json['submitter']['id']) + self.assertEqual(patch_obj.project.id, + patch_json['project']['id']) + + def test_list(self): + """Validate we can list a patch.""" + resp = self.client.get(self.api_url()) + self.assertEqual(status.HTTP_200_OK, resp.status_code) + self.assertEqual(0, len(resp.data)) + + person_obj = create_person(email='test@example.com') + state_obj = create_state(name='Under Review') + project_obj = create_project(linkname='myproject') + patch_obj = create_patch(state=state_obj, project=project_obj, + submitter=person_obj) + + # anonymous user + resp = self.client.get(self.api_url()) + self.assertEqual(status.HTTP_200_OK, resp.status_code) + self.assertEqual(1, len(resp.data)) + patch_rsp = resp.data[0] + self.assertSerialized(patch_obj, patch_rsp) + self.assertNotIn('headers', patch_rsp) + self.assertNotIn('content', patch_rsp) + self.assertNotIn('diff', patch_rsp) + + # authenticated user + user = create_user() + self.client.force_authenticate(user=user) + resp = self.client.get(self.api_url()) + self.assertEqual(status.HTTP_200_OK, resp.status_code) + self.assertEqual(1, len(resp.data)) + patch_rsp = resp.data[0] + self.assertSerialized(patch_obj, patch_rsp) + + # test filtering by state + resp = self.client.get(self.api_url(), {'state': 'under-review'}) + self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) + resp = self.client.get(self.api_url(), {'state': 'missing-state'}) + self.assertEqual(0, len(resp.data)) + + # test filtering by project + resp = self.client.get(self.api_url(), {'project': 'myproject'}) + self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) + resp = self.client.get(self.api_url(), {'project': 'invalidproject'}) + self.assertEqual(0, len(resp.data)) + + # test filtering by submitter, both ID and email + resp = self.client.get(self.api_url(), {'submitter': person_obj.id}) + self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) + resp = self.client.get(self.api_url(), { + 'submitter': 'test@example.com'}) + self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) + resp = self.client.get(self.api_url(), { + 'submitter': 'test@example.org'}) + self.assertEqual(0, len(resp.data)) + + def test_detail(self): + """Validate we can get a specific patch.""" + patch = create_patch( + content='Reviewed-by: Test User <test@example.com>\n') + + resp = self.client.get(self.api_url(patch.id)) + self.assertEqual(status.HTTP_200_OK, resp.status_code) + self.assertSerialized(patch, resp.data) + self.assertEqual(patch.headers, resp.data['headers'] or '') + self.assertEqual(patch.content, resp.data['content']) + self.assertEqual(patch.diff, resp.data['diff']) + self.assertEqual(0, len(resp.data['tags'])) + + def test_create(self): + """Ensure creations are rejected.""" + project = create_project() + patch = { + 'project': project, + 'submitter': create_person().id, + 'msgid': make_msgid(), + 'name': 'test-create-patch', + 'diff': 'patch diff', + } + + # anonymous user + resp = self.client.post(self.api_url(), patch) + self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code) + + # superuser + user = create_maintainer(project) + user.is_superuser = True + user.save() + self.client.force_authenticate(user=user) + resp = self.client.post(self.api_url(), patch) + self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code) + + def test_update(self): + """Ensure updates can be performed by maintainers.""" + project = create_project() + patch = create_patch(project=project) + state = create_state() + + # anonymous user + resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) + + # authenticated user + user = create_user() + self.client.force_authenticate(user=user) + resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) + + # maintainer + user = create_maintainer(project) + self.client.force_authenticate(user=user) + resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) + self.assertEqual(status.HTTP_200_OK, resp.status_code) + self.assertEqual(Patch.objects.get(id=patch.id).state, state) + + def test_update_invalid(self): + """Ensure we handle invalid Patch states.""" + project = create_project() + state = create_state() + patch = create_patch(project=project, state=state) + user = create_maintainer(project) + + # invalid state + self.client.force_authenticate(user=user) + resp = self.client.patch(self.api_url(patch.id), {'state': 'foobar'}) + self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code) + self.assertContains(resp, 'Expected one of: %s.' % state.name, + status_code=status.HTTP_400_BAD_REQUEST) + + def test_delete(self): + """Ensure deletions are always rejected.""" + project = create_project() + patch = create_patch(project=project) + + # anonymous user + resp = self.client.delete(self.api_url(patch.id)) + self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code) + + # superuser + user = create_maintainer(project) + user.is_superuser = True + user.save() + self.client.force_authenticate(user=user) + resp = self.client.delete(self.api_url(patch.id)) + self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code) |