qmp_command.py 12.3 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1 2
import logging
import re
F
Feng Yang 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15
from autotest.client.shared import utils, error
from virttest import utils_misc, qemu_monitor


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

148
    def qmp_cpu_check(output):
149
        """ qmp_cpu test check """
150 151 152 153
        last_cpu = int(params['smp']) - 1
        for out in output:
            cpu = out.get('CPU')
            if cpu is None:
154 155
                raise error.TestFail("'CPU' index is missing in QMP output "
                                     "'%s'" % out)
156 157 158 159
            else:
                current = out.get('current')
                if current is None:
                    raise error.TestFail("'current' key is missing in QMP "
160
                                         "output '%s'" % out)
161
                elif cpu < last_cpu:
L
Lucas Meneghel Rodrigues 已提交
162
                    if current is False:
163 164 165
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
166 167
                                             "'False', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
168
                elif cpu == last_cpu:
L
Lucas Meneghel Rodrigues 已提交
169
                    if current is True:
170 171 172
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
173 174
                                             "'True', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
175 176 177 178 179 180
                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 已提交
181

182
    if not utils_misc.qemu_has_option("qmp", params['qemu_binary']):
F
Feng Yang 已提交
183 184 185 186 187 188 189 190 191
        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:
192
        error.context("modprobe the module %s" % module, logging.info)
F
Feng Yang 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
        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):
211
        """ Helper to execute command on ssh/host/monitor """
F
Feng Yang 已提交
212 213 214 215 216 217 218 219 220 221 222 223
        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")

224 225 226 227 228
    # HOOKs
    if result_check == 'qmp_cpu':
        pre_cmd = "cpu index=%d" % (int(params['smp']) - 1)

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

254
    # Post command
F
Feng Yang 已提交
255 256 257
    if post_cmd is not None:
        error.context("Run post command '%s'." % post_cmd, logging.info)
        post_o = send_cmd(post_cmd)
258
        logging.debug("Post-command: '%s'\n Output: '%s'", post_cmd, post_o)
F
Feng Yang 已提交
259 260 261 262

    if result_check is not None:
        txt = "Verify that qmp command '%s' works as designed." % qmp_cmd
        error.context(txt, logging.info)
263 264 265
        if result_check == 'qmp_cpu':
            qmp_cpu_check(output)
        elif result_check == "equal" or result_check == "contain":
F
Feng Yang 已提交
266 267 268 269 270 271 272 273 274
            check_result(output, cmd_return_value)
        elif result_check == "m_format_q":
            check_result(output, cmd_return_value)
        elif 'post' in result_check:
            result_check = result_check.split('_', 1)[1]
            check_result(post_o, cmd_return_value)
        else:
            check_result(output, post_o)
    session.close()