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

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

from virttest import utils_misc
from virttest import qemu_monitor
F
Feng Yang 已提交
9 10


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

187
    def qmp_cpu_check(output):
188
        """ qmp_cpu test check """
189 190 191 192
        last_cpu = int(params['smp']) - 1
        for out in output:
            cpu = out.get('CPU')
            if cpu is None:
Y
yanwang 已提交
193 194
                raise exceptions.TestFail("'CPU' index is missing in QMP output "
                                          "'%s'" % out)
195 196 197
            else:
                current = out.get('current')
                if current is None:
Y
yanwang 已提交
198 199
                    raise exceptions.TestFail("'current' key is missing in QMP "
                                              "output '%s'" % out)
200
                elif cpu < last_cpu:
L
Lucas Meneghel Rodrigues 已提交
201
                    if current is False:
202 203
                        pass
                    else:
Y
yanwang 已提交
204 205 206
                        raise exceptions.TestFail("Attribute 'current' should be "
                                                  "'False', but is '%s' instead.\n"
                                                  "'%s'" % (current, out))
207
                elif cpu == last_cpu:
L
Lucas Meneghel Rodrigues 已提交
208
                    if current is True:
209 210
                        pass
                    else:
Y
yanwang 已提交
211 212 213
                        raise exceptions.TestFail("Attribute 'current' should be "
                                                  "'True', but is '%s' instead.\n"
                                                  "'%s'" % (current, out))
214 215 216
                elif cpu <= last_cpu:
                    continue
                else:
Y
yanwang 已提交
217 218 219
                    raise exceptions.TestFail("Incorrect CPU index '%s' (corrupted "
                                              "or higher than no_cpus).\n%s"
                                              % (cpu, out))
F
Feng Yang 已提交
220

221 222
    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
Y
yanwang 已提交
223
        raise exceptions.TestSkipError("Host qemu does not support qmp.")
F
Feng Yang 已提交
224 225 226 227 228 229 230 231

    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 已提交
232
        logging.info("modprobe the module %s", module)
F
Feng Yang 已提交
233 234 235 236 237 238
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
Y
yanwang 已提交
239
        raise exceptions.TestError("Incorrect configuration, no QMP monitor found.")
F
Feng Yang 已提交
240 241 242 243
    hmp_ports = vm.get_monitors_by_type('human')
    if hmp_ports:
        hmp_port = hmp_ports[0]
    else:
Y
yanwang 已提交
244 245
        raise exceptions.TestError("Incorrect configuration, no QMP monitor found.")
    callback = {"host_cmd": process.system_output,
F
Feng Yang 已提交
246 247 248 249 250
                "guest_cmd": session.get_command_output,
                "monitor_cmd": hmp_port.send_args_cmd,
                "qmp_cmd": qmp_port.send_args_cmd}

    def send_cmd(cmd):
251
        """ Helper to execute command on ssh/host/monitor """
F
Feng Yang 已提交
252 253 254
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
Y
yanwang 已提交
255
            raise exceptions.TestError("cmd_type is not supported")
F
Feng Yang 已提交
256 257 258 259 260 261 262

    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")
263
    exception_list = params.get("exception_list", "")
F
Feng Yang 已提交
264

265 266 267 268 269
    # HOOKs
    if result_check == 'qmp_cpu':
        pre_cmd = "cpu index=%d" % (int(params['smp']) - 1)

    # Pre command
F
Feng Yang 已提交
270
    if pre_cmd is not None:
Y
yanwang 已提交
271
        logging.info("Run prepare command '%s'.", pre_cmd)
F
Feng Yang 已提交
272
        pre_o = send_cmd(pre_cmd)
273
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)
F
Feng Yang 已提交
274
    try:
275
        # Testing command
Y
yanwang 已提交
276
        logging.info("Run qmp command '%s'.", qmp_cmd)
F
Feng Yang 已提交
277
        output = qmp_port.send_args_cmd(qmp_cmd)
278
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, output)
F
Feng Yang 已提交
279 280
    except qemu_monitor.QMPCmdError, err:
        if params.get("negative_test") == 'yes':
281 282
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
F
Feng Yang 已提交
283 284 285
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
Y
yanwang 已提交
286 287
                    raise exceptions.TestFail("'%s' not in exception '%s'"
                                              % (check_pattern, err))
F
Feng Yang 已提交
288
        else:
Y
yanwang 已提交
289
            raise exceptions.TestFail(err)
F
Feng Yang 已提交
290
    except qemu_monitor.MonitorProtocolError, err:
Y
yanwang 已提交
291
        raise exceptions.TestFail(err)
F
Feng Yang 已提交
292
    except Exception, err:
Y
yanwang 已提交
293
        raise exceptions.TestFail(err)
F
Feng Yang 已提交
294

295
    # Post command
F
Feng Yang 已提交
296
    if post_cmd is not None:
Y
yanwang 已提交
297
        logging.info("Run post command '%s'.", post_cmd)
F
Feng Yang 已提交
298
        post_o = send_cmd(post_cmd)
299
        logging.debug("Post-command: '%s'\n Output: '%s'", post_cmd, post_o)
F
Feng Yang 已提交
300 301 302

    if result_check is not None:
        txt = "Verify that qmp command '%s' works as designed." % qmp_cmd
Y
yanwang 已提交
303
        logging.info(txt)
304 305 306
        if result_check == 'qmp_cpu':
            qmp_cpu_check(output)
        elif result_check == "equal" or result_check == "contain":
307
            check_result(output, cmd_return_value, exception_list)
F
Feng Yang 已提交
308
        elif result_check == "m_format_q":
309
            check_result(output, cmd_return_value, exception_list)
F
Feng Yang 已提交
310 311
        elif 'post' in result_check:
            result_check = result_check.split('_', 1)[1]
312
            check_result(post_o, cmd_return_value, exception_list)
F
Feng Yang 已提交
313
        else:
314
            check_result(output, post_o, exception_list)
F
Feng Yang 已提交
315
    session.close()