This patch add tests for testing cpu flags in qemu:
 a) interface cpu flags tests
  1) qemu -cpu ?model
  2)            dump
  3)            cpuid
 b) guest run cpu flags tests
  1) Test boot cpu model.
  2) Test boot cpu model and additiona/nonstandard model flags.
  3) Test boot fail with host unsupported flags.
  4) Test boot guest and try flags under load.
  5) Test online offline guest CPUs under load.

 There is new c program cpuflags-test which is able to test
 main Intel cpu flags now . There will be extension for test
 AMD cpuflags etc in next version.. This program ensure to test special
 instruction provides cpuflags like rdrand etc..

RFC:

In addition, there is subtest interface. This is class and some
decorators for easy way of start function like a subtest.
Subtests result are collected and it is posible for review on end of test.
Subtest class and decorators should be placed in autotest_lib.client.utils.

There is possible to change results format.

Example:
    @staticmethod
    def result_to_string(result):
        """
        @param result: Result of test.
        """
        print result
        return ("[%(result)]%(name): %(output)") % (result)

  1)
    Subtest.result_to_string = result_to_string
    Subtest.get_text_result()

  2)
    Subtest.get_text_result(result_to_string)

Pull-request: https://github.com/autotest/autotest/pull/109

Signed-off-by: Jiří Župka <jzu...@redhat.com>
---
 .../scripts/cpuflags-test/cpuflags-test.tar.bz2    |  Bin 0 -> 3303 bytes
 client/tests/kvm/subtests.cfg.sample               |    9 +
 client/tests/kvm/tests/cpuflags.py                 |  774 ++++++++++++++++++++
 client/virt/kvm_vm.py                              |   13 +
 4 files changed, 796 insertions(+), 0 deletions(-)
 create mode 100644 client/tests/kvm/scripts/cpuflags-test/cpuflags-test.tar.bz2
 create mode 100644 client/tests/kvm/tests/cpuflags.py

diff --git a/client/tests/kvm/scripts/cpuflags-test/cpuflags-test.tar.bz2 
b/client/tests/kvm/scripts/cpuflags-test/cpuflags-test.tar.bz2
new file mode 100644
index 
0000000000000000000000000000000000000000..e8c7afdfd17829b582eb818facae8a4740cc3588
GIT binary patch
literal 3303
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

literal 0
HcmV?d00001

diff --git a/client/tests/kvm/subtests.cfg.sample 
b/client/tests/kvm/subtests.cfg.sample
index 55f1b21..e8b71ff 100644
--- a/client/tests/kvm/subtests.cfg.sample
+++ b/client/tests/kvm/subtests.cfg.sample
@@ -1300,6 +1300,15 @@ variants:
                 dd_timeout = 900
                 check_cmd_timeout = 900
 
+    - cpuflags:
+        type = cpuflags
+        extra_params += " -snapshot"
+        #Disable all unnecessary vms.
+        vms = ""
+        cpu_models = "core2duo"
+        virtual_flags = "fxsr_opt hypervisor ds pdpe1gb osxsave svm"
+        hw_flags = "pbe tm ds_cpl monitor acpi dtes64 ht tm2 xtpr est pdcm smx"
+
     - cpu_hotplug_test:
         type = cpu_hotplug
         cpu_hotplug_timeout = 600
