qmp_command.py 12.9 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1 2
import logging
import re
3

L
Lucas Meneghel Rodrigues 已提交
4 5
from autotest.client.shared import error

Y
yanwang 已提交
6 7
from avocado.core import exceptions
from avocado.utils import process
8 9 10

from virttest import utils_misc
from virttest import qemu_monitor
F
Feng Yang 已提交
11 12


13
def run(test, params, env):
F
Feng Yang 已提交
14 15 16 17 18 19 20
    """
    Test qmp event notification, this case will:
    1) Start VM with qmp enable.
    2) Connect to qmp port then run qmp_capabilities command.
    3) Initiate the qmp command defined in config (qmp_cmd)
    4) Verify that qmp command works as designed.

L
Lucas Meneghel Rodrigues 已提交
21 22 23
    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
F
Feng Yang 已提交
24
    """
25
    def check_result(qmp_o, output=None, exception_list=""):
F
Feng Yang 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39
        """
        Check test result with difference way accoriding to
        result_check.
        result_check = equal, will compare cmd_return_value with qmp
                       command output.
        result_check = contain, will try to find cmd_return_value in qmp
                       command output.
        result_check = m_equal_q, will compare key value in monitor command
                       output and qmp command output.
        result_check = m_in_q, will try to find monitor command output's key
                       value in qmp command output.
        result_check = m_format_q, will try to match the output's format with
                       check pattern.

L
Lucas Meneghel Rodrigues 已提交
40 41
        :param qmp_o: output from pre_cmd, qmp_cmd or post_cmd.
        :param o: output from pre_cmd, qmp_cmd or post_cmd or an execpt
42
        :param exception_list: element no need check.
F
Feng Yang 已提交
43 44 45 46 47
        result set in config file.
        """
        if result_check == "equal":
            value = output
            if value != str(qmp_o):
Y
yanwang 已提交
48 49 50
                raise exceptions.TestFail("QMP command return value does not match "
                                          "the expect result. Expect result: '%s'\n"
                                          "Actual result: '%s'" % (value, qmp_o))
F
Feng Yang 已提交
51 52 53
        elif result_check == "contain":
            values = output.split(';')
            for value in values:
54 55
                if value in exception_list:
                    continue
F
Feng Yang 已提交
56
                if value.strip() not in str(qmp_o):
Y
yanwang 已提交
57 58 59 60
                    raise exceptions.TestFail("QMP command output does not contain "
                                              "expect result. Expect result: '%s'\n"
                                              "Actual result: '%s'"
                                              % (value, qmp_o))
F
Feng Yang 已提交
61 62 63
        elif result_check == "not_contain":
            values = output.split(';')
            for value in values:
64 65
                if value in exception_list:
                    continue
F
Feng Yang 已提交
66
                if value in str(qmp_o):
Y
yanwang 已提交
67 68 69 70
                    raise exceptions.TestFail("QMP command output contains unexpect"
                                              " result. Unexpect result: '%s'\n"
                                              "Actual result: '%s'"
                                              % (value, qmp_o))
F
Feng Yang 已提交
71 72
        elif result_check == "m_equal_q":
            msg = "QMP command ouput is not equal to in human monitor command."
73 74
            msg += "\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman command output: '%s'" % output
F
Feng Yang 已提交
75 76 77 78 79 80
            res = output.splitlines(True)
            if type(qmp_o) != type(res):
                len_o = 1
            else:
                len_o = len(qmp_o)
            if len(res) != len_o:
81
                if res[0].startswith(' '):
Y
yanwang 已提交
82 83 84
                    raise exceptions.TestFail("Human command starts with ' ', "
                                              "there is probably some garbage in "
                                              "the output.\n" + msg)
85 86 87 88 89 90 91 92 93
                res_tmp = []
                #(qemu)info block in RHEL7 divided into 3 lines
                for line in res:
                    if not line.startswith(' '):
                        res_tmp.append(line)
                    else:
                        res_tmp[-1] += line
                res = res_tmp
                if len(res) != len_o:
Y
yanwang 已提交
94
                    raise exceptions.TestFail(msg)
F
Feng Yang 已提交
95 96
            re_str = r'([^ \t\n\r\f\v=]*)=([^ \t\n\r\f\v=]*)'
            for i in range(len(res)):
97 98 99
                if qmp_cmd == "query-version":
                    version = qmp_o['qemu']
                    version = "%s.%s.%s" % (version['major'], version['minor'],
L
Lucas Meneghel Rodrigues 已提交
100
                                            version['micro'])
101
                    package = qmp_o['package']
