qmp_command.py 13.0 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1 2
import logging
import re
3 4 5 6 7 8

from autotest.client.shared import utils
from autotest.client.shared import error

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


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

164
    def qmp_cpu_check(output):
165
        """ qmp_cpu test check """
166 167 168 169
        last_cpu = int(params['smp']) - 1
        for out in output:
            cpu = out.get('CPU')
            if cpu is None:
170 171
                raise error.TestFail("'CPU' index is missing in QMP output "
                                     "'%s'" % out)
172 173 174 175
            else:
                current = out.get('current')
                if current is None:
                    raise error.TestFail("'current' key is missing in QMP "
176
                                         "output '%s'" % out)
177
                elif cpu < last_cpu:
L
Lucas Meneghel Rodrigues 已提交
178
                    if current is False:
179 180 181
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
182 183
                                             "'False', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
184
                elif cpu == last_cpu:
L
Lucas Meneghel Rodrigues 已提交
185
                    if current is True:
186 187 188
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
189 190
                                             "'True', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
191 192 193 194 195 196
                elif cpu <= last_cpu:
                    continue
                else:
                    raise error.TestFail("Incorrect CPU index '%s' (corrupted "
                                         "or higher than no_cpus).\n%s"
                                         % (cpu, out))
F
Feng Yang 已提交
197

198 199
    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
F
Feng Yang 已提交
200 201 202 203 204 205 206 207 208
        raise error.TestNAError("Host qemu does not support qmp.")

    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:
209
        error.context("modprobe the module %s" % module, logging.info)
F
Feng Yang 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
        raise error.TestError("Incorrect configuration, no QMP monitor found.")
    hmp_ports = vm.get_monitors_by_type('human')
    if hmp_ports:
        hmp_port = hmp_ports[0]
    else:
        raise error.TestError("Incorrect configuration, no QMP monitor found.")
    callback = {"host_cmd": utils.system_output,
                "guest_cmd": session.get_command_output,
                "monitor_cmd": hmp_port.send_args_cmd,
                "qmp_cmd": qmp_port.send_args_cmd}

    def send_cmd(cmd):
228
        """ Helper to execute command on ssh/host/monitor """
F
Feng Yang 已提交
229 230 231 232 233 234 235 236 237 238 239
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
            raise error.TestError("cmd_type is not supported")

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

242 243 244 245 246
    # HOOKs
    if result_check == 'qmp_cpu':
        pre_cmd = "cpu index=%d" % (int(params['smp']) - 1)

    # Pre command
F
Feng Yang 已提交
247 248 249
    if pre_cmd is not None:
        error.context("Run prepare command '%s'." % pre_cmd, logging.info)
        pre_o = send_cmd(pre_cmd)
250
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)
F
Feng Yang 已提交
251
    try:
252
        # Testing command
F
Feng Yang 已提交
253 254
        error.context("Run qmp command '%s'." % qmp_cmd, logging.info)
        output = qmp_port.send_args_cmd(qmp_cmd)
255
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, output)
F
Feng Yang 已提交
256 257
    except qemu_monitor.QMPCmdError, err:
        if params.get("negative_test") == 'yes':
258 259
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
F
Feng Yang 已提交
260 261 262
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
263
                    raise error.TestFail("'%s' not in exception '%s'"
F
Feng Yang 已提交
264 265 266 267 268 269 270 271
                                         % (check_pattern, err))
        else:
            raise error.TestFail(err)
    except qemu_monitor.MonitorProtocolError, err:
        raise error.TestFail(err)
    except Exception, err:
        raise error.TestFail(err)

272
    # Post command
F
Feng Yang 已提交
273 274 275
    if post_cmd is not None:
        error.context("Run post command '%s'." % post_cmd, logging.info)
        post_o = send_cmd(post_cmd)
276
        logging.debug("Post-command: '%s'\n Output: '%s'", post_cmd, post_o)
F
Feng Yang 已提交
277 278 279 280

    if result_check is not None:
        txt = "Verify that qmp command '%s' works as designed." % qmp_cmd
        error.context(txt, logging.info)
281 282 283
        if result_check == 'qmp_cpu':
            qmp_cpu_check(output)
        elif result_check == "equal" or result_check == "contain":
284
            check_result(output, cmd_return_value, exception_list)
F
Feng Yang 已提交
285
        elif result_check == "m_format_q":
286
            check_result(output, cmd_return_value, exception_list)
F
Feng Yang 已提交
287 288
        elif 'post' in result_check:
            result_check = result_check.split('_', 1)[1]
289
            check_result(post_o, cmd_return_value, exception_list)
F
Feng Yang 已提交
290
        else:
291
            check_result(output, post_o, exception_list)
F
Feng Yang 已提交
292
    session.close()