Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1911544/?format=api
{ "id": 1911544, "url": "http://patchwork.ozlabs.org/api/patches/1911544/?format=api", "web_url": "http://patchwork.ozlabs.org/project/patchwork/patch/20240313065642.385843-6-andrepapoti@gmail.com/", "project": { "id": 16, "url": "http://patchwork.ozlabs.org/api/projects/16/?format=api", "name": "Patchwork", "link_name": "patchwork", "list_id": "patchwork.lists.ozlabs.org", "list_email": "patchwork@lists.ozlabs.org", "web_url": "http://jk.ozlabs.org/projects/patchwork/", "scm_url": "git://github.com/getpatchwork/patchwork", "webscm_url": "https://github.com/getpatchwork/patchwork", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20240313065642.385843-6-andrepapoti@gmail.com>", "list_archive_url": null, "date": "2024-03-13T06:56:38", "name": "[6/9] tests: Add tests for Note related endpoints", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "1736df36d7a120e5aca59241ae4418f66e859d67", "submitter": { "id": 88169, "url": "http://patchwork.ozlabs.org/api/people/88169/?format=api", "name": "andrepapoti", "email": "andrepapoti@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/patchwork/patch/20240313065642.385843-6-andrepapoti@gmail.com/mbox/", "series": [ { "id": 398839, "url": "http://patchwork.ozlabs.org/api/series/398839/?format=api", "web_url": "http://patchwork.ozlabs.org/project/patchwork/list/?series=398839", "date": "2024-03-13T06:56:33", "name": "[1/9] models: Add Note model", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/398839/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1911544/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1911544/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "patchwork@lists.ozlabs.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "patchwork@lists.ozlabs.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20230601 header.b=BEezmNps;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org\n (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org;\n envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org;\n receiver=patchwork.ozlabs.org)", "lists.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20230601 header.b=BEezmNps;\n\tdkim-atps=neutral", "lists.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20230601 header.b=BEezmNps;\n\tdkim-atps=neutral", "lists.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gmail.com\n (client-ip=2607:f8b0:4864:20::42a; helo=mail-pf1-x42a.google.com;\n envelope-from=andrepapoti@gmail.com; receiver=lists.ozlabs.org)" ], "Received": [ "from lists.ozlabs.org (lists.ozlabs.org\n [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature ECDSA (secp384r1))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4TvhDK6vDmz1yWn\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 13 Mar 2024 17:58:09 +1100 (AEDT)", "from boromir.ozlabs.org (localhost [IPv6:::1])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 4TvhDK5sKrz3vYW\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 13 Mar 2024 17:58:09 +1100 (AEDT)", "from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com\n [IPv6:2607:f8b0:4864:20::42a])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 4TvhCr1t8xz3fNd\n\tfor <patchwork@lists.ozlabs.org>; Wed, 13 Mar 2024 17:57:44 +1100 (AEDT)", "by mail-pf1-x42a.google.com with SMTP id\n d2e1a72fcca58-6e6b729669bso311546b3a.3\n for <patchwork@lists.ozlabs.org>;\n Tue, 12 Mar 2024 23:57:44 -0700 (PDT)", "from localhost.localdomain ([2804:1b3:a4c0:b1de:3ec4:883:9cca:f0a7])\n by smtp.gmail.com with ESMTPSA id\n le21-20020a056a004fd500b006e691787eaesm4843998pfb.34.2024.03.12.23.57.39\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 12 Mar 2024 23:57:40 -0700 (PDT)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20230601; t=1710313061; x=1710917861;\n darn=lists.ozlabs.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=5BYxYjOFJzBtFqd3jGu5GMLS7R33LgrofCXNJ3DfbKs=;\n b=BEezmNpsJOKRGeyLZyQP600Azq8l1Km0AyzRGPSRnkSfAc/oxDodg299lYqq/D13qS\n Hl0Bzm/nx8FHlpSVsTd4RwITf/Tc8q12kQvIze/Jkh2wY7z24A6jXUBpifKjGZUP1RgX\n WzGqWRDajucFf7p6TkrJrDnu7vybYtFUJvYigid2hz2PxvAJri0hHqeR9NJD5e/3p/Uz\n EoT+F2TbAoCriQrFpgRnVxkQ/F4QPDhBPRa9BgrMyHWeJultqbpEzrAXOW/kCvtA0ICW\n mzB8RdyvMcNYTxOnmc1I6MCneYqhQWVKoLDXT9EIE6E8VmR/rCma59CqinDsys96GaHX\n yWYg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1710313061; x=1710917861;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=5BYxYjOFJzBtFqd3jGu5GMLS7R33LgrofCXNJ3DfbKs=;\n b=hF0OIW108va9rCYzhuQ19IN8TtMiuGiCJAOrkDuwupmD0znsSs/pdAv0YfRSVF72rz\n uTbYKU6FTYA5/pGjgZIgvAEx8mxXM34e/0OVdONgiEdmy6dy5Uc6mWpINHNJy3bAheTN\n 0NystsxLGD+lfgHj9RlCoB14Uoly/JQ1tPFaCZdWdNjUNL1TKHpeS0mIvthhjDYzuejC\n 9Lk5DePEKC7T67DBMHnsQyeJJQSyOXTcrkWoUHpVUIjyFbCyR7Rl1AQWQTDpk+I6Omjk\n 3gfnbXhB6lORT/KwWCnzqzr/VVU8KWFuh6C/d+Gjy8a5yrhlUa1+8Q8wRciadKQi3m6d\n qTBw==", "X-Gm-Message-State": "AOJu0YxobAsFqwiuuwykhin6wBqu1ahF7qebJfZTh7RlxvdTpY/EbgQ9\n\t0jczf0UWKlwFC+qkS6TxJ40LM1QjRDtIrDXa7H1yDZaQY79aSnwjRHUji+pz", "X-Google-Smtp-Source": "\n AGHT+IGZWUCSYoLAipxHjpD5NGF5kFm5EqPVomE+gB9jDr2lvN2kxm5ujrhwU6X5T5rDTCL5PIjFOA==", "X-Received": "by 2002:a05:6a00:1403:b0:6e6:8964:7fcd with SMTP id\n l3-20020a056a00140300b006e689647fcdmr1757560pfu.24.1710313060996;\n Tue, 12 Mar 2024 23:57:40 -0700 (PDT)", "From": "andrepapoti <andrepapoti@gmail.com>", "To": "patchwork@lists.ozlabs.org", "Subject": "[PATCH 6/9] tests: Add tests for Note related endpoints", "Date": "Wed, 13 Mar 2024 03:56:38 -0300", "Message-ID": "<20240313065642.385843-6-andrepapoti@gmail.com>", "X-Mailer": "git-send-email 2.44.0", "In-Reply-To": "<20240313065642.385843-1-andrepapoti@gmail.com>", "References": "<20240313065642.385843-1-andrepapoti@gmail.com>", "MIME-Version": "1.0", "X-BeenThere": "patchwork@lists.ozlabs.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "Patchwork development <patchwork.lists.ozlabs.org>", "List-Unsubscribe": "<https://lists.ozlabs.org/options/patchwork>,\n <mailto:patchwork-request@lists.ozlabs.org?subject=unsubscribe>", "List-Archive": "<http://lists.ozlabs.org/pipermail/patchwork/>", "List-Post": "<mailto:patchwork@lists.ozlabs.org>", "List-Help": "<mailto:patchwork-request@lists.ozlabs.org?subject=help>", "List-Subscribe": "<https://lists.ozlabs.org/listinfo/patchwork>,\n <mailto:patchwork-request@lists.ozlabs.org?subject=subscribe>", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org", "Sender": "\"Patchwork\"\n <patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>" }, "content": "Signed-off-by: andrepapoti <andrepapoti@gmail.com>\n---\n patchwork/tests/api/test_notes.py | 232 ++++++++++++++++++++++++++++++\n patchwork/tests/utils.py | 12 ++\n 2 files changed, 244 insertions(+)\n create mode 100644 patchwork/tests/api/test_notes.py", "diff": "diff --git a/patchwork/tests/api/test_notes.py b/patchwork/tests/api/test_notes.py\nnew file mode 100644\nindex 0000000..fc2d2e3\n--- /dev/null\n+++ b/patchwork/tests/api/test_notes.py\n@@ -0,0 +1,232 @@\n+# Patchwork - automated patch tracking system\n+# Copyright (C) 2018 Red Hat\n+#\n+# SPDX-License-Identifier: GPL-2.0-or-later\n+\n+from django.test import override_settings\n+from django.urls import reverse\n+from rest_framework import status\n+\n+from patchwork.models import Note\n+from patchwork.tests.api import utils\n+from patchwork.tests.utils import create_patch\n+from patchwork.tests.utils import create_maintainer\n+from patchwork.tests.utils import create_person\n+from patchwork.tests.utils import create_project\n+from patchwork.tests.utils import create_note\n+from patchwork.tests.utils import create_user\n+\n+\n+@override_settings(ENABLE_REST_API=True)\n+class TestPatchNotes(utils.APITestCase):\n+ def setUp(self):\n+ super(TestPatchNotes, self).setUp()\n+ self.project = create_project()\n+ self.user = create_maintainer(self.project)\n+ self.patch = create_patch(project=self.project)\n+\n+ def check_for_expected(self, instance, response_data):\n+ self.assertEqual(instance.id, response_data['id'])\n+ self.assertEqual(instance.patch.id, response_data['patch']['id'])\n+ self.assertEqual(\n+ instance.submitter.id, response_data['submitter']['id']\n+ )\n+\n+ def test_create_note(self):\n+ start_num = Note.objects.count()\n+ url = reverse(\n+ 'api-patch-note-list', kwargs={'patch_id': self.patch.id}\n+ )\n+ data = {'content': 'New note'}\n+ self.client.authenticate(user=self.user)\n+ resp = self.client.post(url, data=data)\n+ end_num = Note.objects.count()\n+\n+ self.assertEqual(status.HTTP_201_CREATED, resp.status_code)\n+ self.assertEqual(start_num + 1, end_num)\n+\n+ def test_get_note_as_maintainer(self):\n+ \"\"\"Retrieve patch note with an user that is a maintainer.\"\"\"\n+ person = create_person(user=self.user)\n+ note = create_note(patch=self.patch, submitter=person)\n+\n+ self.client.authenticate(user=self.user)\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+ resp = self.client.get(url)\n+\n+ self.assertEqual(status.HTTP_200_OK, resp.status_code)\n+ self.check_for_expected(note, resp.data)\n+\n+ def test_get_note_as_non_maintainer(self):\n+ \"\"\"Retrieve patch note with an user that is not a maintainer.\"\"\"\n+ person = create_person()\n+ note = create_note(patch=self.patch)\n+\n+ self.client.authenticate(user=person.user)\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+ resp = self.client.get(url)\n+\n+ self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)\n+\n+ def test_get_note_public(self):\n+ \"\"\"Retrieve public patch note with an user that is not a maintainer.\"\"\"\n+ person = create_person(user=self.user)\n+ note = create_note(patch=self.patch, maintainer_only=False)\n+\n+ self.client.authenticate(user=person.user)\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+ resp = self.client.get(url)\n+\n+ self.assertEqual(status.HTTP_200_OK, resp.status_code)\n+ self.check_for_expected(note, resp.data)\n+\n+ def test_get_note_list_as_maintainer(self):\n+ \"\"\"Retrieve notes from a patch note with an user that is a maintainer.\"\"\"\n+ person = create_person(user=self.user)\n+ create_note(patch=self.patch, submitter=person)\n+ create_note(patch=self.patch, submitter=person, maintainer_only=False)\n+\n+ self.client.authenticate(user=self.user)\n+ url = reverse(\n+ 'api-patch-note-list', kwargs={'patch_id': self.patch.id}\n+ )\n+ resp = self.client.get(url)\n+\n+ self.assertEqual(status.HTTP_200_OK, resp.status_code)\n+ self.assertEqual(len(resp.data), 2)\n+\n+ def test_get_note_list_as_non_maintainer(self):\n+ \"\"\"Retrieve notes from a patch note with an user that is not a maintainer.\"\"\"\n+ person = create_person(user=self.user)\n+ create_note(patch=self.patch, submitter=person)\n+ public_note = create_note(\n+ patch=self.patch, submitter=person, maintainer_only=False\n+ )\n+ not_maintainer = create_user()\n+\n+ self.client.authenticate(user=not_maintainer)\n+ url = reverse(\n+ 'api-patch-note-list', kwargs={'patch_id': self.patch.id}\n+ )\n+ resp = self.client.get(url)\n+\n+ self.assertEqual(status.HTTP_200_OK, resp.status_code)\n+ self.assertEqual(len(resp.data), 1)\n+ self.assertEqual(resp.data[0]['id'], public_note.id)\n+\n+ def test_edit_note_as_maintainer(self):\n+ \"\"\"Edit patch note with an user that is a maintainer.\"\"\"\n+ person = create_person(user=self.user)\n+ note = create_note(patch=self.patch, submitter=person)\n+\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+ data = {'content': 'New content'}\n+ self.client.authenticate(user=person.user)\n+ resp = self.client.patch(url, data=data)\n+\n+ self.assertEqual(status.HTTP_200_OK, resp.status_code)\n+ self.check_for_expected(note, resp.data)\n+ self.assertNotEqual(note.content, resp.data['content'])\n+ self.assertNotEqual(note.last_modified, resp.data['last_modified'])\n+\n+ def test_edit_note_as_non_maintainer(self):\n+ \"\"\"Edit patch note with an user that is not a maintainer.\"\"\"\n+ person = create_person()\n+ note = create_note(patch=self.patch)\n+\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+ data = {'content': 'New content'}\n+ self.client.authenticate(user=person.user)\n+ resp = self.client.patch(url, data=data)\n+\n+ self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)\n+\n+ def test_edit_note_public(self):\n+ \"\"\"Edit public patch note with an user that is a maintainerwith an user that is not a maintainer.\"\"\"\n+ person = create_person()\n+ note = create_note(patch=self.patch, maintainer_only=False)\n+\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+ data = {'content': 'New content'}\n+ self.client.authenticate(user=person.user)\n+ resp = self.client.patch(url, data=data)\n+\n+ self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)\n+\n+ def test_delete_note_as_maintainer(self):\n+ \"\"\"Delete patch note with an user that is a maintainer.\"\"\"\n+ person = create_person(user=self.user)\n+ note = create_note(patch=self.patch, submitter=person)\n+ start_num = Note.objects.count()\n+\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+\n+ self.client.authenticate(user=person.user)\n+ resp = self.client.delete(url)\n+ end_num = Note.objects.count()\n+\n+ self.assertEqual(status.HTTP_204_NO_CONTENT, resp.status_code)\n+ self.assertEqual(start_num - 1, end_num)\n+\n+ def test_delete_note_as_non_maintainer(self):\n+ \"\"\"Delete patch note with an user that is not a maintainer.\"\"\"\n+ person = create_person()\n+ note = create_note(patch=self.patch)\n+\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+\n+ self.client.authenticate(user=person.user)\n+ resp = self.client.delete(url)\n+\n+ self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)\n+\n+ def test_delete_note_public(self):\n+ \"\"\"Delete public patch note with an user that is a maintainerwith an user that is not a maintainer.\"\"\"\n+ person = create_person()\n+ note = create_note(patch=self.patch, maintainer_only=False)\n+\n+ url = reverse(\n+ 'api-patch-note-detail',\n+ kwargs={'patch_id': self.patch.id, 'note_id': note.id},\n+ )\n+ self.client.authenticate(user=person.user)\n+ resp = self.client.delete(url)\n+\n+ self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)\n+\n+ def test_notes_in_patch(self):\n+ url = reverse('api-patch-detail', kwargs={'pk': self.patch.id})\n+ self.client.authenticate(user=self.user)\n+ resp = self.client.get(url)\n+\n+ correct_path = reverse(\n+ 'api-patch-note-list', kwargs={'patch_id': self.patch.id}\n+ )\n+ self.assertEqual(\n+ resp.data.get('notes'),\n+ f'http://example.com{correct_path}',\n+ )\ndiff --git a/patchwork/tests/utils.py b/patchwork/tests/utils.py\nindex 4f40489..3fbb689 100644\n--- a/patchwork/tests/utils.py\n+++ b/patchwork/tests/utils.py\n@@ -15,6 +15,7 @@ from patchwork.models import Bundle\n from patchwork.models import Check\n from patchwork.models import Cover\n from patchwork.models import CoverComment\n+from patchwork.models import Note\n from patchwork.models import Patch\n from patchwork.models import PatchComment\n from patchwork.models import PatchRelation\n@@ -270,6 +271,17 @@ def create_patch_comment(**kwargs):\n return PatchComment.objects.create(**values)\n \n \n+def create_note(**kwargs):\n+ \"\"\"Create 'Note' object.\"\"\"\n+ values = {\n+ 'submitter': create_person() if 'submitter' not in kwargs else None,\n+ 'content': 'Note content',\n+ }\n+ values.update(kwargs)\n+\n+ return Note.objects.create(**values)\n+\n+\n def create_check(**kwargs):\n \"\"\"Create 'Check' object.\"\"\"\n values = {\n", "prefixes": [ "6/9" ] }