Blame SOURCES/kvm-iotests-add-qmp-recursive-sorting-function.patch

7711c0
From c455d2804d7ef6c379b815b6787baf69d3cb760a Mon Sep 17 00:00:00 2001
7711c0
From: John Snow <jsnow@redhat.com>
7711c0
Date: Wed, 20 Mar 2019 16:16:20 +0100
7711c0
Subject: [PATCH 022/163] iotests: add qmp recursive sorting function
7711c0
7711c0
RH-Author: John Snow <jsnow@redhat.com>
7711c0
Message-id: <20190320161631.14841-9-jsnow@redhat.com>
7711c0
Patchwork-id: 84944
7711c0
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/19] iotests: add qmp recursive sorting function
7711c0
Bugzilla: 1668956
7711c0
RH-Acked-by: Max Reitz <mreitz@redhat.com>
7711c0
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
7711c0
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
7711c0
7711c0
Python before 3.6 does not sort dictionaries (including kwargs).
7711c0
Therefore, printing QMP objects involves sorting the keys to have
7711c0
a predictable ordering in the iotests output. This means that
7711c0
iotests output will sometimes show arguments in an order not
7711c0
specified by the test author.
7711c0
7711c0
Presently, we accomplish this by using json.dumps' sort_keys argument,
7711c0
where we only serialize the arguments dictionary, but not the command.
7711c0
7711c0
However, if we want to pretty-print QMP objects being sent to the
7711c0
QEMU process, we need to build the entire command before logging it.
7711c0
Ordinarily, this would then involve "arguments" being sorted above
7711c0
"execute", which would necessitate a rather ugly and harder-to-read
7711c0
change to many iotests outputs.
7711c0
7711c0
To facilitate pretty-printing AND maintaining predictable output AND
7711c0
having "arguments" sort after "execute", add a custom sort function
7711c0
that takes a dictionary and recursively builds an OrderedDict that
7711c0
maintains the specific key order we wish to see in iotests output.
7711c0
7711c0
The qmp_log function uses this to build a QMP object that keeps
7711c0
"execute" above "arguments", but sorts all keys and keys in any
7711c0
subdicts in "arguments" lexicographically to maintain consistent
7711c0
iotests output, with no incompatible changes to any current test.
7711c0
7711c0
Signed-off-by: John Snow <jsnow@redhat.com>
7711c0
Reviewed-by: Eric Blake <eblake@redhat.com>
7711c0
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7711c0
Message-Id: <20181221093529.23855-8-jsnow@redhat.com>
7711c0
Signed-off-by: Eric Blake <eblake@redhat.com>
7711c0
(cherry picked from commit 0706e87d72b02f28bfa04400388f9c9df1b9c943)
7711c0
Signed-off-by: John Snow <jsnow@redhat.com>
7711c0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
7711c0
---
7711c0
 tests/qemu-iotests/iotests.py | 24 ++++++++++++++++++++----
7711c0
 1 file changed, 20 insertions(+), 4 deletions(-)
7711c0
7711c0
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
7711c0
index 5334ff4..bd508be 100644
7711c0
--- a/tests/qemu-iotests/iotests.py
7711c0
+++ b/tests/qemu-iotests/iotests.py
7711c0
@@ -28,6 +28,7 @@ import json
7711c0
 import signal
7711c0
 import logging
7711c0
 import atexit
7711c0
+from collections import OrderedDict
7711c0
 
7711c0
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
7711c0
 import qtest
7711c0
@@ -73,6 +74,16 @@ def qemu_img(*args):
7711c0
         sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
7711c0
     return exitcode
7711c0
 
7711c0
+def ordered_kwargs(kwargs):
7711c0
+    # kwargs prior to 3.6 are not ordered, so:
7711c0
+    od = OrderedDict()
7711c0
+    for k, v in sorted(kwargs.items()):
7711c0
+        if isinstance(v, dict):
7711c0
+            od[k] = ordered_kwargs(v)
7711c0
+        else:
7711c0
+            od[k] = v
7711c0
+    return od
7711c0
+
7711c0
 def qemu_img_create(*args):
7711c0
     args = list(args)
7711c0
 
7711c0
@@ -251,8 +262,10 @@ def filter_img_info(output, filename):
7711c0
 def log(msg, filters=[]):
7711c0
     for flt in filters:
7711c0
         msg = flt(msg)
7711c0
-    if type(msg) is dict or type(msg) is list:
7711c0
-        print(json.dumps(msg, sort_keys=True))
7711c0
+    if isinstance(msg, dict) or isinstance(msg, list):
7711c0
+        # Don't sort if it's already sorted
7711c0
+        do_sort = not isinstance(msg, OrderedDict)
7711c0
+        print(json.dumps(msg, sort_keys=do_sort))
7711c0
     else:
7711c0
         print(msg)
7711c0
 
7711c0
@@ -442,8 +455,11 @@ class VM(qtest.QEMUQtestMachine):
7711c0
         return result
7711c0
 
7711c0
     def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs):
7711c0
-        logmsg = '{"execute": "%s", "arguments": %s}' % \
7711c0
-            (cmd, json.dumps(kwargs, sort_keys=True))
7711c0
+        full_cmd = OrderedDict((
7711c0
+            ("execute", cmd),
7711c0
+            ("arguments", ordered_kwargs(kwargs))
7711c0
+        ))
7711c0
+        logmsg = json.dumps(full_cmd)
7711c0
         log(logmsg, filters)
7711c0
         result = self.qmp(cmd, **kwargs)
7711c0
         log(json.dumps(result, sort_keys=True), filters)
7711c0
-- 
7711c0
1.8.3.1
7711c0