qmp_command.py 13.0 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1 2
import logging
import re
F
Feng Yang 已提交
3 4 5 6 7
from autotest.client.shared import utils, error
from virttest import utils_misc, qemu_monitor


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

160
    def qmp_cpu_check(output):
161
        """ qmp_cpu test check """
162 163 164 165
        last_cpu = int(params['smp']) - 1
        for out in output:
            cpu = out.get('CPU')
            if cpu is None:
166 167
                raise error.TestFail("'CPU' index is missing in QMP output "
                                     "'%s'" % out)
168 169 170 171
            else:
                current = out.get('current')
                if current is None:
                    raise error.TestFail("'current' key is missing in QMP "
172
                                         "output '%s'" % out)
173
                elif cpu < last_cpu:
L
Lucas Meneghel Rodrigues 已提交
174
                    if current is False:
175 176 177
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
178 179
                                             "'False', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
180
                elif cpu == last_cpu:
L
Lucas Meneghel Rodrigues 已提交
181
                    if current is True:
182 183 184
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
185 186
                                             "'True', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
187 188 189 190 191 192
                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 已提交
193

194 195
    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
F
Feng Yang 已提交
196 197 198 199 200 201 202 203 204
        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:
205
        error.context("modprobe the module %s" % module, logging.info)
F
Feng Yang 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
        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):
224
        """ Helper to execute command on ssh/host/monitor """
F
Feng Yang 已提交
225 226 227 228 229 230 231 232 233 234 235
        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")
236
    exception_list = params.get("exception_list", "")
F
Feng Yang 已提交
237

238 239 240 241 242
    # HOOKs
    if result_check == 'qmp_cpu':
        pre_cmd = "cpu index=%d" % (int(params['smp']) - 1)

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

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

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