get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/40784/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 40784,
    "url": "http://patchwork.dpdk.org/api/patches/40784/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/6cd7373c1cfe7011b5fb4e245aaa03cd2d399ac9.1528404133.git.anatoly.burakov@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<6cd7373c1cfe7011b5fb4e245aaa03cd2d399ac9.1528404133.git.anatoly.burakov@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/6cd7373c1cfe7011b5fb4e245aaa03cd2d399ac9.1528404133.git.anatoly.burakov@intel.com",
    "date": "2018-06-07T21:01:59",
    "name": "[dpdk-dev,5/7] autotest: improve filtering",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "0870dca4c32b86dbe954f685ce120bff08f98c77",
    "submitter": {
        "id": 4,
        "url": "http://patchwork.dpdk.org/api/people/4/?format=api",
        "name": "Burakov, Anatoly",
        "email": "anatoly.burakov@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/6cd7373c1cfe7011b5fb4e245aaa03cd2d399ac9.1528404133.git.anatoly.burakov@intel.com/mbox/",
    "series": [
        {
            "id": 37,
            "url": "http://patchwork.dpdk.org/api/series/37/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=37",
            "date": "2018-06-07T21:01:54",
            "name": "Make unit tests great again",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/37/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/40784/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/40784/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 2501C1B16B;\n\tThu,  7 Jun 2018 23:02:16 +0200 (CEST)",
            "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n\tby dpdk.org (Postfix) with ESMTP id 5897F1AEF6;\n\tThu,  7 Jun 2018 23:02:06 +0200 (CEST)",
            "from orsmga005.jf.intel.com ([10.7.209.41])\n\tby orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t07 Jun 2018 14:02:04 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga005.jf.intel.com with ESMTP; 07 Jun 2018 14:02:03 -0700",
            "from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com\n\t[10.237.217.45])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tw57L22kG023043; Thu, 7 Jun 2018 22:02:02 +0100",
            "from sivswdev01.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev01.ir.intel.com with ESMTP id w57L22p6004381;\n\tThu, 7 Jun 2018 22:02:02 +0100",
            "(from aburakov@localhost)\n\tby sivswdev01.ir.intel.com with LOCAL id w57L22wx004377;\n\tThu, 7 Jun 2018 22:02:02 +0100"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.49,488,1520924400\"; d=\"scan'208\";a=\"230805271\"",
        "From": "Anatoly Burakov <anatoly.burakov@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "john.mcnamara@intel.com, reshma.pattan@intel.com,\n\tbruce.richardson@intel.com, stable@dpdk.org",
        "Date": "Thu,  7 Jun 2018 22:01:59 +0100",
        "Message-Id": "<6cd7373c1cfe7011b5fb4e245aaa03cd2d399ac9.1528404133.git.anatoly.burakov@intel.com>",
        "X-Mailer": "git-send-email 1.7.0.7",
        "In-Reply-To": [
            "<cover.1528404133.git.anatoly.burakov@intel.com>",
            "<cover.1528404133.git.anatoly.burakov@intel.com>"
        ],
        "References": [
            "<cover.1528404133.git.anatoly.burakov@intel.com>",
            "<cover.1528404133.git.anatoly.burakov@intel.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH 5/7] autotest: improve filtering",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Improve code for filtering test groups. Also, move reading binary\nsymbols into filtering stage, so that tests that are meant to be\nskipped are never attempted to be executed in the first place.\nBefore running tests, print out any tests that were skipped because\nthey weren't compiled.\n\nCc: stable@dpdk.org\n\nSigned-off-by: Anatoly Burakov <anatoly.burakov@intel.com>\n---\n test/test/autotest_runner.py | 118 ++++++++++++++++++++---------------\n 1 file changed, 66 insertions(+), 52 deletions(-)",
    "diff": "diff --git a/test/test/autotest_runner.py b/test/test/autotest_runner.py\nindex d9d5f7a97..c98ec2a57 100644\n--- a/test/test/autotest_runner.py\n+++ b/test/test/autotest_runner.py\n@@ -95,13 +95,6 @@ def run_test_group(cmdline, target, test_group):\n     results.append((0, \"Success\", \"Start %s\" % test_group[\"Prefix\"],\n                     time.time() - start_time, startuplog.getvalue(), None))\n \n-    # parse the binary for available test commands\n-    binary = cmdline.split()[0]\n-    stripped = 'not stripped' not in subprocess.check_output(['file', binary])\n-    if not stripped:\n-        symbols = subprocess.check_output(['nm', binary]).decode('utf-8')\n-        avail_cmds = re.findall('test_register_(\\w+)', symbols)\n-\n     # run all tests in test group\n     for test in test_group[\"Tests\"]:\n \n@@ -121,10 +114,7 @@ def run_test_group(cmdline, target, test_group):\n             print(\"\\n%s %s\\n\" % (\"-\" * 20, test[\"Name\"]), file=logfile)\n \n             # run test function associated with the test\n-            if stripped or test[\"Command\"] in avail_cmds:\n-                result = test[\"Func\"](child, test[\"Command\"])\n-            else:\n-                result = (0, \"Skipped [Not Available]\")\n+            result = test[\"Func\"](child, test[\"Command\"])\n \n             # make a note when the test was finished\n             end_time = time.time()\n@@ -186,8 +176,10 @@ class AutotestRunner:\n     def __init__(self, cmdline, target, blacklist, whitelist):\n         self.cmdline = cmdline\n         self.target = target\n+        self.binary = cmdline.split()[0]\n         self.blacklist = blacklist\n         self.whitelist = whitelist\n+        self.skipped = []\n \n         # log file filename\n         logfile = \"%s.log\" % target\n@@ -276,53 +268,58 @@ def __process_results(self, results):\n             if i != 0:\n                 self.csvwriter.writerow([test_name, test_result, result_str])\n \n-    # this function iterates over test groups and removes each\n-    # test that is not in whitelist/blacklist\n-    def __filter_groups(self, test_groups):\n-        groups_to_remove = []\n-\n-        # filter out tests from parallel test groups\n-        for i, test_group in enumerate(test_groups):\n-\n-            # iterate over a copy so that we could safely delete individual\n-            # tests\n-            for test in test_group[\"Tests\"][:]:\n-                test_id = test[\"Command\"]\n-\n-                # dump tests are specified in full e.g. \"Dump_mempool\"\n-                if \"_autotest\" in test_id:\n-                    test_id = test_id[:-len(\"_autotest\")]\n-\n-                # filter out blacklisted/whitelisted tests\n-                if self.blacklist and test_id in self.blacklist:\n-                    test_group[\"Tests\"].remove(test)\n-                    continue\n-                if self.whitelist and test_id not in self.whitelist:\n-                    test_group[\"Tests\"].remove(test)\n-                    continue\n-\n-            # modify or remove original group\n-            if len(test_group[\"Tests\"]) > 0:\n-                test_groups[i] = test_group\n-            else:\n-                # remember which groups should be deleted\n-                # put the numbers backwards so that we start\n-                # deleting from the end, not from the beginning\n-                groups_to_remove.insert(0, i)\n+    # this function checks individual test and decides if this test should be in\n+    # the group by comparing it against  whitelist/blacklist. it also checks if\n+    # the test is compiled into the binary, and marks it as skipped if necessary\n+    def __filter_test(self, test):\n+        test_cmd = test[\"Command\"]\n+        test_id = test_cmd\n+\n+        # dump tests are specified in full e.g. \"Dump_mempool\"\n+        if \"_autotest\" in test_id:\n+            test_id = test_id[:-len(\"_autotest\")]\n+\n+        # filter out blacklisted/whitelisted tests\n+        if self.blacklist and test_id in self.blacklist:\n+            return False\n+        if self.whitelist and test_id not in self.whitelist:\n+            return False\n+\n+        # if test wasn't compiled in, remove it as well\n+\n+        # parse the binary for available test commands\n+        stripped = 'not stripped' not in \\\n+                   subprocess.check_output(['file', self.binary])\n+        if not stripped:\n+            symbols = subprocess.check_output(['nm',\n+                                               self.binary]).decode('utf-8')\n+            avail_cmds = re.findall('test_register_(\\w+)', symbols)\n+\n+            if test_cmd not in avail_cmds:\n+                # notify user\n+                result = 0, \"Skipped [Not compiled]\", test_id, 0, \"\", None\n+                self.skipped.append(tuple(result))\n+                return False\n \n-        # remove test groups that need to be removed\n-        for i in groups_to_remove:\n-            del test_groups[i]\n+        return True\n \n-        return test_groups\n+    def __filter_group(self, group):\n+        group[\"Tests\"] = list(filter(self.__filter_test, group[\"Tests\"]))\n+        return len(group[\"Tests\"]) > 0\n \n     # iterate over test groups and run tests associated with them\n     def run_all_tests(self):\n         # filter groups\n-        self.parallel_test_groups = \\\n-            self.__filter_groups(self.parallel_test_groups)\n-        self.non_parallel_test_groups = \\\n-            self.__filter_groups(self.non_parallel_test_groups)\n+        # for each test group, check all tests against the filter, then remove\n+        # all groups that don't have any tests\n+        self.parallel_test_groups = list(\n+            filter(self.__filter_group,\n+                   self.parallel_test_groups)\n+        )\n+        self.non_parallel_test_groups = list(\n+            filter(self.__filter_group,\n+                   self.non_parallel_test_groups)\n+        )\n \n         # create a pool of worker threads\n         pool = multiprocessing.Pool(processes=1)\n@@ -338,6 +335,23 @@ def run_all_tests(self):\n                   \"Test\".center(9) + \"Total\".center(9))\n             print(\"=\" * 80)\n \n+            # print out skipped autotests if there were any\n+            if len(self.skipped):\n+                print(\"Skipped autotests:\")\n+\n+                # print out any skipped tests\n+                for result in self.skipped:\n+                    # unpack result tuple\n+                    test_result, result_str, test_name, _, _, _ = result\n+                    self.csvwriter.writerow([test_name, test_result,\n+                                             result_str])\n+\n+                    t = (\"%s:\" % test_name).ljust(30)\n+                    t += result_str.ljust(29)\n+                    t += \"[00m 00s]\"\n+\n+                    print(t)\n+\n             # make a note of tests start time\n             self.start = time.time()\n \n",
    "prefixes": [
        "dpdk-dev",
        "5/7"
    ]
}