mirror of
https://github.com/sissbruecker/linkding
synced 2024-11-10 06:04:15 +00:00
Implement bookmark API tests
This commit is contained in:
parent
5644dae14e
commit
8c161ba119
4 changed files with 212 additions and 35 deletions
64
bookmarks/tests/helpers.py
Normal file
64
bookmarks/tests/helpers.py
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.utils.crypto import get_random_string
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
|
from bookmarks.models import Bookmark, Tag
|
||||||
|
|
||||||
|
|
||||||
|
class BookmarkFactoryMixin:
|
||||||
|
user = None
|
||||||
|
|
||||||
|
def get_or_create_test_user(self):
|
||||||
|
if self.user is None:
|
||||||
|
self.user = User.objects.create_user('testuser', 'test@example.com', 'password123')
|
||||||
|
|
||||||
|
return self.user
|
||||||
|
|
||||||
|
def setup_bookmark(self, is_archived: bool = False, tags: [Tag] = [], user: User = None):
|
||||||
|
if user is None:
|
||||||
|
user = self.get_or_create_test_user()
|
||||||
|
unique_id = get_random_string(length=32)
|
||||||
|
bookmark = Bookmark(
|
||||||
|
url='https://example.com/' + unique_id,
|
||||||
|
date_added=timezone.now(),
|
||||||
|
date_modified=timezone.now(),
|
||||||
|
owner=user,
|
||||||
|
is_archived=is_archived
|
||||||
|
)
|
||||||
|
bookmark.save()
|
||||||
|
for tag in tags:
|
||||||
|
bookmark.tags.add(tag)
|
||||||
|
bookmark.save()
|
||||||
|
return bookmark
|
||||||
|
|
||||||
|
def setup_tag(self, user: User = None):
|
||||||
|
if user is None:
|
||||||
|
user = self.get_or_create_test_user()
|
||||||
|
name = get_random_string(length=32)
|
||||||
|
tag = Tag(name=name, date_added=timezone.now(), owner=user)
|
||||||
|
tag.save()
|
||||||
|
return tag
|
||||||
|
|
||||||
|
|
||||||
|
class LinkdingApiTestCase(APITestCase):
|
||||||
|
def get(self, url, expected_status_code=status.HTTP_200_OK):
|
||||||
|
response = self.client.get(url)
|
||||||
|
self.assertEqual(response.status_code, expected_status_code)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def post(self, url, data=None, expected_status_code=status.HTTP_200_OK):
|
||||||
|
response = self.client.post(url, data, format='json')
|
||||||
|
self.assertEqual(response.status_code, expected_status_code)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def put(self, url, data=None, expected_status_code=status.HTTP_200_OK):
|
||||||
|
response = self.client.put(url, data, format='json')
|
||||||
|
self.assertEqual(response.status_code, expected_status_code)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def delete(self, url, expected_status_code=status.HTTP_200_OK):
|
||||||
|
response = self.client.delete(url)
|
||||||
|
self.assertEqual(response.status_code, expected_status_code)
|
||||||
|
return response
|
138
bookmarks/tests/test_bookmarks_api.py
Normal file
138
bookmarks/tests/test_bookmarks_api.py
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
|
||||||
|
from bookmarks.models import Bookmark
|
||||||
|
from bookmarks.tests.helpers import LinkdingApiTestCase, BookmarkFactoryMixin
|
||||||
|
|
||||||
|
|
||||||
|
class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.api_token = Token.objects.get_or_create(user=self.get_or_create_test_user())[0]
|
||||||
|
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.api_token.key)
|
||||||
|
self.tag1 = self.setup_tag()
|
||||||
|
self.tag2 = self.setup_tag()
|
||||||
|
self.bookmark1 = self.setup_bookmark(tags=[self.tag1, self.tag2])
|
||||||
|
self.bookmark2 = self.setup_bookmark()
|
||||||
|
self.bookmark3 = self.setup_bookmark(tags=[self.tag2])
|
||||||
|
self.archived_bookmark1 = self.setup_bookmark(is_archived=True, tags=[self.tag1, self.tag2])
|
||||||
|
self.archived_bookmark2 = self.setup_bookmark(is_archived=True)
|
||||||
|
|
||||||
|
def assertBookmarkListEqual(self, data_list, bookmarks):
|
||||||
|
expectations = []
|
||||||
|
for bookmark in bookmarks:
|
||||||
|
tag_names = [tag.name for tag in bookmark.tags.all()]
|
||||||
|
tag_names.sort(key=str.lower)
|
||||||
|
expectation = OrderedDict()
|
||||||
|
expectation['id'] = bookmark.id
|
||||||
|
expectation['url'] = bookmark.url
|
||||||
|
expectation['title'] = bookmark.title
|
||||||
|
expectation['description'] = bookmark.description
|
||||||
|
expectation['website_title'] = bookmark.website_title
|
||||||
|
expectation['website_description'] = bookmark.website_description
|
||||||
|
expectation['tag_names'] = tag_names
|
||||||
|
expectation['date_added'] = bookmark.date_added.isoformat().replace('+00:00', 'Z')
|
||||||
|
expectation['date_modified'] = bookmark.date_modified.isoformat().replace('+00:00', 'Z')
|
||||||
|
expectations.append(expectation)
|
||||||
|
|
||||||
|
for data in data_list:
|
||||||
|
data['tag_names'].sort(key=str.lower)
|
||||||
|
|
||||||
|
self.assertCountEqual(data_list, expectations)
|
||||||
|
|
||||||
|
def test_create_bookmark(self):
|
||||||
|
data = {
|
||||||
|
'url': 'https://example.com/',
|
||||||
|
'title': 'Test title',
|
||||||
|
'description': 'Test description',
|
||||||
|
'tag_names': ['tag1', 'tag2']
|
||||||
|
}
|
||||||
|
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||||
|
bookmark = Bookmark.objects.get(url=data['url'])
|
||||||
|
self.assertEqual(bookmark.url, data['url'])
|
||||||
|
self.assertEqual(bookmark.title, data['title'])
|
||||||
|
self.assertEqual(bookmark.description, data['description'])
|
||||||
|
self.assertEqual(bookmark.tags.count(), 2)
|
||||||
|
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][0]).count(), 1)
|
||||||
|
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][1]).count(), 1)
|
||||||
|
|
||||||
|
def test_create_bookmark_minimal_payload(self):
|
||||||
|
data = {'url': 'https://example.com/'}
|
||||||
|
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
def test_list_bookmarks(self):
|
||||||
|
response = self.get(reverse('bookmarks:bookmark-list'), expected_status_code=status.HTTP_200_OK)
|
||||||
|
self.assertBookmarkListEqual(response.data['results'], [self.bookmark1, self.bookmark2, self.bookmark3])
|
||||||
|
|
||||||
|
def test_list_bookmarks_should_filter_by_query(self):
|
||||||
|
response = self.get(reverse('bookmarks:bookmark-list') + '?q=#' + self.tag1.name, expected_status_code=status.HTTP_200_OK)
|
||||||
|
self.assertBookmarkListEqual(response.data['results'], [self.bookmark1])
|
||||||
|
|
||||||
|
def test_list_archived_bookmarks_does_not_return_unarchived_bookmarks(self):
|
||||||
|
response = self.get(reverse('bookmarks:bookmark-archived'), expected_status_code=status.HTTP_200_OK)
|
||||||
|
self.assertBookmarkListEqual(response.data['results'], [self.archived_bookmark1, self.archived_bookmark2])
|
||||||
|
|
||||||
|
def test_list_archived_bookmarks_should_filter_by_query(self):
|
||||||
|
response = self.get(reverse('bookmarks:bookmark-archived') + '?q=#' + self.tag1.name, expected_status_code=status.HTTP_200_OK)
|
||||||
|
self.assertBookmarkListEqual(response.data['results'], [self.archived_bookmark1])
|
||||||
|
|
||||||
|
def test_get_bookmark(self):
|
||||||
|
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||||
|
response = self.get(url, expected_status_code=status.HTTP_200_OK)
|
||||||
|
self.assertBookmarkListEqual([response.data], [self.bookmark1])
|
||||||
|
|
||||||
|
def test_update_bookmark(self):
|
||||||
|
data = {'url': 'https://example.com/'}
|
||||||
|
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||||
|
self.put(url, data, expected_status_code=status.HTTP_200_OK)
|
||||||
|
updated_bookmark = Bookmark.objects.get(id=self.bookmark1.id)
|
||||||
|
self.assertEqual(updated_bookmark.url, data['url'])
|
||||||
|
|
||||||
|
def test_delete_bookmark(self):
|
||||||
|
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||||
|
self.delete(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
self.assertEqual(len(Bookmark.objects.filter(id=self.bookmark1.id)), 0)
|
||||||
|
|
||||||
|
def test_archive(self):
|
||||||
|
url = reverse('bookmarks:bookmark-archive', args=[self.bookmark1.id])
|
||||||
|
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
bookmark = Bookmark.objects.get(id=self.bookmark1.id)
|
||||||
|
self.assertTrue(bookmark.is_archived)
|
||||||
|
|
||||||
|
def test_unarchive(self):
|
||||||
|
url = reverse('bookmarks:bookmark-unarchive', args=[self.archived_bookmark1.id])
|
||||||
|
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
bookmark = Bookmark.objects.get(id=self.archived_bookmark1.id)
|
||||||
|
self.assertFalse(bookmark.is_archived)
|
||||||
|
|
||||||
|
def test_can_only_access_own_bookmarks(self):
|
||||||
|
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
|
||||||
|
inaccessible_bookmark = self.setup_bookmark(user=other_user)
|
||||||
|
self.setup_bookmark(user=other_user, is_archived=True)
|
||||||
|
|
||||||
|
url = reverse('bookmarks:bookmark-list')
|
||||||
|
response = self.get(url, expected_status_code=status.HTTP_200_OK)
|
||||||
|
self.assertEqual(len(response.data['results']), 3)
|
||||||
|
|
||||||
|
url = reverse('bookmarks:bookmark-archived')
|
||||||
|
response = self.get(url, expected_status_code=status.HTTP_200_OK)
|
||||||
|
self.assertEqual(len(response.data['results']), 2)
|
||||||
|
|
||||||
|
url = reverse('bookmarks:bookmark-detail', args=[inaccessible_bookmark.id])
|
||||||
|
self.get(url, expected_status_code=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
url = reverse('bookmarks:bookmark-detail', args=[inaccessible_bookmark.id])
|
||||||
|
self.put(url, {url: 'https://example.com/'}, expected_status_code=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
url = reverse('bookmarks:bookmark-detail', args=[inaccessible_bookmark.id])
|
||||||
|
self.delete(url, expected_status_code=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
url = reverse('bookmarks:bookmark-archive', args=[inaccessible_bookmark.id])
|
||||||
|
self.post(url, expected_status_code=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
url = reverse('bookmarks:bookmark-unarchive', args=[inaccessible_bookmark.id])
|
||||||
|
self.post(url, expected_status_code=status.HTTP_404_NOT_FOUND)
|
|
@ -1,38 +1,13 @@
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.crypto import get_random_string
|
|
||||||
from bookmarks.models import Bookmark, Tag
|
|
||||||
from bookmarks import queries
|
from bookmarks import queries
|
||||||
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class QueriesTestCase(TestCase):
|
class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
self.user = User.objects.create_user('testuser', 'test@example.com', 'password123')
|
|
||||||
|
|
||||||
def setup_bookmark(self, is_archived: bool = False, tags: [Tag] = []):
|
|
||||||
unique_id = get_random_string(length=32)
|
|
||||||
bookmark = Bookmark(
|
|
||||||
url='https://example.com/' + unique_id,
|
|
||||||
date_added=timezone.now(),
|
|
||||||
date_modified=timezone.now(),
|
|
||||||
owner=self.user,
|
|
||||||
is_archived=is_archived
|
|
||||||
)
|
|
||||||
bookmark.save()
|
|
||||||
for tag in tags:
|
|
||||||
bookmark.tags.add(tag)
|
|
||||||
bookmark.save()
|
|
||||||
return bookmark
|
|
||||||
|
|
||||||
def setup_tag(self):
|
|
||||||
name = get_random_string(length=32)
|
|
||||||
tag = Tag(name=name, date_added=timezone.now(), owner=self.user)
|
|
||||||
tag.save()
|
|
||||||
return tag
|
|
||||||
|
|
||||||
def test_query_bookmarks_should_not_return_archived_bookmarks(self):
|
def test_query_bookmarks_should_not_return_archived_bookmarks(self):
|
||||||
bookmark1 = self.setup_bookmark()
|
bookmark1 = self.setup_bookmark()
|
||||||
|
@ -41,7 +16,7 @@ class QueriesTestCase(TestCase):
|
||||||
self.setup_bookmark(is_archived=True)
|
self.setup_bookmark(is_archived=True)
|
||||||
self.setup_bookmark(is_archived=True)
|
self.setup_bookmark(is_archived=True)
|
||||||
|
|
||||||
query = queries.query_bookmarks(self.user, '')
|
query = queries.query_bookmarks(self.get_or_create_test_user(), '')
|
||||||
|
|
||||||
self.assertCountEqual([bookmark1, bookmark2], list(query))
|
self.assertCountEqual([bookmark1, bookmark2], list(query))
|
||||||
|
|
||||||
|
@ -52,7 +27,7 @@ class QueriesTestCase(TestCase):
|
||||||
self.setup_bookmark()
|
self.setup_bookmark()
|
||||||
self.setup_bookmark()
|
self.setup_bookmark()
|
||||||
|
|
||||||
query = queries.query_archived_bookmarks(self.user, '')
|
query = queries.query_archived_bookmarks(self.get_or_create_test_user(), '')
|
||||||
|
|
||||||
self.assertCountEqual([bookmark1, bookmark2], list(query))
|
self.assertCountEqual([bookmark1, bookmark2], list(query))
|
||||||
|
|
||||||
|
@ -63,7 +38,7 @@ class QueriesTestCase(TestCase):
|
||||||
self.setup_bookmark()
|
self.setup_bookmark()
|
||||||
self.setup_bookmark(is_archived=True, tags=[tag2])
|
self.setup_bookmark(is_archived=True, tags=[tag2])
|
||||||
|
|
||||||
query = queries.query_bookmark_tags(self.user, '')
|
query = queries.query_bookmark_tags(self.get_or_create_test_user(), '')
|
||||||
|
|
||||||
self.assertCountEqual([tag1], list(query))
|
self.assertCountEqual([tag1], list(query))
|
||||||
|
|
||||||
|
@ -73,7 +48,7 @@ class QueriesTestCase(TestCase):
|
||||||
self.setup_bookmark(tags=[tag])
|
self.setup_bookmark(tags=[tag])
|
||||||
self.setup_bookmark(tags=[tag])
|
self.setup_bookmark(tags=[tag])
|
||||||
|
|
||||||
query = queries.query_bookmark_tags(self.user, '')
|
query = queries.query_bookmark_tags(self.get_or_create_test_user(), '')
|
||||||
|
|
||||||
self.assertCountEqual([tag], list(query))
|
self.assertCountEqual([tag], list(query))
|
||||||
|
|
||||||
|
@ -84,7 +59,7 @@ class QueriesTestCase(TestCase):
|
||||||
self.setup_bookmark()
|
self.setup_bookmark()
|
||||||
self.setup_bookmark(is_archived=True, tags=[tag2])
|
self.setup_bookmark(is_archived=True, tags=[tag2])
|
||||||
|
|
||||||
query = queries.query_archived_bookmark_tags(self.user, '')
|
query = queries.query_archived_bookmark_tags(self.get_or_create_test_user(), '')
|
||||||
|
|
||||||
self.assertCountEqual([tag2], list(query))
|
self.assertCountEqual([tag2], list(query))
|
||||||
|
|
||||||
|
@ -94,6 +69,6 @@ class QueriesTestCase(TestCase):
|
||||||
self.setup_bookmark(is_archived=True, tags=[tag])
|
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||||
self.setup_bookmark(is_archived=True, tags=[tag])
|
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||||
|
|
||||||
query = queries.query_archived_bookmark_tags(self.user, '')
|
query = queries.query_archived_bookmark_tags(self.get_or_create_test_user(), '')
|
||||||
|
|
||||||
self.assertCountEqual([tag], list(query))
|
self.assertCountEqual([tag], list(query))
|
||||||
|
|
|
@ -41,7 +41,7 @@ INSTALLED_APPS = [
|
||||||
'widget_tweaks',
|
'widget_tweaks',
|
||||||
'django_generate_secret_key',
|
'django_generate_secret_key',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework.authtoken'
|
'rest_framework.authtoken',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
Loading…
Reference in a new issue