102
                    re_str = r"([0-9]+\.[0-9]+\.[0-9]+)\s*(\(\S*\))?"
103 104 105
                    hmp_version, hmp_package = re.findall(re_str, res[i])[0]
                    if not hmp_package:
                        hmp_package = package
106 107 108
                    hmp_package = hmp_package.strip()
                    package = package.strip()
                    hmp_version = hmp_version.strip()
109
                    if version != hmp_version or package != hmp_package:
Y
yanwang 已提交
110
                        raise exceptions.TestFail(msg)
111 112 113
                else:
                    matches = re.findall(re_str, res[i])
                    for key, val in matches:
114 115
                        if key in exception_list:
                            continue
116 117
                        if '0x' in val:
                            val = long(val, 16)
Y
yanwang 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130
                            val_str = str(bin(val))
                            com_str = ""
                            for p in range(3, len(val_str)):
                                if val_str[p] == '1':
                                    com_str += '0'
                                else:
                                    com_str += '1'
                            com_str = "0b" + com_str
                            value = eval(com_str) + 1
                            if val_str[2] == '1':
                                value = -value
                            if value != qmp_o[i][key]:
                                msg += "\nValue in human monitor: '%s'" % value
131
                                msg += "\nValue in qmp: '%s'" % qmp_o[i][key]
Y
yanwang 已提交
132
                                raise exceptions.TestFail(msg)
133 134 135 136 137 138 139 140 141 142
                        elif qmp_cmd == "query-block":
                            cmp_str = "u'%s': u'%s'" % (key, val)
                            cmp_s = "u'%s': %s" % (key, val)
                            if '0' == val:
                                cmp_str_b = "u'%s': False" % key
                            elif '1' == val:
                                cmp_str_b = "u'%s': True" % key
                            else:
                                cmp_str_b = cmp_str
                            if (cmp_str not in str(qmp_o[i]) and
143 144
                                    cmp_str_b not in str(qmp_o[i]) and
                                    cmp_s not in str(qmp_o[i])):
145 146 147
                                msg += ("\nCan not find '%s', '%s' or '%s' in "
                                        " QMP command output."
                                        % (cmp_s, cmp_str_b, cmp_str))
Y
yanwang 已提交
148
                                raise exceptions.TestFail(msg)
149 150
                        elif qmp_cmd == "query-balloon":
                            if (int(val) * 1024 * 1024 != qmp_o[key] and
151
                                    val not in str(qmp_o[key])):
152 153
                                msg += ("\n'%s' is not in QMP command output"
                                        % val)
Y
yanwang 已提交
154
                                raise exceptions.TestFail(msg)
F
Feng Yang 已提交
155
                        else:
156
                            if (val not in str(qmp_o[i][key]) and
157
                                    str(bool(int(val))) not in str(qmp_o[i][key])):
158 159
                                msg += ("\n'%s' is not in QMP command output"
                                        % val)
Y
yanwang 已提交
160
                                raise exceptions.TestFail(msg)
F
Feng Yang 已提交
161 162 163
        elif result_check == "m_in_q":
            res = output.splitlines(True)
            msg = "Key value from human monitor command is not in"
164 165
            msg += "QMP command output.\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman monitor command output '%s'" % output
L
Lucas Meneghel Rodrigues 已提交
166
            for i in range(len(res)):
167
                params = res[i].rstrip().split()
F
Feng Yang 已提交
168
                for param in params:
169 170
                    if param.rstrip() in exception_list:
                        continue
F
Feng Yang 已提交
171 172 173 174 175
                    try:
                        str_o = str(qmp_o.values())
                    except AttributeError:
                        str_o = qmp_o
                    if param.rstrip() not in str(str_o):
176
                        msg += "\nKey value is '%s'" % param.rstrip()
F
Feng Yang 已提交
177 178 179 180 181
                        raise error.TestFail(msg)
        elif result_check == "m_format_q":
            match_flag = True
            for i in qmp_o:
                if output is None:
Y
yanwang 已提交
182
                    raise exceptions.TestError("QMP output pattern is missing")
F
Feng Yang 已提交
183 184 185
                if re.match(output.strip(), str(i)) is None:
                    match_flag = False
            if not match_flag:
186
                msg = "Output does not match the pattern: '%s'" % output
Y
yanwang 已提交
187
                raise exceptions.TestFail(msg)
F
Feng Yang 已提交
188

189 190
    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
Y
yanwang 已提交
191
        raise exceptions.TestSkipError("Host qemu does not support qmp.")
