-
Notifications
You must be signed in to change notification settings - Fork 91
[Issue #441] Add maintainer notes to patches #586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
andrepapoti
wants to merge
9
commits into
getpatchwork:main
Choose a base branch
from
profusion:i441
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
caf054a
models: Add Note model
andrepapoti cb13754
migrations: add migration for Note
andrepapoti a9541d6
api: Add Note view and serializer
andrepapoti df9ce0e
api: Add Note to Patch Serializer
andrepapoti 13f5fd5
urls: add endpoints for Notes
andrepapoti a87fd13
tests: Add tests for Note related endpoints
andrepapoti cafc714
admin: Add Note admin
andrepapoti 58ea0eb
views: Add notes to patch-detail view
andrepapoti ded8739
release-notes: Add release notes for the patch note feature
andrepapoti File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
tests: Add tests for Note related endpoints
Signed-off-by: andrepapoti <andrepapoti@gmail.com>
- Loading branch information
commit a87fd136d7cd92beba3c2f6caf8737b1a9118a37
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,332 @@ | ||
| # Patchwork - automated patch tracking system | ||
| # Copyright (C) 2024 Collabora | ||
| # | ||
| # SPDX-License-Identifier: GPL-2.0-or-later | ||
|
|
||
| from django.test import override_settings | ||
| from django.urls import reverse | ||
| from rest_framework import status | ||
|
|
||
| from patchwork.models import Note | ||
| from patchwork.tests.api import utils | ||
| from patchwork.tests.utils import create_patch | ||
| from patchwork.tests.utils import create_maintainer | ||
| from patchwork.tests.utils import create_person | ||
| from patchwork.tests.utils import create_project | ||
| from patchwork.tests.utils import create_note | ||
| from patchwork.tests.utils import create_user | ||
| from patchwork.tests.utils import create_superuser | ||
|
|
||
|
|
||
| @override_settings(ENABLE_REST_API=True) | ||
| class TestPatchNotes(utils.APITestCase): | ||
| def setUp(self): | ||
| super().setUp() | ||
| self.project = create_project() | ||
| self.superuser = create_superuser() | ||
| self.user = create_maintainer(self.project) | ||
| self.patch = create_patch(project=self.project) | ||
|
|
||
| def check_for_expected(self, instance, response_data): | ||
| self.assertEqual(instance.id, response_data['id']) | ||
| self.assertEqual(instance.patch.id, response_data['patch']['id']) | ||
| self.assertEqual( | ||
| instance.submitter.id, response_data['submitter']['id'] | ||
| ) | ||
|
|
||
| def test_create_note(self): | ||
| start_num = Note.objects.count() | ||
| url = reverse( | ||
| 'api-patch-note-list', kwargs={'patch_id': self.patch.id} | ||
| ) | ||
| data = {'content': 'New note'} | ||
| self.client.authenticate(user=self.user) | ||
| resp = self.client.post(url, data=data) | ||
| end_num = Note.objects.count() | ||
|
|
||
| self.assertEqual(status.HTTP_201_CREATED, resp.status_code) | ||
| self.assertEqual(start_num + 1, end_num) | ||
|
|
||
| def test_create_public_note(self): | ||
| start_num = Note.objects.count() | ||
| url = reverse( | ||
| 'api-patch-note-list', kwargs={'patch_id': self.patch.id} | ||
| ) | ||
| data = { | ||
| 'content': 'New note', | ||
| 'maintainer_only': False, | ||
| } | ||
| self.client.authenticate(user=self.user) | ||
| resp = self.client.post(url, data=data) | ||
| end_num = Note.objects.count() | ||
|
|
||
| self.assertEqual(status.HTTP_201_CREATED, resp.status_code) | ||
| self.assertEqual(start_num + 1, end_num) | ||
|
|
||
| def test_get_note_as_super_user(self): | ||
| """Retrieve patch note with an superuser.""" | ||
| note = create_note(patch=self.patch) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| self.client.authenticate(user=self.superuser) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.check_for_expected(note, resp.data) | ||
|
|
||
| def test_get_note_as_anon_user(self): | ||
| """Retrieve patch note with an anonymous user.""" | ||
| note = create_note() | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) | ||
|
|
||
| def test_get_public_note_as_anon_user(self): | ||
| """Retrieve public patch note with an anon user.""" | ||
| note = create_note(patch=self.patch, maintainer_only=False) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.check_for_expected(note, resp.data) | ||
|
|
||
| def test_get_note_as_maintainer(self): | ||
| """Retrieve patch note with an user that is a maintainer.""" | ||
| note = create_note(patch=self.patch, submitter=self.user) | ||
|
|
||
| self.client.authenticate(user=self.user) | ||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.check_for_expected(note, resp.data) | ||
|
|
||
| def test_get_note_as_non_maintainer(self): | ||
| """Retrieve patch note with an user that is not a maintainer.""" | ||
| note = create_note() | ||
|
|
||
| self.client.authenticate(user=self.user) | ||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) | ||
|
|
||
| def test_get_note_public(self): | ||
| """Retrieve public patch note with an user that is not a maintainer.""" | ||
| person = create_person(user=self.user) | ||
| note = create_note(patch=self.patch, maintainer_only=False) | ||
|
|
||
| self.client.authenticate(user=person.user) | ||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.check_for_expected(note, resp.data) | ||
|
|
||
| def test_get_public_note_list_as_anon_user(self): | ||
| """Retrieve public patch note without authentication.""" | ||
| note = create_note(patch=self.patch, maintainer_only=False) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.check_for_expected(note, resp.data) | ||
|
|
||
| def test_get_note_list_as_super_user(self): | ||
| """Retrieve notes from a patch note without an user.""" | ||
| create_note(patch=self.patch, submitter=self.user) | ||
| create_note( | ||
| patch=self.patch, submitter=self.user, maintainer_only=False | ||
| ) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-list', kwargs={'patch_id': self.patch.id} | ||
| ) | ||
| self.client.authenticate(user=self.superuser) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.assertEqual(len(resp.data), 2) | ||
|
|
||
| def test_get_note_list_as_anon_user(self): | ||
| """Retrieve notes from a patch note without an user.""" | ||
| create_note(patch=self.patch, submitter=self.user) | ||
| public_note = create_note( | ||
| patch=self.patch, submitter=self.user, maintainer_only=False | ||
| ) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-list', kwargs={'patch_id': self.patch.id} | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.assertEqual(len(resp.data), 1) | ||
| self.check_for_expected(public_note, resp.data[0]) | ||
|
|
||
| def test_get_note_list_as_maintainer(self): | ||
| """Retrieve notes from a patch note with an user that is a maintainer.""" | ||
| create_note(patch=self.patch, submitter=self.user) | ||
| create_note( | ||
| patch=self.patch, submitter=self.user, maintainer_only=False | ||
| ) | ||
|
|
||
| self.client.authenticate(user=self.user) | ||
| url = reverse( | ||
| 'api-patch-note-list', kwargs={'patch_id': self.patch.id} | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.assertEqual(len(resp.data), 2) | ||
|
|
||
| def test_get_note_list_as_non_maintainer(self): | ||
| """Retrieve notes from a patch note with an user that is not a maintainer.""" | ||
| create_note(patch=self.patch, submitter=self.user) | ||
| public_note = create_note( | ||
| patch=self.patch, submitter=self.user, maintainer_only=False | ||
| ) | ||
| not_maintainer = create_user() | ||
|
|
||
| self.client.authenticate(user=not_maintainer) | ||
| url = reverse( | ||
| 'api-patch-note-list', kwargs={'patch_id': self.patch.id} | ||
| ) | ||
| resp = self.client.get(url) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.assertEqual(len(resp.data), 1) | ||
| self.assertEqual(resp.data[0]['id'], public_note.id) | ||
|
|
||
| def test_edit_note_as_maintainer(self): | ||
| """Edit patch note with an user that is a maintainer.""" | ||
| note = create_note(patch=self.patch, submitter=self.user) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| data = {'content': 'New content'} | ||
| self.client.authenticate(user=self.user) | ||
| resp = self.client.patch(url, data=data) | ||
|
|
||
| self.assertEqual(status.HTTP_200_OK, resp.status_code) | ||
| self.check_for_expected(note, resp.data) | ||
| self.assertNotEqual(note.content, resp.data['content']) | ||
| self.assertNotEqual(note.updated_at, resp.data['updated_at']) | ||
|
|
||
| def test_edit_note_as_non_maintainer(self): | ||
| """Edit patch note with an user that is not a maintainer.""" | ||
| note = create_note() | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| data = {'content': 'New content'} | ||
| self.client.authenticate(user=self.user) | ||
| resp = self.client.patch(url, data=data) | ||
|
|
||
| self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) | ||
|
|
||
| def test_edit_note_public_as_non_maintainer(self): | ||
| """ | ||
| Edit public patch note with an user that is not a maintainer. | ||
| """ | ||
| note = create_note(patch=self.patch, maintainer_only=False) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| data = {'content': 'New content'} | ||
| self.client.authenticate(user=create_user()) | ||
| resp = self.client.patch(url, data=data) | ||
|
|
||
| self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) | ||
|
|
||
| def test_delete_note_as_maintainer(self): | ||
| """Delete patch note with an user that is a maintainer.""" | ||
| note = create_note(patch=self.patch, submitter=self.user) | ||
| start_num = Note.objects.count() | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
|
|
||
| self.client.authenticate(user=self.user) | ||
| resp = self.client.delete(url) | ||
| end_num = Note.objects.count() | ||
|
|
||
| self.assertEqual(status.HTTP_204_NO_CONTENT, resp.status_code) | ||
| self.assertEqual(start_num - 1, end_num) | ||
|
|
||
| def test_delete_note_as_non_maintainer(self): | ||
| """Delete patch note with an user that is not a maintainer.""" | ||
| note = create_note() | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
|
|
||
| self.client.authenticate(user=self.user) | ||
| resp = self.client.delete(url) | ||
|
|
||
| self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) | ||
|
|
||
| def test_delete_note_public(self): | ||
| """ | ||
| Delete public patch note with an user that is a maintainer with | ||
| an user that is not a maintainer. | ||
| """ | ||
| person = create_person() | ||
| note = create_note(patch=self.patch, maintainer_only=False) | ||
|
|
||
| url = reverse( | ||
| 'api-patch-note-detail', | ||
| kwargs={'patch_id': self.patch.id, 'note_id': note.id}, | ||
| ) | ||
| self.client.authenticate(user=person.user) | ||
| resp = self.client.delete(url) | ||
|
|
||
| self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) | ||
|
|
||
| def test_notes_in_patch(self): | ||
| url = reverse('api-patch-detail', kwargs={'pk': self.patch.id}) | ||
| self.client.authenticate(user=self.user) | ||
| resp = self.client.get(url) | ||
|
|
||
| correct_path = reverse( | ||
| 'api-patch-note-list', kwargs={'patch_id': self.patch.id} | ||
| ) | ||
| self.assertEqual( | ||
| resp.data.get('notes'), | ||
| f'http://example.com{correct_path}', | ||
| ) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add create public note for tests