[v2,3/6] tests: Add events API tests

Message ID 20180409210256.19649-4-stephen@that.guru
State New
Headers show
Series
  • Add 'Event.payload' field
Related show

Commit Message

Stephen Finucane April 9, 2018, 9:02 p.m.
This will make sure we don't regress in upcoming changes.

Signed-off-by: Stephen Finucane <stephen@that.guru>
---
 patchwork/tests/api/test_event.py | 173 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 patchwork/tests/api/test_event.py

Patch

diff --git a/patchwork/tests/api/test_event.py b/patchwork/tests/api/test_event.py
new file mode 100644
index 00000000..ffc2489a
--- /dev/null
+++ b/patchwork/tests/api/test_event.py
@@ -0,0 +1,173 @@ 
+# Patchwork - automated patch tracking system
+# Copyright (C) 2018 Stephen Finucane <stephen@that.guru>
+#
+# 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
+
+import unittest
+
+from django.conf import settings
+
+from patchwork.compat import reverse
+from patchwork.models import Event
+from patchwork.tests.utils import create_cover
+from patchwork.tests.utils import create_maintainer
+from patchwork.tests.utils import create_patch
+from patchwork.tests.utils import create_series_patch
+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 TestEventAPI(APITestCase):
+    fixtures = ['default_tags']
+    _category_payload_fields = {
+        Event.CATEGORY_COVER_CREATED: ['cover'],
+        Event.CATEGORY_PATCH_CREATED: ['patch'],
+        Event.CATEGORY_PATCH_COMPLETED: ['patch', 'series'],
+        Event.CATEGORY_PATCH_STATE_CHANGED: ['patch', 'previous_state',
+                                             'current_state'],
+        Event.CATEGORY_PATCH_DELEGATED: ['patch', 'previous_delegate',
+                                         'current_delegate'],
+        Event.CATEGORY_CHECK_CREATED: ['patch', 'check'],
+        Event.CATEGORY_SERIES_CREATED: ['series'],
+        Event.CATEGORY_SERIES_COMPLETED: ['series'],
+    }
+
+    @staticmethod
+    def api_url():
+        return reverse('api-event-list')
+
+    def assertSerialized(self, event_objs, event_jsons, categories):
+        # NOTE(stephenfin): This assertSerialized is a little different due to
+        # the need to validate multiple events in some situation
+        self.assertTrue(len(event_objs) == len(event_jsons) == len(categories))
+
+        for event_obj, event_json, category in zip(
+                event_objs, event_jsons, categories):
+            self.assertEqual(event_obj.id, event_json['id'])
+            self.assertEqual(event_obj.category, category)
+            self.assertEqual(event_obj.category, event_json['category'])
+
+            # nested fields
+
+            self.assertEqual(event_obj.project.id,
+                             event_json['project']['id'])
+
+            payload_fields = self._category_payload_fields[category]
+            self.assertEqual(len(event_json['payload']), len(payload_fields))
+            self.assertEqual(set(event_json['payload']), set(payload_fields))
+
+    def test_list(self):
+        """Validate we can list bundles."""
+        resp = self.client.get(self.api_url())
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(0, len(resp.data))
+
+        # cover_created event
+        cover = create_cover()
+
+        resp = self.client.get(self.api_url())
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(1, len(resp.data))
+        self.assertSerialized(Event.objects.filter(cover=cover.id), resp.data,
+                              [Event.CATEGORY_COVER_CREATED])
+
+        resp = self.client.get(self.api_url(), {'cover': cover.id})
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(1, len(resp.data))
+        self.assertSerialized(Event.objects.filter(cover=cover.id), resp.data,
+                              [Event.CATEGORY_COVER_CREATED])
+
+        # patch_created, patch_state_changed, patch_delegated
+        patch = create_patch()
+
+        resp = self.client.get(self.api_url(), {'patch': patch.id})
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(1, len(resp.data))
+        self.assertSerialized(Event.objects.filter(patch=patch.id), resp.data,
+                              [Event.CATEGORY_PATCH_CREATED])
+
+        user = create_user()
+        patch.delegate = user
+        patch.save()
+
+        resp = self.client.get(self.api_url(), {'patch': patch.id})
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(2, len(resp.data))
+        self.assertSerialized(Event.objects.filter(patch=patch.id), resp.data,
+                              [Event.CATEGORY_PATCH_DELEGATED,
+                               Event.CATEGORY_PATCH_CREATED])
+
+        state = create_state()
+        patch.state = state
+        patch.save()
+
+        resp = self.client.get(self.api_url(), {'patch': patch.id})
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(3, len(resp.data))
+        self.assertSerialized(Event.objects.filter(patch=patch.id), resp.data,
+                              [Event.CATEGORY_PATCH_STATE_CHANGED,
+                               Event.CATEGORY_PATCH_DELEGATED,
+                               Event.CATEGORY_PATCH_CREATED])
+
+        # patch_completed, series_created, series_completed
+        patch = create_series_patch()
+
+        resp = self.client.get(self.api_url(), {'patch': patch.patch.id})
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(2, len(resp.data))
+        self.assertSerialized(Event.objects.filter(patch=patch.patch.id),
+                              resp.data,
+                              [Event.CATEGORY_PATCH_COMPLETED,
+                               Event.CATEGORY_PATCH_CREATED])
+
+        resp = self.client.get(self.api_url(), {'series': patch.series.id})
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(3, len(resp.data))
+        # TODO(stephenfin): The creation of the series- and patch-completed
+        # events could be racey.
+        self.assertSerialized(Event.objects.filter(series=patch.series.id),
+                              resp.data,
+                              [Event.CATEGORY_SERIES_COMPLETED,
+                               Event.CATEGORY_PATCH_COMPLETED,
+                               Event.CATEGORY_SERIES_CREATED])
+
+        # test filtering by invalid project
+        resp = self.client.get(self.api_url(), {'project': 'invalidproject'})
+        self.assertEqual(0, len(resp.data))
+
+    def test_create(self):
+        """Ensure creates aren't allowed.
+
+        There is no detail endpoint so updates and deletes aren't possible.
+        """
+        user = create_maintainer()
+        user.is_superuser = True
+        user.save()
+        self.client.force_authenticate(user=user)
+
+        resp = self.client.post(self.api_url(), {'category': 'cover-created'})
+        self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code)