diff --git a/.gitignore b/.gitignore index fb5e0a6..96bac63 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ db.sqlite3 *.pyc *.egg-info dist -script \ No newline at end of file +script +.idea/* +*/.idea/* +*.DS_STORE diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ecca835..9d128f9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,22 @@ --- +image: python:3.6 + stages: + - test - release include: - project: 'infra/platform' ref: master file: '/templates/python.ci.yml' + +test: + stage: test + script: + - pip install .[dev] + - python -m unittest djangoldp_notification.tests.runner + except: + - master + - tags + tags: + - test diff --git a/djangoldp_notification/tests/__init__.py b/djangoldp_notification/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/djangoldp_notification/tests/conftest.py b/djangoldp_notification/tests/conftest.py deleted file mode 100644 index b1beb8b..0000000 --- a/djangoldp_notification/tests/conftest.py +++ /dev/null @@ -1,15 +0,0 @@ -from importlib import import_module -from os import environ - -from pytest import fail - -settings_module = environ.get("DJANGO_SETTINGS_MODULE") -if settings_module is None or len(settings_module) == 0: - fail("DJANGO_SETTINGS_MODULE needs to be defined and point to your SIB app installation settings") - -try: - import_module(settings_module) -except ImportError: - initial_module = [token for token in settings_module.split(".") if len(token) > 0][0] - fail("Unable to import {}. Try to configure PYTHONPATH to point the " - "directory containing the {} module".format(settings_module, initial_module)) diff --git a/djangoldp_notification/tests/runner.py b/djangoldp_notification/tests/runner.py new file mode 100644 index 0000000..29f3947 --- /dev/null +++ b/djangoldp_notification/tests/runner.py @@ -0,0 +1,49 @@ +import sys +import yaml + +import django +from django.conf import settings as django_settings +from djangoldp.conf.ldpsettings import LDPSettings +from djangoldp.tests.settings_default import yaml_config + +# override config loading +config = { + # add the packages to the reference list + 'ldppackages': ['djangoldp_account', 'djangoldp_notification', 'djangoldp_notification.tests'], + + # required values for server + 'server': { + 'AUTH_USER_MODEL': 'djangoldp_account.LDPUser', + 'REST_FRAMEWORK': { + 'DEFAULT_PAGINATION_CLASS': 'djangoldp.pagination.LDPPagination', + 'PAGE_SIZE': 5 + }, + # map the config of the core settings (avoid asserts to fail) + 'SITE_URL': 'http://happy-dev.fr', + 'BASE_URL': 'http://happy-dev.fr', + 'SEND_BACKLINKS': False, + 'JABBER_DEFAULT_HOST': None, + 'PERMISSIONS_CACHE': False, + 'ANONYMOUS_USER_NAME': None, + 'SERIALIZER_CACHE': True, + 'USER_NESTED_FIELDS': ['inbox', 'settings'], + 'USER_EMPTY_CONTAINERS': ['inbox'], + 'EMAIL_BACKEND': 'django.core.mail.backends.console.EmailBackend' + } +} +ldpsettings = LDPSettings(config) +ldpsettings.config = yaml.safe_load(yaml_config) + +django_settings.configure(ldpsettings) + +django.setup() +from django.test.runner import DiscoverRunner + +test_runner = DiscoverRunner(verbosity=1) + +failures = test_runner.run_tests([ + 'djangoldp_notification.tests.test_models', + 'djangoldp_notification.tests.test_cache', +]) +if failures: + sys.exit(failures) diff --git a/djangoldp_notification/tests/test_cache.py b/djangoldp_notification/tests/test_cache.py new file mode 100644 index 0000000..dafc1bc --- /dev/null +++ b/djangoldp_notification/tests/test_cache.py @@ -0,0 +1,57 @@ +import uuid +import json +from rest_framework.test import APITestCase, APIClient + +from djangoldp.serializers import LDListMixin, LDPSerializer +from djangoldp_account.models import LDPUser +from djangoldp_notification.models import Notification + + +class TestSubscription(APITestCase): + def _get_random_user(self): + return LDPUser.objects.create(email='{}@test.co.uk'.format(str(uuid.uuid4())), first_name='Test', + last_name='Test', username=str(uuid.uuid4())) + + def _get_random_notification(self, recipient, author): + return Notification.objects.create(user=recipient, author=author.urlid, object=author.urlid, + unread=True) + + def setUpLoggedInUser(self): + self.user = self._get_random_user() + self.client.force_authenticate(user=self.user) + + def setUp(self): + self.client = APIClient() + LDListMixin.to_representation_cache.reset() + LDPSerializer.to_representation_cache.reset() + + def test_indirect_cache(self): + self.setUpLoggedInUser() + author_user = self._get_random_user() + notification = self._get_random_notification(recipient=self.user, author=author_user) + self.assertEqual(notification.unread, True) + + # GET the inbox - should set the cache + response = self.client.get("/users/{}/inbox/".format(self.user.username)) + self.assertEqual(response.status_code, 200) + notif_serialized = response.data["ldp:contains"][0] + self.assertEqual(notif_serialized["unread"], True) + + # PATCH the notification - should wipe the cache + patch = { + "unread": False, + "@context": { + "@vocab":"http://happy-dev.fr/owl/#", + "unread": "http://happy-dev.fr/owl/#unread" + } + } + response = self.client.patch("/notifications/{}/".format(notification.pk), data=json.dumps(patch), + content_type="application/ld+json") + notif_obj = Notification.objects.get(pk=notification.pk) + self.assertEqual(notif_obj.unread, False) + + # GET the inbox - should now be read + response = self.client.get("/users/{}/inbox/".format(self.user.username)) + self.assertEqual(response.status_code, 200) + notif_serialized = response.data["ldp:contains"][0] + self.assertEqual(notif_serialized["unread"], False) diff --git a/djangoldp_notification/tests/test_models.py b/djangoldp_notification/tests/test_models.py index 3ae6f09..6bfaf7b 100644 --- a/djangoldp_notification/tests/test_models.py +++ b/djangoldp_notification/tests/test_models.py @@ -1,47 +1,48 @@ -from collections import OrderedDict - -from djangoldp.factories import UserFactory -from test_plus import APITestCase +import uuid +from rest_framework.test import APITestCase, APIClient +from djangoldp.serializers import LDListMixin, LDPSerializer +from djangoldp_account.models import LDPUser from djangoldp_notification.models import Subscription class TestSubscription(APITestCase): - user1 = None - user2 = None - circle_user1_url = "http://localhost:8000/circles/1" - circle_user2_url = "http://localhost:8000/circles/2" + circle_user1_url = "http://localhost:8000/circles/1/" + circle_user2_url = "http://localhost:8000/circles/2/" + + def _get_random_user(self): + return LDPUser.objects.create(email='{}@test.co.uk'.format(str(uuid.uuid4())), first_name='Test', + last_name='Test', username=str(uuid.uuid4())) + + def _auth_as_user(self, user): + self.client.force_authenticate(user=user) + + def setUpLoggedInUser(self): + self.user = self._get_random_user() + self._auth_as_user(self.user) def setUp(self): - self.user1 = UserFactory(username="karl_marx", password="password") + self.client = APIClient() + LDListMixin.to_representation_cache.reset() + LDPSerializer.to_representation_cache.reset() + + self.user1 = self._get_random_user() Subscription.objects.create(object=self.circle_user1_url, inbox="http://testserver/users/karl_marx/inbox/") - self.user2 = UserFactory(username="piotr_kropotkine", password="password") + self.user2 = self._get_random_user() Subscription.objects.create(object=self.circle_user2_url, inbox="http://testserver/users/piotr_kropotkine/inbox/") def test_not_logged_fails(self): - response = self.get("/subscriptions/") - self.assert_http_403_forbidden(response) - self.assertEqual(response.data.get("detail"), "Authentication credentials were not provided.") + response = self.client.get("/subscriptions/") + self.assertEqual(response.status_code, 403) def test_logged_in_succeeds(self): - with self.login(self.user1): - result = self.get("/subscriptions/").data.get("ldp:contains") - expected = [OrderedDict({ - "@id": "http://localhost:8000/subscriptions/1/", - "object": self.circle_user1_url, - "inbox": "http://testserver/users/karl_marx/inbox/", - "permissions": [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'delete'}}] - })] - self.assertSequenceEqual(result, expected) - - with self.login(self.user2): - result = self.get("/subscriptions/").data.get("ldp:contains") - expected = [OrderedDict({ - "@id": "http://localhost:8000/subscriptions/2/", - "object": self.circle_user2_url, - "inbox": "http://testserver/users/piotr_kropotkine/inbox/", - "permissions": [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'delete'}}] - })] - self.assertSequenceEqual(result, expected) + self._auth_as_user(self.user2) + response = self.client.get("/subscriptions/").data.get("ldp:contains") + self.assertEqual(len(response), 2) + response = response[1] + self.assertEqual(response["object"], self.circle_user2_url) + self.assertEqual(response["inbox"], "http://testserver/users/piotr_kropotkine/inbox/") + self.assertIn({'mode': {'@type': 'view'}}, response["permissions"]) + self.assertIn({'mode': {'@type': 'delete'}}, response["permissions"]) diff --git a/setup.cfg b/setup.cfg index ac5dc54..9fc1c0f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,14 +11,12 @@ license = MIT packages = find: install_requires = djangoldp~=2.0.0 + djangoldp_account~=2.0 [options.extras_require] include_package_data = True dev = factory_boy>=2.12.0 - pytest==5.1.1 - pytest-django==3.7.0 - django-test-plus==1.4.0 [semantic_release] version_source = tag