diff --git a/client/tests/kvm/tests/cpuflags.py 
b/client/tests/kvm/tests/cpuflags.py
new file mode 100644
index 0000000..a6d3f11
--- /dev/null
+++ b/client/tests/kvm/tests/cpuflags.py
@@ -0,0 +1,774 @@
+import logging, re, random, os, time, traceback, sys
+from autotest_lib.client.common_lib import error, utils
+from autotest_lib.client.virt import kvm_vm
+from autotest_lib.client.virt import virt_utils, aexpect
+
+
+def run_cpuflags(test, params, env):
+    """
+    Boot guest with different cpu flags and check if guest work correctly.
+
+
+    @param test: kvm test object
+
+    @param params: Dictionary with the test parameters
+    @param env: Dictionary with test environment.
+    """
+    def subtest_fatal(f):
+        """
+        Decorator which mark test critical.
+        If subtest failed whole test ends.
+        """
+        def new_f(self, *args, **kwds):
+            self._fatal = True
+            self.decored()
+            result = f(self, *args, **kwds)
+            return result
+        new_f.func_name = f.func_name
+        return new_f
+
+
+    def subtest_nocleanup(f):
+        """
+        Decorator disable cleanup function.
+        """
+        def new_f(self, *args, **kwds):
+            self._cleanup = False
+            self.decored()
+            result = f(self, *args, **kwds)
+            return result
+        new_f.func_name = f.func_name
+        return new_f
+
+
+    class Subtest(object):
+        """
+        Collect result of subtest of main test.
+        """
+        result = []
+        passed = 0
+        failed = 0
+        def __new__(cls, *args, **kargs):
+            self = super(Subtest, cls).__new__(cls)
+
+            self._fatal = False
+            self._cleanup = True
+            self._num_decored = 0
+
+            ret = None
+            if args is None:
+                args = []
+
+            res = {
+                   'result' : None,
+                   'name'   : self.__class__.__name__,
+                   'args'   : args,
+                   'kargs'  : kargs,
+                   'output' : None,
+                  }
+            try:
+                logging.info("Starting test %s" % self.__class__.__name__)
+                ret = self.test(*args, **kargs)
+                res['result'] = 'PASS'
+                res['output'] = ret
+                try:
+                    logging.info(Subtest.result_to_string(res))
+                except:
+                    self._num_decored = 0
+                    raise
+                Subtest.result.append(res)
+                Subtest.passed += 1
+            except:
+                exc_type, exc_value, exc_traceback = sys.exc_info()
+                for _ in range(self._num_decored):
+                    exc_traceback = exc_traceback.tb_next
+                logging.error("In function (" + self.__class__.__name__ + "):")
+                logging.error("Call from:\n" +
+                              traceback.format_stack()[-2][:-1])
+                logging.error("Exception from:\n" +
+                              "".join(traceback.format_exception(
+                                                      exc_type, exc_value,
+                                                      exc_traceback.tb_next)))
+                # Clean up environment after subTest crash
+                res['result'] = 'FAIL'
+                logging.info(self.result_to_string(res))
+                Subtest.result.append(res)
+                Subtest.failed += 1
+                if self._fatal:
+                    raise
+            finally:
+                if self._cleanup:
+                    self.clean()
+
+            return ret
+
+
+        def test(self):
+            """
+            Check if test is defined.
+
+            For makes test fatal add before implementation of test method
+            decorator @subtest_fatal
+            """
+            raise NotImplementedError("Method test is not implemented.")
+
+
+        def clean(self):
+            """
+            Check if cleanup is defined.
+
+            For makes test fatal add before implementation of test method
+            decorator @subtest_nocleanup
+            """
+            raise NotImplementedError("Method cleanup is not implemented.")
+
+
+        def decored(self):
+            self._num_decored += 1
+
+
+        @classmethod
+        def has_failed(cls):
+            """
+            @return: If any of subtest not pass return True.
+            """
+            if cls.failed > 0:
+                return True
+            else:
+                return False
+
+
+        @classmethod
+        def get_result(cls):
+            """
+            @return: Result of subtests.
+               Format:
+                 tuple(pass/fail,function_name,call_arguments)
+            """
+            return cls.result
+
+
+        @staticmethod
+        def result_to_string_debug(result):
+            """
+            @param result: Result of test.
+            """
+            sargs = ""
+            for arg in result['args']:
+                sargs += str(arg) + ","
+            sargs = sargs[:-1]
+            return ("Subtest (%s(%s)): --> %s") % (result['name'],
+                                                   sargs,
+                                                   result['status'])
+
+
+        @staticmethod
+        def result_to_string(result):
+            """
+            Format of result dict.
+
+            result = {
+                   'result' : "PASS" / "FAIL",
+                   'name'   : class name,
+                   'args'   : test's args,
+                   'kargs'  : test's kargs,
+                   'output' : return of test function,
+                  }
+
+            @param result: Result of test.
+            """
+            return ("Subtest (%(name)s): --> %(result)s") % (result)
+
+
+        @classmethod
+        def log_append(cls, msg):
+            """
+            Add log_append to result output.
+
+            @param msg: Test of log_append
+            """
+            cls.result.append([msg])
+
+
+        @classmethod
+        def _gen_res(cls, format_func):
+            """
+            Format result with formatting function
+
+            @param format_func: Func for formating result.
+            """
+            result = ""
+            for res in cls.result:
+                if (isinstance(res,dict)):
+                    result += format_func(res) + "\n"
+                else:
+                    result += str(res[0]) + "\n"
+            return result
+
+
+        @classmethod
+        def get_full_text_result(cls, format_func=None):
+            """
+            @return string with text form of result
+            """
+            if format_func is None:
+                format_func = cls.result_to_string_debug
+            return cls._gen_res(lambda s: format_func(s))
+
+
+        @classmethod
+        def get_text_result(cls, format_func=None):
+            """
+            @return string with text form of result
+            """
+            if format_func is None:
+                format_func = cls.result_to_string
+            return cls._gen_res(lambda s: format_func(s))
+
+
+    class Flag(str):
+        """
+        Class for easy merge cpuflags.
+        """
+        def __init__(self,  *args, **kwargs):
+            super(Flag, self).__init__( *args, **kwargs)
+
+        def __eq__(self, other):
+            s = set(self.split("|"))
+            o = set(other.split("|"))
+            if s & o:
+                return True
+            else:
+                return False
+
+        def __hash__(self, *args, **kwargs):
+            return 0
+
+    qemu_binary = virt_utils.get_path('.', params.get("qemu_binary", "qemu"))
+    pwd = os.path.join(os.environ['AUTODIR'], 'tests/kvm')
+    cpuflags_path = "scripts/cpuflags-test/cpuflags-test.tar.bz2"
+    stress_src = os.path.join(pwd, cpuflags_path)
+    smp = int(params.get("smp", 4))
+
+    map_flags_to_test = {
+                         Flag('avx')                        :set(['avx']),
+                         Flag('sse3')                       :set(['sse3']),
+                         Flag('ssse3')                      :set(['ssse3']),
+                         Flag('sse4.1|sse4_1|sse4.2|sse4_2'):set(['sse4']),
+                         Flag('aes')                        
:set(['aes','pclmul']),
+                         Flag('pclmuldq')                   :set(['pclmul']),
+                         Flag('pclmulqdq')                  :set(['pclmul']),
+                         Flag('rdrand')                     :set(['rdrand']),
+                         }
+
+    class Hg_flags:
+        def __init__(self, cpu_model):
+            virtual_flags = set(map(Flag,
+                                    params.get("virtual_flags", "").split()))
+            self.hw_flags = set(map(Flag, params.get("hw_flags", "").split()))
+            self.qemu_support_flags = get_all_qemu_flags()
+            self.host_support_flags = get_host_cpuflags()
+            self.quest_cpu_model_flags = get_guest_host_cpuflags(cpu_model) - \
+                                         virtual_flags
+
+            self.supported_flags = self.qemu_support_flags & \
+                                   self.host_support_flags
+            self.cpumodel_unsupport_flags = self.supported_flags -\
+                                            self.quest_cpu_model_flags
+
+            self.host_unsupported_flags = self.quest_cpu_model_flags - \
+                                          self.host_support_flags
+
+            self.guest_flags = self.quest_cpu_model_flags
+            self.guest_flags -= self.host_unsupported_flags
+            self.guest_flags |= self.cpumodel_unsupport_flags
+
+            self.host_all_unsupported_flags = self.qemu_support_flags
+            self.host_all_unsupported_flags -= self.host_support_flags | \
+                                               virtual_flags
+
+
+    def start_guest_with_cpuflags(cpuflags, smp=None):
+        """
+        Try to boot guest with special cpu flags and try login in to them.
+        """
+        params_b = params.copy()
+        params_b["cpu_model"] = cpuflags
+        if smp is not None:
+            params_b["smp"] = smp
+
+        vm_name = "vm1-cpuflags"
+        vm = kvm_vm.VM(vm_name, params_b, test.bindir, env['address_cache'])
+        env.register_vm(vm_name, vm)
+        vm.create()
+        vm.verify_alive()
+
+        session = vm.wait_for_login()
+
+        return (vm, session)
+
+    def get_guest_system_cpuflags(vm_session):
+        """
+        Get guest system cpuflags.
+
+        @param vm_session: session to checked vm.
+        @return: [corespond flags]
+        """
+        flags_re = re.compile(r'^flags\s*:(.*)$', re.MULTILINE)
+        out = vm_session.cmd_output("cat /proc/cpuinfo")
+
+        flags = flags_re.search(out).groups()[0].split()
+        return set(map(Flag, flags))
+
+
+    def get_guest_host_cpuflags(cpumodel):
+        """
+        Get cpu flags correspond with cpumodel parameters.
+
+        @param cpumodel: Cpumodel parameter sended to <qemu-kvm-cmd>.
+        @return: [corespond flags]
+        """
+        cmd = qemu_binary + " -cpu ?dump"
+        output = utils.run(cmd).stdout
+        re.escape(cpumodel)
+        pattern = ".+%s.*\n.*\n +feature_edx .+ \((.*)\)\n +feature_"\
+                  "ecx .+ \((.*)\)\n +extfeature_edx .+ \((.*)\)\n +"\
+                  "extfeature_ecx .+ \((.*)\)\n" % (cpumodel)
+        flags = []
+        model = re.search(pattern, output)
+        if model == None:
+            raise error.TestFail("Cannot find %s cpu model." % (cpumodel))
+        for flag_group in model.groups():
+            flags += flag_group.split()
+        return set(map(Flag, flags))
+
+
+    def get_all_qemu_flags():
+        cmd = qemu_binary + " -cpu ?cpuid"
+        output = utils.run(cmd).stdout
+
+        flags_re = re.compile(r".*\n.*f_edx:(.*)\n.*f_ecx:(.*)\n.*extf_edx:"\
+                              "(.*)\n.*extf_ecx:(.*)")
+        m = flags_re.search(output)
+        flags = []
+        for a in m.groups():
+            flags += a.split()
+
+        return set(map(Flag, flags))
+
+
+    def get_flags_full_name(cpu_flag):
+        """
+        Get all name of Flag.
+
+        @param cpu_flag: Flag
+        @return: all name of Flag.
+        """
+        cpu_flag = Flag(cpu_flag)
+        for f in get_all_qemu_flags():
+            if f == cpu_flag:
+                return Flag(f)
+        return []
+
+
+    def get_host_cpuflags():
+        """
+        Get cpu flags correspond with cpumodel parameters.
+
+        @return: [host cpu flags]
+        """
+        flags = virt_utils.get_cpu_flags()
+        return set(map(Flag, flags))
+
+
+    def parse_qemu_cpucommand(cpumodel):
+        """
+        Parse qemu cpu params.
+
+        @param cpumodel: Cpu model command.
+        @return: All flags which guest must have.
+        """
+        flags = cpumodel.split(",")
+        cpumodel = flags[0]
+
+        qemu_model_flag = get_guest_host_cpuflags(cpumodel)
+        host_support_flag = get_host_cpuflags()
+        real_flags = qemu_model_flag & host_support_flag
+
+        for f in flags[1:]:
+            if f[0].startswith("+"):
+                real_flags |= set([get_flags_full_name(f[1:])])
+            if f[0].startswith("-"):
+                real_flags -= set([get_flags_full_name(f[1:])])
+
+        return real_flags
+
+
+    def get_cpu_models():
+        """
+        Get all cpu models from qemu.
+
+        @return: cpu models.
+        """
+        cmd = qemu_binary + " -cpu ?"
+        output = utils.run(cmd).stdout
+
+        cpu_re = re.compile("\w+\s+\[?(\w+)\]?")
+        return cpu_re.findall(output)
+
+
+    def check_cpuflags(cpumodel, vm_session):
+        """
+        Check if vm flags are same like flags select by cpumodel.
+
+        @param cpumodel: params for -cpu param in qemu-kvm
+        @param vm_session: session to vm to check flags.
+
+        @return: ([excess], [missing]) flags
+        """
+        gf = get_guest_system_cpuflags(vm_session)
+        rf = parse_qemu_cpucommand(cpumodel)
+
+        logging.debug("Guest flags: %s" % (gf))
+        logging.debug("Host flags: %s" % (rf))
+        logging.debug("Flags on guest not defined by host: %s" % (gf-rf))
+        return rf-gf
+
+
+    def disable_cpu(vm_session, cpu, disable=True):
+        """
+        Disable cpu in guest system.
+
+        @param cpu: CPU id to disable.
+        @param disable: if True disable cpu else enable cpu.
+        """
+        system_cpu_dir = "/sys/devices/system/cpu/"
+        cpu_online = system_cpu_dir + "cpu%d/online" % (cpu)
+        cpu_state = vm_session.cmd_output("cat %s" % cpu_online).strip()
+        if disable and cpu_state == "1":
+            vm_session.cmd("echo 0 > %s" % cpu_online)
+            logging.debug("Guest cpu %d is disabled." % cpu)
+        elif cpu_state == "0":
+            vm_session.cmd("echo 1 > %s" % cpu_online)
+            logging.debug("Guest cpu %d is enabled." % cpu)
+
+
+    def install_cpuflags_test_on_vm(vm, dst_dir):
+        """
+        Install stress to vm.
+
+        @param vm: virtual machine.
+        @param dst_dir: Installation path.
+        """
+        session = vm.wait_for_login()
+        vm.copy_files_to(stress_src, dst_dir)
+        session.cmd("cd /tmp; tar -xvjf cpuflags-test.tar.bz2;"
+                    " make EXTRA_FLAGS='';")
+        session.close()
+
+
+    def check_cpuflags_work(vm, path, flags):
+        """
+        Check which flags work.
+
+        @param vm: Virtual machine.
+        @param path: Path of cpuflags_test
+        @param flags: Flags to test.
+        @return: Tuple (Working, not working, not tested) flags.
+        """
+        pass_Flags = []
+        not_tested = []
+        not_working = []
+        session = vm.wait_for_login()
+        for f in flags:
+            try:
+                for tc in map_flags_to_test[f]:
+                    session.cmd("%s/cpuflags-test --%s" % (path, tc))
+                pass_Flags.append(f)
+            except aexpect.ShellCmdError:
+                not_working.append(f)
+            except KeyError:
+                not_tested.append(f)
+        return (pass_Flags, not_working, not_tested)
+
+
+    def flags_to_stresstests(flags):
+        """
+        Covert [cpu flags] to [tests]
+
+        @param cpuflags: list of cpuflags
+        @return: Return tests like string.
+        """
+        tests = set([])
+        for f in flags:
+            tests |= map_flags_to_test[f]
+        param = ""
+        for f in tests:
+            param += ","+f
+        return param
+
+
+    def run_stress(vm, timeout, guest_flags):
+        """
+        Run stress on vm for timeout time.
+        """
+        ret = False
+        install_path = "/tmp"
+        install_cpuflags_test_on_vm(vm, install_path)
+        flags = check_cpuflags_work(vm, install_path, guest_flags)
+        dd_session = vm.wait_for_login()
+        stress_session = vm.wait_for_login()
+        dd_session.sendline("dd if=/dev/[svh]da of=/tmp/stressblock"
+                            " bs=10MB count=100 &")
+        try:
+            stress_session.cmd("%s/cpuflags-test --stress %s%s" %
+                        (install_path, smp, flags_to_stresstests(flags[0])))
+        except aexpect.ShellTimeoutError:
+            ret = True
+        stress_session.close()
+        dd_session.close()
+        return ret
+
+
+    def test_qemu_interface():
+        """
+        1) <qemu-kvm-cmd> -cpu ?model
+        2) <qemu-kvm-cmd> -cpu ?dump
+        3) <qemu-kvm-cmd> -cpu ?cpuid
+        """
+
+        # 1) <qemu-kvm-cmd> -cpu ?model
+        class test_qemu_cpu_model(Subtest):
+            @subtest_fatal
+            @subtest_nocleanup
+            def test(self):
+                cpu_models = params.get("cpu_models","core2duo").split()
+                cmd = qemu_binary + " -cpu ?model"
+                result = utils.run(cmd)
+                missing = []
+                for cpu_model in cpu_models:
+                    if not cpu_model in result.stdout:
+                        missing.append(cpu_model)
+                if missing:
+                    raise error.TestFail("CPU models %s are not in output "
+                                         "'%s' of command \n%s" %
+                                         (missing, cmd, result.stdout))
+
+        # 2) <qemu-kvm-cmd> -cpu ?dump
+        class test_qemu_dump(Subtest):
+            @subtest_nocleanup
+            def test(self):
+                cpu_models = params.get("cpu_models","core2duo").split()
+                cmd = qemu_binary + " -cpu ?dump"
+                result = utils.run(cmd)
+                missing = []
+                for cpu_model in cpu_models:
+                    if not cpu_model in result.stdout:
+                        missing.append(cpu_model)
+                if missing:
+                    raise error.TestFail("CPU models %s are not in output "
+                                         "'%s' of command \n%s" %
+                                         (missing, cmd, result.stdout))
+
+        # 3) <qemu-kvm-cmd> -cpu ?cpuid
+        class test_qemu_cpuid(Subtest):
+            @subtest_nocleanup
+            def test(self):
+                cmd = qemu_binary + " -cpu ?cpuid"
+                result = utils.run(cmd)
+                if result.stdout is "":
+                    raise error.TestFail("There aren't any cpu Flag in output"
+                                         " '%s' of command \n%s" %
+                                         (cmd, result.stdout))
+
+        test_qemu_cpu_model()
+        test_qemu_dump()
+        test_qemu_cpuid()
+
+
+    def test_qemu_guest():
+        """
+        1) boot with cpu_model
+        2) migrate with flags
+        3) <qemu-kvm-cmd> -cpu model_name,+Flag
+        4) fail boot unsupported flags
+        5) check guest flags under load cpu, system (dd)
+        6) online/offline CPU
+        """
+        cpu_models = params.get("cpu_models","").split()
+        if not cpu_models:
+            cpu_models = get_cpu_models()
+        logging.debug("Founded cpu models %s." % (str(cpu_models)))
+
+        # 1 boot with cpu_model
+        class test_boot_cpu_model(Subtest):
+            def test(self, cpu_model):
+                logging.debug("Run tests with cpu model %s" % (cpu_model))
+                (self.vm, session) = start_guest_with_cpuflags(cpu_model)
+                not_enable_flags = check_cpuflags(cpu_model, session)
+                if not_enable_flags != set([]):
+                    raise error.TestFail("Flags defined by host and supported"
+                                         " by host but not on find on guest:"
+                                         " %s" % (not_enable_flags))
+
+            def clean(self):
+                logging.info("cleanup")
+                self.vm.destroy(gracefully=False)
+
+        # 2 migration test
+        # TODO: Migration test.
+
+        # 3) success boot with supported flags
+        class test_boot_cpu_model_and_additiona_flags(test_boot_cpu_model):
+            def test(self, cpu_model):
+                flags = Hg_flags(cpu_model)
+
+                logging.debug("Cpu mode flags %s." %
+                              str(flags.quest_cpu_model_flags))
+                cpuf_model = cpu_model
+
+                # Add unsupported flags.
+                for fadd in flags.cpumodel_unsupport_flags:
+                    cpuf_model += ",+" + fadd
+
+                for fdel in flags.host_unsupported_flags:
+                    cpuf_model += ",-" + fdel
+
+                guest_flags = (flags.quest_cpu_model_flags -
+                               flags.host_unsupported_flags)
+                guest_flags |= flags.cpumodel_unsupport_flags
+
+                (self.vm, session) = start_guest_with_cpuflags(cpuf_model)
+
+                not_enable_flags = check_cpuflags(cpuf_model, session) - \
+                                   flags.hw_flags
+                if not_enable_flags != set([]):
+                    logging.error("Model unsupported flags: %s" %
+                                  str(flags.cpumodel_unsupport_flags))
+                    logging.error("Flags defined by host and supported "
+                                  "by host but not on find on guest: %s" %
+                                  str(not_enable_flags))
+                logging.info("Check main instruction sets.")
+
+                install_path = "/tmp"
+                install_cpuflags_test_on_vm(self.vm, install_path)
+                Flags = check_cpuflags_work(self.vm, install_path, guest_flags)
+                logging.info("Woking CPU flags: %s" % str(Flags[0]))
+                logging.error("Not working CPU flags: %s" % str(Flags[1]))
+                logging.warning("Not tested CPU flags: %s" % str(Flags[2]))
+
+                if Flags[1]:
+                    raise error.TestFail("Some of flags not work: %s" %
+                                         (str(Flags[1])))
+
+
+        # 4) fail boot unsupported flags
+        class test_fail_boot_with_host_unsupported_flags(Subtest):
+            @subtest_nocleanup
+            def test(self, cpu_model):
+                #This is virtual cpu flags which are supported by
+                #qemu but no with host cpu.
+                flags = Hg_flags(cpu_model)
+
+                logging.debug("Unsupported flags %s." %
+                              str(flags.host_all_unsupported_flags))
+                cpuf_model = cpu_model + ",enforce"
+
+                # Add unsupported flags.
+                for fadd in flags.host_all_unsupported_flags:
+                    cpuf_model += ",+" + fadd
+
+                cmd = qemu_binary + " -cpu " + cpuf_model
+                out = None
+                try:
+                    out = utils.run(cmd, timeout=5, ignore_status=True).stderr
+                except error.CmdError:
+                    logging.error("Host boot with unsupported flag")
+                finally:
+                    uns_re = re.compile("^warning:.*flag '(.+)'", re.MULTILINE)
+                    warn_flags = set(map(Flag, uns_re.findall(out)))
+                    fwarn_flags = flags.host_all_unsupported_flags - warn_flags
+                    if fwarn_flags:
+                        raise error.TestFail("Qemu not warn for flags %s." %
+                                      str(fwarn_flags))
+
+
+        # 5) check guest flags under load cpu, stress and system (dd)
+        class test_boot_guest_and_try_flags_under_load(test_boot_cpu_model):
+            def test(self, cpu_model):
+                logging.info("Check guest working cpuflags under load"
+                             " cpu and stress and system (dd).")
+
+                flags = Hg_flags(cpu_model)
+
+                logging.debug("Cpu mode flags %s." %
+                              str(flags.quest_cpu_model_flags))
+                logging.debug("Added flags %s." %
+                              str(flags.cpumodel_unsupport_flags))
+                cpuf_model = cpu_model
+
+                # Add unsupported flags.
+                for fadd in flags.cpumodel_unsupport_flags:
+                    cpuf_model += ",+" + fadd
+
+                for fdel in flags.host_unsupported_flags:
+                    cpuf_model += ",-" + fdel
+
+                (self.vm, _) = start_guest_with_cpuflags(cpuf_model, smp)
+
+                if (not run_stress(self.vm, 60, flags.guest_flags)):
+                    raise error.TestFail("Stress test ended before"
+                                         " end of test.")
+
+
+        # 6) Online/offline CPU
+        class test_online_offline_guest_CPUs(test_boot_cpu_model):
+            def test(self, cpu_model):
+                logging.debug("Run tests with cpu model %s." % (cpu_model))
+                flags = Hg_flags(cpu_model)
+
+                (self.vm, session) = start_guest_with_cpuflags(cpu_model, smp)
+
+                def encap(timeout):
+                    random.seed()
+                    begin = time.time()
+                    end = begin
+                    if smp > 1:
+                        while end - begin < 60:
+                            cpu = random.randint(1, smp - 1)
+                            if random.randint(0, 1):
+                                disable_cpu(session, cpu, True)
+                            else:
+                                disable_cpu(session, cpu, False)
+                            end = time.time()
+                        return True
+                    else:
+                        logging.warning("For this test is necessary smp > 1.")
+                        return False
+                timeout = 60
+                result = virt_utils.parallel([(encap, [timeout]),
+                                             (run_stress, [self.vm, timeout,
+                                                          flags.guest_flags])])
+                if not (result[0] and result[1]):
+                    raise error.TestFail("Stress tests failed before"
+                                         " end of testing.")
+
+
+        for cpu_model in cpu_models:
+            test_fail_boot_with_host_unsupported_flags(cpu_model)
+            test_boot_cpu_model(cpu_model)
+            test_boot_cpu_model_and_additiona_flags(cpu_model)
+            test_boot_guest_and_try_flags_under_load(cpu_model)
+            test_online_offline_guest_CPUs(cpu_model)
+
+
+    try:
+        Subtest.log_append("<qemu-kvm> interface tests.")
+        test_qemu_interface()
+        Subtest.log_append("<qemu-kvm> guests tests.")
+        test_qemu_guest()
+    finally:
+        logging.info("\n\nRESULTS:\n%s \n" % (Subtest.get_text_result()))
+
+    if Subtest.has_failed():
+        raise error.TestFail("Some of subtest failed.")
diff --git a/client/virt/kvm_vm.py b/client/virt/kvm_vm.py
index 6747c2b..0952793 100644
--- a/client/virt/kvm_vm.py
+++ b/client/virt/kvm_vm.py
@@ -413,6 +413,19 @@ class VM(virt_vm.BaseVM):
             else:
                 return ""
 
+        def add_cpu_flags(help, cpu_model, flags=None, vendor_id=None):
+            if has_option(help, 'cpu'):
+                cmd = " -cpu %s" % cpu_model
+
+                if vendor_id:
+                    cmd += ",vendor=\"%s\"" % vendor_id
+                if flags:
+                    cmd += ",%s" % flags
+
+                return cmd
+            else:
+                return ""
+
         def add_usb(help, usb_id, usb_type, multifunction=False,
                     masterbus=None, firstport=None):
             cmd = ""
-- 
1.7.7.3

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to