F
Feng Yang 已提交
192 193 194 195 196 197 198 199

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))

    module = params.get("modprobe_module")
    if module:
Y
yanwang 已提交
200
        logging.info("modprobe the module %s", module)
F
Feng Yang 已提交
201 202 203 204 205 206
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
Y
yanwang 已提交
207
        raise exceptions.TestError("Incorrect configuration, no QMP monitor found.")
F
Feng Yang 已提交
208 209 210 211
    hmp_ports = vm.get_monitors_by_type('human')
    if hmp_ports:
        hmp_port = hmp_ports[0]
    else:
Y
yanwang 已提交
212 213
        raise exceptions.TestError("Incorrect configuration, no QMP monitor found.")
    callback = {"host_cmd": process.system_output,
F
Feng Yang 已提交
214 215 216 217 218
                "guest_cmd": session.get_command_output,
                "monitor_cmd": hmp_port.send_args_cmd,
                "qmp_cmd": qmp_port.send_args_cmd}

    def send_cmd(cmd):
219
        """ Helper to execute command on ssh/host/monitor """
F
Feng Yang 已提交
220 221 222
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
Y
yanwang 已提交
223
            raise exceptions.TestError("cmd_type is not supported")
F
Feng Yang 已提交
224 225 226 227 228 229 230

    pre_cmd = params.get("pre_cmd")
    qmp_cmd = params.get("qmp_cmd")
    cmd_type = params.get("event_cmd_type")
    post_cmd = params.get("post_cmd")
    result_check = params.get("cmd_result_check")
    cmd_return_value = params.get("cmd_return_value")
231
    exception_list = params.get("exception_list", "")
F
Feng Yang 已提交
232

233
    # Pre command
F
Feng Yang 已提交
234
    if pre_cmd is not None:
Y
yanwang 已提交
235
        logging.info("Run prepare command '%s'.", pre_cmd)
F
Feng Yang 已提交
236
        pre_o = send_cmd(pre_cmd)
237
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)
F
Feng Yang 已提交
238
    try:
239
        # Testing command
Y
yanwang 已提交
240
        logging.info("Run qmp command '%s'.", qmp_cmd)
F
Feng Yang 已提交
241
        output = qmp_port.send_args_cmd(qmp_cmd)
242
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, output)
F
Feng Yang 已提交
243 244
    except qemu_monitor.QMPCmdError, err:
        if params.get("negative_test") == 'yes':
245 246
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
F
Feng Yang 已提交
247 248 249
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
Y
yanwang 已提交
250 251
                    raise exceptions.TestFail("'%s' not in exception '%s'"
                                              % (check_pattern, err))
F
Feng Yang 已提交
252
        else:
Y
yanwang 已提交
253
            raise exceptions.TestFail(err)
F
Feng Yang 已提交
254
    except qemu_monitor.MonitorProtocolError, err:
Y
yanwang 已提交
255
        raise exceptions.TestFail(err)
F
Feng Yang 已提交
256
    except Exception, err:
Y
yanwang 已提交
257
        raise exceptions.TestFail(err)
F
Feng Yang 已提交
258

259
    # Post command
F
Feng Yang 已提交
260
    if post_cmd is not None:
Y
yanwang 已提交
261
        logging.info("Run post command '%s'.", post_cmd)
F
Feng Yang 已提交
262
        post_o = send_cmd(post_cmd)
263
        logging.debug("Post-command: '%s'\n Output: '%s'", post_cmd, post_o)
F
Feng Yang 已提交
264 265 266

    if result_check is not None:
        txt = "Verify that qmp command '%s' works as designed." % qmp_cmd
Y
yanwang 已提交
267
        logging.info(txt)
J
jinzhao 已提交
268
        if result_check == "equal" or result_check == "contain":
269 270 271 272 273 274 275 276
            if qmp_cmd == "query-name":
                vm_name = params["main_vm"]
                check_result(output, vm_name, exception_list)
            elif qmp_cmd == "query-uuid":
                uuid_input = params["uuid"]
                check_result(output, uuid_input, exception_list)
            else:
                check_result(output, cmd_return_value, exception_list)
F
Feng Yang 已提交
277
        elif result_check == "m_format_q":
278
            check_result(output, cmd_return_value, exception_list)
F
Feng Yang 已提交
279 280
        elif 'post' in result_check:
            result_check = result_check.split('_', 1)[1]
281
            check_result(post_o, cmd_return_value, exception_list)
F
Feng Yang 已提交
282
        else:
283
            check_result(output, post_o, exception_list)
F
Feng Yang 已提交
284
    session.close()