[PATCH v3 12/16] tests: Standardize validation of REST API JSON

Stephen Finucane stephen at that.guru
Sat Nov 26 05:18:31 AEDT 2016


Standardize how the JSON bodies of REST API responses is validated.

Signed-off-by: Stephen Finucane <stephen at that.guru>
---
 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)
-- 
2.7.4



More information about the Patchwork mailing list