[PATCH v3 12/16] tests: Standardize validation of REST API JSON
Andy Doan
andy.doan at linaro.org
Tue Nov 29 09:26:36 AEDT 2016
On 11/25/2016 12:18 PM, Stephen Finucane wrote:
> Standardize how the JSON bodies of REST API responses is validated.
>
> Signed-off-by: Stephen Finucane <stephen at that.guru>
nice idea
Reviewed-by: Andy Doan <andy.doan at linaro.org>
> ---
> patchwork/tests/test_rest_api.py | 123 +++++++++++++++++++++++++--------------
> 1 file changed, 78 insertions(+), 45 deletions(-)
>
> diff --git a/patchwork/tests/test_rest_api.py b/patchwork/tests/test_rest_api.py
> index beba55c..618c66c 100644
> --- a/patchwork/tests/test_rest_api.py
> +++ b/patchwork/tests/test_rest_api.py
> @@ -52,6 +52,11 @@ class TestProjectAPI(APITestCase):
> return reverse('api-project-list')
> return reverse('api-project-detail', args=[item])
>
> + def assertSerialized(self, project_obj, project_json):
> + self.assertEqual(project_obj.name, project_json['name'])
> + self.assertEqual(project_obj.linkname, project_json['link_name'])
> + self.assertEqual(project_obj.listid, project_json['list_id'])
> +
> def test_list(self):
> """Validate we can list the default test project."""
> project = create_project()
> @@ -59,10 +64,7 @@ class TestProjectAPI(APITestCase):
> resp = self.client.get(self.api_url())
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> self.assertEqual(1, len(resp.data))
> - proj = resp.data[0]
> - self.assertEqual(project.linkname, proj['link_name'])
> - self.assertEqual(project.name, proj['name'])
> - self.assertEqual(project.listid, proj['list_id'])
> + self.assertSerialized(project, resp.data[0])
>
> def test_detail(self):
> """Validate we can get a specific project."""
> @@ -75,7 +77,7 @@ class TestProjectAPI(APITestCase):
> # make sure we can look up by linkname
> resp = self.client.get(self.api_url(resp.data['link_name']))
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> - self.assertEqual(project.name, resp.data['name'])
> + self.assertSerialized(project, resp.data)
>
> def test_get_numeric_linkname(self):
> """Validate we try to do the right thing for numeric linkname"""
> @@ -83,7 +85,7 @@ class TestProjectAPI(APITestCase):
>
> resp = self.client.get(self.api_url('12345'))
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> - self.assertEqual(project.name, resp.data['name'])
> + self.assertSerialized(project, resp.data)
>
> def test_create(self):
> """Ensure creations are rejected."""
> @@ -150,35 +152,59 @@ class TestPersonAPI(APITestCase):
> return reverse('api-person-list')
> return reverse('api-person-detail', args=[item])
>
> + def assertSerialized(self, person_obj, person_json, has_user=False):
> + if not has_user:
> + self.assertEqual(person_obj.name, person_json['name'])
> + self.assertEqual(person_obj.email, person_json['email'])
> + else:
> + self.assertEqual(person_obj.user.username, person_json['name'])
> + self.assertEqual(person_obj.user.email, person_json['email'])
> + self.assertIn(TestUserAPI.api_url(person_obj.user.id),
> + person_json['user'])
> +
> def test_list(self):
> """This API requires authenticated users."""
> + person = create_person()
> +
> # anonymous user
> resp = self.client.get(self.api_url())
> self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
>
> # authenticated user
> - user = create_user()
> + user = create_user(link_person=False)
> 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))
> - self.assertEqual(user.username, resp.data[0]['name'])
> - self.assertEqual(user.email, resp.data[0]['email'])
> - self.assertIn('users/%d/' % user.id, resp.data[0]['user'])
> + self.assertSerialized(person, resp.data[0])
>
> - def test_unlinked_user(self):
> + def test_detail(self):
> person = create_person()
> - user = create_user()
> +
> + # anonymous user
> + resp = self.client.get(self.api_url(person.id))
> + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
> +
> + # authenticated, unlinked user
> + user = create_user(link_person=False)
> self.client.force_authenticate(user=user)
>
> - resp = self.client.get(self.api_url())
> + resp = self.client.get(self.api_url(person.id))
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> - self.assertEqual(2, len(resp.data))
> - self.assertEqual(person.name, resp.data[0]['name'])
> - self.assertIsNone(resp.data[0]['user'])
> + self.assertSerialized(person, resp.data, has_user=False)
> +
> + # authenticated, linked user
> + user = create_user(link_person=True)
> + person = user.person_set.all().first()
> + self.client.force_authenticate(user=user)
> +
> + resp = self.client.get(self.api_url(person.id))
> + self.assertEqual(status.HTTP_200_OK, resp.status_code)
> + self.assertSerialized(person, resp.data, has_user=True)
>
> def test_create_update_delete(self):
> + """Ensure creates, updates and deletes aren't allowed"""
> user = create_maintainer()
> user.is_superuser = True
> user.save()
> @@ -203,6 +229,11 @@ class TestUserAPI(APITestCase):
> return reverse('api-user-list')
> return reverse('api-user-detail', args=[item])
>
> + def assertSerialized(self, user_obj, user_json):
> + self.assertEqual(user_obj.username, user_json['username'])
> + self.assertNotIn('password', user_json)
> + self.assertNotIn('is_superuser', user_json)
> +
> def test_list(self):
> """This API requires authenticated users."""
> # anonymous users
> @@ -216,9 +247,7 @@ class TestUserAPI(APITestCase):
> resp = self.client.get(self.api_url())
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> self.assertEqual(1, len(resp.data))
> - self.assertEqual(user.username, resp.data[0]['username'])
> - self.assertNotIn('password', resp.data[0])
> - self.assertNotIn('is_superuser', resp.data[0])
> + self.assertSerialized(user, resp.data[0])
>
> def test_update(self):
> """Ensure updates are allowed."""
> @@ -229,6 +258,7 @@ class TestUserAPI(APITestCase):
>
> resp = self.client.patch(self.api_url(user.id), {'first_name': 'Tan'})
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> + self.assertSerialized(user, resp.data)
>
> def test_create_delete(self):
> """Ensure creations and deletions and not allowed."""
> @@ -254,6 +284,16 @@ class TestPatchAPI(APITestCase):
> return reverse('api-patch-list')
> return reverse('api-patch-detail', args=[item])
>
> + def assertSerialized(self, patch_obj, patch_json):
> + self.assertEqual(patch_obj.name, patch_json['name'])
> + self.assertEqual(patch_obj.msgid, patch_json['msgid'])
> + self.assertEqual(patch_obj.state.name, patch_json['state'])
> + self.assertIn(patch_obj.get_mbox_url(), patch_json['mbox'])
> + self.assertIn(TestPersonAPI.api_url(patch_obj.submitter.id),
> + patch_json['submitter'])
> + self.assertIn(TestProjectAPI.api_url(patch_obj.project.id),
> + patch_json['project'])
> +
> def test_list(self):
> """Validate we can list a patch."""
> resp = self.client.get(self.api_url())
> @@ -267,9 +307,9 @@ class TestPatchAPI(APITestCase):
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> self.assertEqual(1, len(resp.data))
> patch_rsp = resp.data[0]
> - self.assertEqual(patch_obj.name, patch_rsp['name'])
> - self.assertNotIn('content', patch_rsp)
> + self.assertSerialized(patch_obj, patch_rsp)
> self.assertNotIn('headers', patch_rsp)
> + self.assertNotIn('content', patch_rsp)
> self.assertNotIn('diff', patch_rsp)
>
> # authenticated user
> @@ -279,31 +319,21 @@ class TestPatchAPI(APITestCase):
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> self.assertEqual(1, len(resp.data))
> patch_rsp = resp.data[0]
> - self.assertEqual(patch_obj.name, patch_rsp['name'])
> + self.assertSerialized(patch_obj, patch_rsp)
>
> def test_detail(self):
> """Validate we can get a specific patch."""
> - patch = create_patch()
> + patch = create_patch(
> + content='Reviewed-by: Test User <test at example.com>\n')
>
> resp = self.client.get(self.api_url(patch.id))
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> - self.assertEqual(patch.name, resp.data['name'])
> - self.assertIn(TestProjectAPI.api_url(patch.project.id),
> - resp.data['project'])
> - self.assertEqual(patch.msgid, resp.data['msgid'])
> + 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.assertIn(TestPersonAPI.api_url(patch.submitter.id),
> - resp.data['submitter'])
> - self.assertEqual(patch.state.name, resp.data['state'])
> - self.assertIn(patch.get_mbox_url(), resp.data['mbox'])
> -
> - def test_detail_tags(self):
> - patch = create_patch(
> - content='Reviewed-by: Test User <test at example.com>\n')
> - resp = self.client.get(self.api_url(patch.id))
> - tags = resp.data['tags']
> - self.assertEqual(3, len(tags))
> - self.assertEqual(1, tags['Reviewed-by'])
> + self.assertEqual(3, len(resp.data['tags']))
> + self.assertEqual(1, resp.data['tags']['Reviewed-by'])
>
> def test_create(self):
> """Ensure creations are rejected."""
> @@ -392,6 +422,12 @@ class TestCheckAPI(APITestCase):
> }
> return create_check(**values)
>
> + def assertSerialized(self, check_obj, check_json):
> + self.assertEqual(check_obj.get_state_display(), check_json['state'])
> + self.assertEqual(check_obj.target_url, check_json['target_url'])
> + self.assertEqual(check_obj.context, check_json['context'])
> + self.assertEqual(check_obj.description, check_json['description'])
> +
> def test_list(self):
> """Validate we can list checks on a patch."""
> resp = self.client.get(self.api_url())
> @@ -403,18 +439,14 @@ class TestCheckAPI(APITestCase):
> resp = self.client.get(self.api_url())
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> self.assertEqual(1, len(resp.data))
> - check_rsp = resp.data[0]
> - self.assertEqual(check_obj.get_state_display(), check_rsp['state'])
> - self.assertEqual(check_obj.target_url, check_rsp['target_url'])
> - self.assertEqual(check_obj.context, check_rsp['context'])
> - self.assertEqual(check_obj.description, check_rsp['description'])
> + self.assertSerialized(check_obj, resp.data[0])
>
> def test_detail(self):
> """Validate we can get a specific check."""
> check = self._create_check()
> resp = self.client.get(self.api_url(check))
> self.assertEqual(status.HTTP_200_OK, resp.status_code)
> - self.assertEqual(check.target_url, resp.data['target_url'])
> + self.assertSerialized(check, resp.data)
>
> def test_create(self):
> """Ensure creations can be performed by user of patch."""
> @@ -429,6 +461,7 @@ class TestCheckAPI(APITestCase):
> resp = self.client.post(self.api_url(), check)
> self.assertEqual(status.HTTP_201_CREATED, resp.status_code)
> self.assertEqual(1, Check.objects.all().count())
> + self.assertSerialized(Check.objects.first(), resp.data)
>
> user = create_user()
> self.client.force_authenticate(user=user)
>
More information about the Patchwork
mailing list